s_drawpix.c revision 709892459922a32096fe9dd8261d0d92337bb02f
1/* $Id: s_drawpix.c,v 1.15 2001/03/19 02:25:36 keithw Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27 28#include "glheader.h" 29#include "colormac.h" 30#include "context.h" 31#include "convolve.h" 32#include "image.h" 33#include "macros.h" 34#include "mem.h" 35#include "mmath.h" 36#include "pixel.h" 37 38#include "s_context.h" 39#include "s_drawpix.h" 40#include "s_pixeltex.h" 41#include "s_span.h" 42#include "s_stencil.h" 43#include "s_texture.h" 44#include "s_zoom.h" 45 46 47 48/* 49 * Given the dest position, size and skipPixels and skipRows values 50 * for a glDrawPixels command, perform clipping of the image bounds 51 * so the result lies withing the context's buffer bounds. 52 * Return: GL_TRUE if image is ready for drawing 53 * GL_FALSE if image was completely clipped away (draw nothing) 54 */ 55GLboolean 56_mesa_clip_pixelrect(const GLcontext *ctx, 57 GLint *destX, GLint *destY, 58 GLsizei *width, GLsizei *height, 59 GLint *skipPixels, GLint *skipRows) 60{ 61 const GLframebuffer *buffer = ctx->DrawBuffer; 62 63 /* left clipping */ 64 if (*destX < buffer->_Xmin) { 65 *skipPixels += (buffer->_Xmin - *destX); 66 *width -= (buffer->_Xmin - *destX); 67 *destX = buffer->_Xmin; 68 } 69 /* right clipping */ 70 if (*destX + *width > buffer->_Xmax) 71 *width -= (*destX + *width - buffer->_Xmax); 72 73 if (*width <= 0) 74 return GL_FALSE; 75 76 /* bottom clipping */ 77 if (*destY < buffer->_Ymin) { 78 *skipRows += (buffer->_Ymin - *destY); 79 *height -= (buffer->_Ymin - *destY); 80 *destY = buffer->_Ymin; 81 } 82 /* top clipping */ 83 if (*destY + *height > buffer->_Ymax) 84 *height -= (*destY + *height - buffer->_Ymax); 85 86 if (*height <= 0) 87 return GL_TRUE; 88 89 return GL_TRUE; 90} 91 92 93 94/* 95 * Try to do a fast and simple RGB(a) glDrawPixels. 96 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead 97 */ 98static GLboolean 99fast_draw_pixels(GLcontext *ctx, GLint x, GLint y, 100 GLsizei width, GLsizei height, 101 GLenum format, GLenum type, const GLvoid *pixels) 102{ 103 SWcontext *swrast = SWRAST_CONTEXT(ctx); 104 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; 105 GLchan rgb[MAX_WIDTH][3]; 106 GLchan rgba[MAX_WIDTH][4]; 107 108 if (!ctx->Current.RasterPosValid) { 109 return GL_TRUE; /* no-op */ 110 } 111 112 if ((SWRAST_CONTEXT(ctx)->_RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0 113 && ctx->Texture._ReallyEnabled == 0 114 && unpack->Alignment == 1 115 && !unpack->SwapBytes 116 && !unpack->LsbFirst) { 117 118 GLint destX = x; 119 GLint destY = y; 120 GLint drawWidth = width; /* actual width drawn */ 121 GLint drawHeight = height; /* actual height drawn */ 122 GLint skipPixels = unpack->SkipPixels; 123 GLint skipRows = unpack->SkipRows; 124 GLint rowLength; 125 GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */ 126 GLint zoomY0 = 0; 127 128 if (unpack->RowLength > 0) 129 rowLength = unpack->RowLength; 130 else 131 rowLength = width; 132 133 /* If we're not using pixel zoom then do all clipping calculations 134 * now. Otherwise, we'll let the _mesa_write_zoomed_*_span() functions 135 * handle the clipping. 136 */ 137 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 138 /* horizontal clipping */ 139 if (destX < ctx->DrawBuffer->_Xmin) { 140 skipPixels += (ctx->DrawBuffer->_Xmin - destX); 141 drawWidth -= (ctx->DrawBuffer->_Xmin - destX); 142 destX = ctx->DrawBuffer->_Xmin; 143 } 144 if (destX + drawWidth > ctx->DrawBuffer->_Xmax) 145 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); 146 if (drawWidth <= 0) 147 return GL_TRUE; 148 149 /* vertical clipping */ 150 if (destY < ctx->DrawBuffer->_Ymin) { 151 skipRows += (ctx->DrawBuffer->_Ymin - destY); 152 drawHeight -= (ctx->DrawBuffer->_Ymin - destY); 153 destY = ctx->DrawBuffer->_Ymin; 154 } 155 if (destY + drawHeight > ctx->DrawBuffer->_Ymax) 156 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax); 157 if (drawHeight <= 0) 158 return GL_TRUE; 159 } 160 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 161 /* upside-down image */ 162 /* horizontal clipping */ 163 if (destX < ctx->DrawBuffer->_Xmin) { 164 skipPixels += (ctx->DrawBuffer->_Xmin - destX); 165 drawWidth -= (ctx->DrawBuffer->_Xmin - destX); 166 destX = ctx->DrawBuffer->_Xmin; 167 } 168 if (destX + drawWidth > ctx->DrawBuffer->_Xmax) 169 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); 170 if (drawWidth <= 0) 171 return GL_TRUE; 172 173 /* vertical clipping */ 174 if (destY > ctx->DrawBuffer->_Ymax) { 175 skipRows += (destY - ctx->DrawBuffer->_Ymax); 176 drawHeight -= (destY - ctx->DrawBuffer->_Ymax); 177 destY = ctx->DrawBuffer->_Ymax; 178 } 179 if (destY - drawHeight < ctx->DrawBuffer->_Ymin) 180 drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight)); 181 if (drawHeight <= 0) 182 return GL_TRUE; 183 } 184 else { 185 /* setup array of fragment Z value to pass to zoom function */ 186 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF); 187 GLint i; 188 ASSERT(drawWidth < MAX_WIDTH); 189 for (i=0; i<drawWidth; i++) 190 zSpan[i] = z; 191 192 /* save Y value of first row */ 193 zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F); 194 } 195 196 197 /* 198 * Ready to draw! 199 * The window region at (destX, destY) of size (drawWidth, drawHeight) 200 * will be written to. 201 * We'll take pixel data from buffer pointed to by "pixels" but we'll 202 * skip "skipRows" rows and skip "skipPixels" pixels/row. 203 */ 204 205 if (format == GL_RGBA && type == CHAN_TYPE 206 && ctx->_ImageTransferState==0) { 207 if (ctx->Visual.rgbMode) { 208 GLchan *src = (GLchan *) pixels 209 + (skipRows * rowLength + skipPixels) * 4; 210 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 211 /* no zooming */ 212 GLint row; 213 for (row=0; row<drawHeight; row++) { 214 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 215 (CONST GLchan (*)[4]) src, NULL); 216 src += rowLength * 4; 217 destY++; 218 } 219 } 220 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 221 /* upside-down */ 222 GLint row; 223 for (row=0; row<drawHeight; row++) { 224 destY--; 225 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 226 (CONST GLchan (*)[4]) src, NULL); 227 src += rowLength * 4; 228 } 229 } 230 else { 231 /* with zooming */ 232 GLint row; 233 for (row=0; row<drawHeight; row++) { 234 _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY, 235 zSpan, 0, (CONST GLchan (*)[4]) src, zoomY0); 236 src += rowLength * 4; 237 destY++; 238 } 239 } 240 } 241 return GL_TRUE; 242 } 243 else if (format == GL_RGB && type == CHAN_TYPE 244 && ctx->_ImageTransferState == 0) { 245 if (ctx->Visual.rgbMode) { 246 GLchan *src = (GLchan *) pixels 247 + (skipRows * rowLength + skipPixels) * 3; 248 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 249 GLint row; 250 for (row=0; row<drawHeight; row++) { 251 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 252 (CONST GLchan (*)[3]) src, NULL); 253 src += rowLength * 3; 254 destY++; 255 } 256 } 257 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 258 /* upside-down */ 259 GLint row; 260 for (row=0; row<drawHeight; row++) { 261 destY--; 262 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 263 (CONST GLchan (*)[3]) src, NULL); 264 src += rowLength * 3; 265 } 266 } 267 else { 268 /* with zooming */ 269 GLint row; 270 for (row=0; row<drawHeight; row++) { 271 _mesa_write_zoomed_rgb_span(ctx, drawWidth, destX, destY, 272 zSpan, 0, (CONST GLchan (*)[3]) src, zoomY0); 273 src += rowLength * 3; 274 destY++; 275 } 276 } 277 } 278 return GL_TRUE; 279 } 280 else if (format == GL_LUMINANCE && type == CHAN_TYPE 281 && ctx->_ImageTransferState==0) { 282 if (ctx->Visual.rgbMode) { 283 GLchan *src = (GLchan *) pixels 284 + (skipRows * rowLength + skipPixels); 285 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 286 /* no zooming */ 287 GLint row; 288 ASSERT(drawWidth < MAX_WIDTH); 289 for (row=0; row<drawHeight; row++) { 290 GLint i; 291 for (i=0;i<drawWidth;i++) { 292 rgb[i][0] = src[i]; 293 rgb[i][1] = src[i]; 294 rgb[i][2] = src[i]; 295 } 296 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 297 (CONST GLchan (*)[3]) rgb, NULL); 298 src += rowLength; 299 destY++; 300 } 301 } 302 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 303 /* upside-down */ 304 GLint row; 305 ASSERT(drawWidth < MAX_WIDTH); 306 for (row=0; row<drawHeight; row++) { 307 GLint i; 308 for (i=0;i<drawWidth;i++) { 309 rgb[i][0] = src[i]; 310 rgb[i][1] = src[i]; 311 rgb[i][2] = src[i]; 312 } 313 destY--; 314 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 315 (CONST GLchan (*)[3]) rgb, NULL); 316 src += rowLength; 317 } 318 } 319 else { 320 /* with zooming */ 321 GLint row; 322 ASSERT(drawWidth < MAX_WIDTH); 323 for (row=0; row<drawHeight; row++) { 324 GLint i; 325 for (i=0;i<drawWidth;i++) { 326 rgb[i][0] = src[i]; 327 rgb[i][1] = src[i]; 328 rgb[i][2] = src[i]; 329 } 330 _mesa_write_zoomed_rgb_span(ctx, drawWidth, destX, destY, 331 zSpan, 0, (CONST GLchan (*)[3]) rgb, zoomY0); 332 src += rowLength; 333 destY++; 334 } 335 } 336 } 337 return GL_TRUE; 338 } 339 else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE 340 && ctx->_ImageTransferState == 0) { 341 if (ctx->Visual.rgbMode) { 342 GLchan *src = (GLchan *) pixels 343 + (skipRows * rowLength + skipPixels)*2; 344 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 345 /* no zooming */ 346 GLint row; 347 ASSERT(drawWidth < MAX_WIDTH); 348 for (row=0; row<drawHeight; row++) { 349 GLint i; 350 GLchan *ptr = src; 351 for (i=0;i<drawWidth;i++) { 352 rgba[i][0] = *ptr; 353 rgba[i][1] = *ptr; 354 rgba[i][2] = *ptr++; 355 rgba[i][3] = *ptr++; 356 } 357 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 358 (CONST GLchan (*)[4]) rgba, NULL); 359 src += rowLength*2; 360 destY++; 361 } 362 } 363 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 364 /* upside-down */ 365 GLint row; 366 ASSERT(drawWidth < MAX_WIDTH); 367 for (row=0; row<drawHeight; row++) { 368 GLint i; 369 GLchan *ptr = src; 370 for (i=0;i<drawWidth;i++) { 371 rgba[i][0] = *ptr; 372 rgba[i][1] = *ptr; 373 rgba[i][2] = *ptr++; 374 rgba[i][3] = *ptr++; 375 } 376 destY--; 377 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 378 (CONST GLchan (*)[4]) rgba, NULL); 379 src += rowLength*2; 380 } 381 } 382 else { 383 /* with zooming */ 384 GLint row; 385 ASSERT(drawWidth < MAX_WIDTH); 386 for (row=0; row<drawHeight; row++) { 387 GLchan *ptr = src; 388 GLint i; 389 for (i=0;i<drawWidth;i++) { 390 rgba[i][0] = *ptr; 391 rgba[i][1] = *ptr; 392 rgba[i][2] = *ptr++; 393 rgba[i][3] = *ptr++; 394 } 395 _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY, 396 zSpan, 0, (CONST GLchan (*)[4]) rgba, zoomY0); 397 src += rowLength*2; 398 destY++; 399 } 400 } 401 } 402 return GL_TRUE; 403 } 404 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) { 405 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels; 406 if (ctx->Visual.rgbMode) { 407 /* convert CI data to RGBA */ 408 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 409 /* no zooming */ 410 GLint row; 411 for (row=0; row<drawHeight; row++) { 412 ASSERT(drawWidth < MAX_WIDTH); 413 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba); 414 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 415 (const GLchan (*)[4]) rgba, 416 NULL); 417 src += rowLength; 418 destY++; 419 } 420 return GL_TRUE; 421 } 422 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 423 /* upside-down */ 424 GLint row; 425 for (row=0; row<drawHeight; row++) { 426 ASSERT(drawWidth < MAX_WIDTH); 427 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba); 428 destY--; 429 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 430 (CONST GLchan (*)[4]) rgba, 431 NULL); 432 src += rowLength; 433 } 434 return GL_TRUE; 435 } 436 else { 437 /* with zooming */ 438 GLint row; 439 for (row=0; row<drawHeight; row++) { 440 ASSERT(drawWidth < MAX_WIDTH); 441 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba); 442 _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY, 443 zSpan, 0, (CONST GLchan (*)[4]) rgba, zoomY0); 444 src += rowLength; 445 destY++; 446 } 447 return GL_TRUE; 448 } 449 } 450 else if (ctx->_ImageTransferState==0) { 451 /* write CI data to CI frame buffer */ 452 GLint row; 453 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 454 /* no zooming */ 455 for (row=0; row<drawHeight; row++) { 456 (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY, 457 src, NULL); 458 src += rowLength; 459 destY++; 460 } 461 return GL_TRUE; 462 } 463 else { 464 /* with zooming */ 465 return GL_FALSE; 466 } 467 } 468 } 469 else { 470 /* can't handle this pixel format and/or data type here */ 471 return GL_FALSE; 472 } 473 } 474 475 /* can't do a simple draw, have to use slow path */ 476 return GL_FALSE; 477} 478 479 480 481/* 482 * Do glDrawPixels of index pixels. 483 */ 484static void 485draw_index_pixels( GLcontext *ctx, GLint x, GLint y, 486 GLsizei width, GLsizei height, 487 GLenum type, const GLvoid *pixels ) 488{ 489 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 490 const GLint desty = y; 491 GLint row, drawWidth; 492 GLdepth zspan[MAX_WIDTH]; 493 494 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 495 496 /* Fragment depth values */ 497 if (ctx->Depth.Test || ctx->Fog.Enabled) { 498 GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF); 499 GLint i; 500 for (i = 0; i < drawWidth; i++) { 501 zspan[i] = zval; 502 } 503 } 504 505 /* 506 * General solution 507 */ 508 for (row = 0; row < height; row++, y++) { 509 GLuint indexes[MAX_WIDTH]; 510 const GLvoid *source = _mesa_image_address(&ctx->Unpack, 511 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0); 512 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes, 513 type, source, &ctx->Unpack, 514 ctx->_ImageTransferState); 515 if (zoom) { 516 _mesa_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, desty); 517 } 518 else { 519 _mesa_write_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, GL_BITMAP); 520 } 521 } 522} 523 524 525 526/* 527 * Do glDrawPixels of stencil image. The image datatype may either 528 * be GLubyte or GLbitmap. 529 */ 530static void 531draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, 532 GLsizei width, GLsizei height, 533 GLenum type, const GLvoid *pixels ) 534{ 535 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 536 const GLint desty = y; 537 GLint row, drawWidth; 538 539 if (type != GL_BYTE && 540 type != GL_UNSIGNED_BYTE && 541 type != GL_SHORT && 542 type != GL_UNSIGNED_SHORT && 543 type != GL_INT && 544 type != GL_UNSIGNED_INT && 545 type != GL_FLOAT && 546 type != GL_BITMAP) { 547 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)"); 548 return; 549 } 550 551 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 552 553 for (row = 0; row < height; row++, y++) { 554 GLstencil values[MAX_WIDTH]; 555 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) 556 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; 557 const GLvoid *source = _mesa_image_address(&ctx->Unpack, 558 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0); 559 _mesa_unpack_index_span(ctx, drawWidth, destType, values, 560 type, source, &ctx->Unpack, 561 ctx->_ImageTransferState); 562 if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) { 563 _mesa_shift_and_offset_stencil( ctx, drawWidth, values ); 564 } 565 if (ctx->Pixel.MapStencilFlag) { 566 _mesa_map_stencil( ctx, drawWidth, values ); 567 } 568 569 if (zoom) { 570 _mesa_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y, 571 values, desty ); 572 } 573 else { 574 _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values ); 575 } 576 } 577} 578 579 580 581/* 582 * Do a glDrawPixels of depth values. 583 */ 584static void 585draw_depth_pixels( GLcontext *ctx, GLint x, GLint y, 586 GLsizei width, GLsizei height, 587 GLenum type, const GLvoid *pixels ) 588{ 589 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0; 590 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 591 const GLint desty = y; 592 GLchan rgba[MAX_WIDTH][4]; 593 GLuint ispan[MAX_WIDTH]; 594 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 595 596 if (type != GL_BYTE 597 && type != GL_UNSIGNED_BYTE 598 && type != GL_SHORT 599 && type != GL_UNSIGNED_SHORT 600 && type != GL_INT 601 && type != GL_UNSIGNED_INT 602 && type != GL_FLOAT) { 603 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)"); 604 return; 605 } 606 607 /* Colors or indexes */ 608 if (ctx->Visual.rgbMode) { 609 GLint i; 610 GLint r, g, b, a; 611 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]); 612 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]); 613 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]); 614 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]); 615 for (i = 0; i < drawWidth; i++) { 616 rgba[i][RCOMP] = r; 617 rgba[i][GCOMP] = g; 618 rgba[i][BCOMP] = b; 619 rgba[i][ACOMP] = a; 620 } 621 } 622 else { 623 GLint i; 624 for (i = 0; i < drawWidth; i++) { 625 ispan[i] = ctx->Current.RasterIndex; 626 } 627 } 628 629 if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort) 630 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) { 631 /* Special case: directly write 16-bit depth values */ 632 GLint row; 633 for (row = 0; row < height; row++, y++) { 634 GLdepth zspan[MAX_WIDTH]; 635 const GLushort *zptr = (const GLushort *) 636 _mesa_image_address(&ctx->Unpack, pixels, width, height, 637 GL_DEPTH_COMPONENT, type, 0, row, 0); 638 GLint i; 639 for (i = 0; i < width; i++) 640 zspan[i] = zptr[i]; 641 _mesa_write_rgba_span( ctx, width, x, y, zspan, 0, rgba, GL_BITMAP ); 642 } 643 } 644 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32 645 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) { 646 /* Special case: directly write 32-bit depth values */ 647 GLint row; 648 for (row = 0; row < height; row++, y++) { 649 const GLuint *zptr = (const GLuint *) 650 _mesa_image_address(&ctx->Unpack, pixels, width, height, 651 GL_DEPTH_COMPONENT, type, 0, row, 0); 652 _mesa_write_rgba_span( ctx, width, x, y, zptr, 0, rgba, GL_BITMAP ); 653 } 654 } 655 else { 656 /* General case */ 657 GLint row; 658 for (row = 0; row < height; row++, y++) { 659 GLfloat fspan[MAX_WIDTH]; 660 GLdepth zspan[MAX_WIDTH]; 661 const GLvoid *src = _mesa_image_address(&ctx->Unpack, 662 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0); 663 _mesa_unpack_depth_span( ctx, drawWidth, fspan, type, src, 664 &ctx->Unpack ); 665 /* clamp depth values to [0,1] and convert from floats to integers */ 666 { 667 const GLfloat zs = ctx->DepthMaxF; 668 GLint i; 669 for (i = 0; i < drawWidth; i++) { 670 zspan[i] = (GLdepth) (fspan[i] * zs); 671 } 672 } 673 674 if (ctx->Visual.rgbMode) { 675 if (zoom) { 676 _mesa_write_zoomed_rgba_span(ctx, width, x, y, zspan, 0, 677 (const GLchan (*)[4]) rgba, desty); 678 } 679 else { 680 _mesa_write_rgba_span(ctx, width, x, y, zspan, 0, rgba, GL_BITMAP); 681 } 682 } 683 else { 684 if (zoom) { 685 _mesa_write_zoomed_index_span(ctx, width, x, y, zspan, 0, 686 ispan, GL_BITMAP); 687 } 688 else { 689 _mesa_write_index_span(ctx, width, x, y, zspan, 0, 690 ispan, GL_BITMAP); 691 } 692 } 693 694 } 695 } 696} 697 698 699/* 700 * Do glDrawPixels of RGBA pixels. 701 */ 702static void 703draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y, 704 GLsizei width, GLsizei height, 705 GLenum format, GLenum type, const GLvoid *pixels ) 706{ 707 SWcontext *swrast = SWRAST_CONTEXT(ctx); 708 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; 709 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 710 const GLint desty = y; 711 GLdepth zspan[MAX_WIDTH]; 712 GLboolean quickDraw; 713 GLfloat *convImage = NULL; 714 GLuint transferOps = ctx->_ImageTransferState; 715 716 if (!_mesa_is_legal_format_and_type(format, type)) { 717 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)"); 718 return; 719 } 720 721 /* Try an optimized glDrawPixels first */ 722 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels)) 723 return; 724 725 /* Fragment depth values */ 726 if (ctx->Depth.Test || ctx->Fog.Enabled) { 727 /* fill in array of z values */ 728 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF); 729 GLint i; 730 for (i=0;i<width;i++) { 731 zspan[i] = z; 732 } 733 } 734 735 736 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0 737 && x + width <= ctx->DrawBuffer->Width 738 && y + height <= ctx->DrawBuffer->Height) { 739 quickDraw = GL_TRUE; 740 } 741 else { 742 quickDraw = GL_FALSE; 743 } 744 745 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 746 /* Convolution has to be handled specially. We'll create an 747 * intermediate image, applying all pixel transfer operations 748 * up to convolution. Then we'll convolve the image. Then 749 * we'll proceed with the rest of the transfer operations and 750 * rasterize the image. 751 */ 752 GLint row; 753 GLfloat *dest, *tmpImage; 754 755 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 756 if (!tmpImage) { 757 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 758 return; 759 } 760 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 761 if (!convImage) { 762 FREE(tmpImage); 763 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 764 return; 765 } 766 767 /* Unpack the image and apply transfer ops up to convolution */ 768 dest = tmpImage; 769 for (row = 0; row < height; row++) { 770 const GLvoid *source = _mesa_image_address(unpack, 771 pixels, width, height, format, type, 0, row, 0); 772 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest, 773 format, type, source, unpack, 774 transferOps & IMAGE_PRE_CONVOLUTION_BITS, 775 GL_FALSE); 776 dest += width * 4; 777 } 778 779 /* do convolution */ 780 if (ctx->Pixel.Convolution2DEnabled) { 781 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 782 } 783 else { 784 ASSERT(ctx->Pixel.Separable2DEnabled); 785 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 786 } 787 FREE(tmpImage); 788 789 /* continue transfer ops and draw the convolved image */ 790 unpack = &_mesa_native_packing; 791 pixels = convImage; 792 format = GL_RGBA; 793 type = GL_FLOAT; 794 transferOps &= IMAGE_POST_CONVOLUTION_BITS; 795 } 796 797 /* 798 * General solution 799 */ 800 { 801 GLchan rgba[MAX_WIDTH][4]; 802 GLint row; 803 if (width > MAX_WIDTH) 804 width = MAX_WIDTH; 805 for (row = 0; row < height; row++, y++) { 806 const GLvoid *source = _mesa_image_address(unpack, 807 pixels, width, height, format, type, 0, row, 0); 808 _mesa_unpack_chan_color_span(ctx, width, GL_RGBA, (GLchan *) rgba, 809 format, type, source, unpack, 810 transferOps); 811 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) || 812 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink)) 813 continue; 814 815 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) { 816 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH]; 817 GLchan primary_rgba[MAX_WIDTH][4]; 818 GLuint unit; 819 /* XXX not sure how multitexture is supposed to work here */ 820 821 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan)); 822 823 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 824 if (ctx->Texture.Unit[unit]._ReallyEnabled) { 825 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba, 826 s, t, r, q); 827 _swrast_texture_fragments(ctx, unit, width, s, t, r, NULL, 828 (CONST GLchan (*)[4]) primary_rgba, 829 rgba); 830 } 831 } 832 } 833 834 if (quickDraw) { 835 (*swrast->Driver.WriteRGBASpan)( ctx, width, x, y, 836 (CONST GLchan (*)[]) rgba, NULL); 837 } 838 else if (zoom) { 839 _mesa_write_zoomed_rgba_span( ctx, width, x, y, zspan, 0, 840 (CONST GLchan (*)[]) rgba, desty ); 841 } 842 else { 843 _mesa_write_rgba_span( ctx, (GLuint) width, x, y, zspan, 0, 844 rgba, GL_BITMAP); 845 } 846 } 847 } 848 849 if (convImage) { 850 FREE(convImage); 851 } 852} 853 854 855 856/* 857 * Execute glDrawPixels 858 */ 859void 860_swrast_DrawPixels( GLcontext *ctx, 861 GLint x, GLint y, 862 GLsizei width, GLsizei height, 863 GLenum format, GLenum type, 864 const struct gl_pixelstore_attrib *unpack, 865 const GLvoid *pixels ) 866{ 867 SWcontext *swrast = SWRAST_CONTEXT(ctx); 868 (void) unpack; 869 870 871 if (swrast->NewState) 872 _swrast_validate_derived( ctx ); 873 874 RENDER_START(swrast,ctx); 875 876 switch (format) { 877 case GL_STENCIL_INDEX: 878 draw_stencil_pixels( ctx, x, y, width, height, type, pixels ); 879 break; 880 case GL_DEPTH_COMPONENT: 881 draw_depth_pixels( ctx, x, y, width, height, type, pixels ); 882 break; 883 case GL_COLOR_INDEX: 884 if (ctx->Visual.rgbMode) 885 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels); 886 else 887 draw_index_pixels(ctx, x, y, width, height, type, pixels); 888 break; 889 case GL_RED: 890 case GL_GREEN: 891 case GL_BLUE: 892 case GL_ALPHA: 893 case GL_LUMINANCE: 894 case GL_LUMINANCE_ALPHA: 895 case GL_RGB: 896 case GL_BGR: 897 case GL_RGBA: 898 case GL_BGRA: 899 case GL_ABGR_EXT: 900 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels); 901 break; 902 default: 903 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" ); 904 } 905 906 RENDER_FINISH(swrast,ctx); 907} 908