s_drawpix.c revision b7f5e92f1749ce4601a758f66ddc64959f11742b
1/* $Id: s_drawpix.c,v 1.32 2002/04/12 15:39:59 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 4.1 6 * 7 * Copyright (C) 1999-2002 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 struct sw_span span; 106 107 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 108 /*span.arrayMask |= SPAN_RGBA;*/ 109 110 if (!ctx->Current.RasterPosValid) { 111 return GL_TRUE; /* no-op */ 112 } 113 114 if (ctx->Depth.Test) 115 _mesa_span_default_z(ctx, &span); 116 if (ctx->Fog.Enabled) 117 _mesa_span_default_fog(ctx, &span); 118 119 if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0 120 && ctx->Texture._ReallyEnabled == 0 121 && unpack->Alignment == 1 122 && !unpack->SwapBytes 123 && !unpack->LsbFirst) { 124 125 GLint destX = x; 126 GLint destY = y; 127 GLint drawWidth = width; /* actual width drawn */ 128 GLint drawHeight = height; /* actual height drawn */ 129 GLint skipPixels = unpack->SkipPixels; 130 GLint skipRows = unpack->SkipRows; 131 GLint rowLength; 132 GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */ 133 GLint zoomY0 = 0; 134 135 if (unpack->RowLength > 0) 136 rowLength = unpack->RowLength; 137 else 138 rowLength = width; 139 140 /* If we're not using pixel zoom then do all clipping calculations 141 * now. Otherwise, we'll let the _mesa_write_zoomed_*_span() functions 142 * handle the clipping. 143 */ 144 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 145 /* horizontal clipping */ 146 if (destX < ctx->DrawBuffer->_Xmin) { 147 skipPixels += (ctx->DrawBuffer->_Xmin - destX); 148 drawWidth -= (ctx->DrawBuffer->_Xmin - destX); 149 destX = ctx->DrawBuffer->_Xmin; 150 } 151 if (destX + drawWidth > ctx->DrawBuffer->_Xmax) 152 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); 153 if (drawWidth <= 0) 154 return GL_TRUE; 155 156 /* vertical clipping */ 157 if (destY < ctx->DrawBuffer->_Ymin) { 158 skipRows += (ctx->DrawBuffer->_Ymin - destY); 159 drawHeight -= (ctx->DrawBuffer->_Ymin - destY); 160 destY = ctx->DrawBuffer->_Ymin; 161 } 162 if (destY + drawHeight > ctx->DrawBuffer->_Ymax) 163 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax); 164 if (drawHeight <= 0) 165 return GL_TRUE; 166 } 167 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 168 /* upside-down image */ 169 /* horizontal clipping */ 170 if (destX < ctx->DrawBuffer->_Xmin) { 171 skipPixels += (ctx->DrawBuffer->_Xmin - destX); 172 drawWidth -= (ctx->DrawBuffer->_Xmin - destX); 173 destX = ctx->DrawBuffer->_Xmin; 174 } 175 if (destX + drawWidth > ctx->DrawBuffer->_Xmax) 176 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax); 177 if (drawWidth <= 0) 178 return GL_TRUE; 179 180 /* vertical clipping */ 181 if (destY > ctx->DrawBuffer->_Ymax) { 182 skipRows += (destY - ctx->DrawBuffer->_Ymax); 183 drawHeight -= (destY - ctx->DrawBuffer->_Ymax); 184 destY = ctx->DrawBuffer->_Ymax; 185 } 186 if (destY - drawHeight < ctx->DrawBuffer->_Ymin) 187 drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight)); 188 if (drawHeight <= 0) 189 return GL_TRUE; 190 } 191 else { 192 /* setup array of fragment Z value to pass to zoom function */ 193 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF); 194 GLint i; 195 ASSERT(drawWidth < MAX_WIDTH); 196 for (i=0; i<drawWidth; i++) 197 zSpan[i] = z; 198 199 /* save Y value of first row */ 200 zoomY0 = IROUND(ctx->Current.RasterPos[1]); 201 } 202 203 204 /* 205 * Ready to draw! 206 * The window region at (destX, destY) of size (drawWidth, drawHeight) 207 * will be written to. 208 * We'll take pixel data from buffer pointed to by "pixels" but we'll 209 * skip "skipRows" rows and skip "skipPixels" pixels/row. 210 */ 211 212 if (format == GL_RGBA && type == CHAN_TYPE 213 && ctx->_ImageTransferState==0) { 214 if (ctx->Visual.rgbMode) { 215 GLchan *src = (GLchan *) pixels 216 + (skipRows * rowLength + skipPixels) * 4; 217 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 218 /* no zooming */ 219 GLint row; 220 for (row=0; row<drawHeight; row++) { 221 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 222 (CONST GLchan (*)[4]) src, NULL); 223 src += rowLength * 4; 224 destY++; 225 } 226 } 227 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 228 /* upside-down */ 229 GLint row; 230 for (row=0; row<drawHeight; row++) { 231 destY--; 232 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 233 (CONST GLchan (*)[4]) src, NULL); 234 src += rowLength * 4; 235 } 236 } 237 else { 238 /* with zooming */ 239 GLint row; 240 for (row=0; row<drawHeight; row++) { 241 span.x = destX; 242 span.y = destY; 243 span.end = drawWidth; 244 _mesa_write_zoomed_rgba_span(ctx, &span, 245 (CONST GLchan (*)[4]) src, zoomY0); 246 src += rowLength * 4; 247 destY++; 248 } 249 } 250 } 251 return GL_TRUE; 252 } 253 else if (format == GL_RGB && type == CHAN_TYPE 254 && ctx->_ImageTransferState == 0) { 255 if (ctx->Visual.rgbMode) { 256 GLchan *src = (GLchan *) pixels 257 + (skipRows * rowLength + skipPixels) * 3; 258 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 259 GLint row; 260 for (row=0; row<drawHeight; row++) { 261 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 262 (CONST GLchan (*)[3]) src, NULL); 263 src += rowLength * 3; 264 destY++; 265 } 266 } 267 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 268 /* upside-down */ 269 GLint row; 270 for (row=0; row<drawHeight; row++) { 271 destY--; 272 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 273 (CONST GLchan (*)[3]) src, NULL); 274 src += rowLength * 3; 275 } 276 } 277 else { 278 /* with zooming */ 279 GLint row; 280 for (row=0; row<drawHeight; row++) { 281 span.x = destX; 282 span.y = destY; 283 span.end = drawWidth; 284 _mesa_write_zoomed_rgb_span(ctx, &span, 285 (CONST GLchan (*)[3]) src, zoomY0); 286 src += rowLength * 3; 287 destY++; 288 } 289 } 290 } 291 return GL_TRUE; 292 } 293 else if (format == GL_LUMINANCE && type == CHAN_TYPE 294 && ctx->_ImageTransferState==0) { 295 if (ctx->Visual.rgbMode) { 296 GLchan *src = (GLchan *) pixels 297 + (skipRows * rowLength + skipPixels); 298 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 299 /* no zooming */ 300 GLint row; 301 ASSERT(drawWidth < MAX_WIDTH); 302 for (row=0; row<drawHeight; row++) { 303 GLint i; 304 for (i=0;i<drawWidth;i++) { 305 span.color.rgb[i][0] = src[i]; 306 span.color.rgb[i][1] = src[i]; 307 span.color.rgb[i][2] = src[i]; 308 } 309 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 310 (CONST GLchan (*)[3]) span.color.rgb, NULL); 311 src += rowLength; 312 destY++; 313 } 314 } 315 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 316 /* upside-down */ 317 GLint row; 318 ASSERT(drawWidth < MAX_WIDTH); 319 for (row=0; row<drawHeight; row++) { 320 GLint i; 321 for (i=0;i<drawWidth;i++) { 322 span.color.rgb[i][0] = src[i]; 323 span.color.rgb[i][1] = src[i]; 324 span.color.rgb[i][2] = src[i]; 325 } 326 destY--; 327 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 328 (CONST GLchan (*)[3]) span.color.rgb, NULL); 329 src += rowLength; 330 } 331 } 332 else { 333 /* with zooming */ 334 GLint row; 335 ASSERT(drawWidth < MAX_WIDTH); 336 for (row=0; row<drawHeight; row++) { 337 GLint i; 338 for (i=0;i<drawWidth;i++) { 339 span.color.rgb[i][0] = src[i]; 340 span.color.rgb[i][1] = src[i]; 341 span.color.rgb[i][2] = src[i]; 342 } 343 span.x = destX; 344 span.y = destY; 345 span.end = drawWidth; 346 _mesa_write_zoomed_rgb_span(ctx, &span, 347 (CONST GLchan (*)[3]) span.color.rgb, zoomY0); 348 src += rowLength; 349 destY++; 350 } 351 } 352 } 353 return GL_TRUE; 354 } 355 else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE 356 && ctx->_ImageTransferState == 0) { 357 if (ctx->Visual.rgbMode) { 358 GLchan *src = (GLchan *) pixels 359 + (skipRows * rowLength + skipPixels)*2; 360 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 361 /* no zooming */ 362 GLint row; 363 ASSERT(drawWidth < MAX_WIDTH); 364 for (row=0; row<drawHeight; row++) { 365 GLint i; 366 GLchan *ptr = src; 367 for (i=0;i<drawWidth;i++) { 368 span.color.rgba[i][0] = *ptr; 369 span.color.rgba[i][1] = *ptr; 370 span.color.rgba[i][2] = *ptr++; 371 span.color.rgba[i][3] = *ptr++; 372 } 373 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 374 (CONST GLchan (*)[4]) span.color.rgba, NULL); 375 src += rowLength*2; 376 destY++; 377 } 378 } 379 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 380 /* upside-down */ 381 GLint row; 382 ASSERT(drawWidth < MAX_WIDTH); 383 for (row=0; row<drawHeight; row++) { 384 GLint i; 385 GLchan *ptr = src; 386 for (i=0;i<drawWidth;i++) { 387 span.color.rgba[i][0] = *ptr; 388 span.color.rgba[i][1] = *ptr; 389 span.color.rgba[i][2] = *ptr++; 390 span.color.rgba[i][3] = *ptr++; 391 } 392 destY--; 393 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 394 (CONST GLchan (*)[4]) span.color.rgba, NULL); 395 src += rowLength*2; 396 } 397 } 398 else { 399 /* with zooming */ 400 GLint row; 401 ASSERT(drawWidth < MAX_WIDTH); 402 for (row=0; row<drawHeight; row++) { 403 GLchan *ptr = src; 404 GLint i; 405 for (i=0;i<drawWidth;i++) { 406 span.color.rgba[i][0] = *ptr; 407 span.color.rgba[i][1] = *ptr; 408 span.color.rgba[i][2] = *ptr++; 409 span.color.rgba[i][3] = *ptr++; 410 } 411 span.x = destX; 412 span.y = destY; 413 span.end = drawWidth; 414 _mesa_write_zoomed_rgba_span(ctx, &span, 415 (CONST GLchan (*)[4]) span.color.rgba, zoomY0); 416 src += rowLength*2; 417 destY++; 418 } 419 } 420 } 421 return GL_TRUE; 422 } 423 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) { 424 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels; 425 if (ctx->Visual.rgbMode) { 426 /* convert CI data to RGBA */ 427 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 428 /* no zooming */ 429 GLint row; 430 for (row=0; row<drawHeight; row++) { 431 ASSERT(drawWidth < MAX_WIDTH); 432 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.color.rgba); 433 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 434 (const GLchan (*)[4]) span.color.rgba, NULL); 435 src += rowLength; 436 destY++; 437 } 438 return GL_TRUE; 439 } 440 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 441 /* upside-down */ 442 GLint row; 443 for (row=0; row<drawHeight; row++) { 444 ASSERT(drawWidth < MAX_WIDTH); 445 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.color.rgba); 446 destY--; 447 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 448 (CONST GLchan (*)[4]) span.color.rgba, NULL); 449 src += rowLength; 450 } 451 return GL_TRUE; 452 } 453 else { 454 /* with zooming */ 455 GLint row; 456 for (row=0; row<drawHeight; row++) { 457 ASSERT(drawWidth < MAX_WIDTH); 458 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, span.color.rgba); 459 span.x = destX; 460 span.y = destY; 461 span.end = drawWidth; 462 _mesa_write_zoomed_rgba_span(ctx, &span, 463 (CONST GLchan (*)[4]) span.color.rgba, zoomY0); 464 src += rowLength; 465 destY++; 466 } 467 return GL_TRUE; 468 } 469 } 470 else if (ctx->_ImageTransferState==0) { 471 /* write CI data to CI frame buffer */ 472 GLint row; 473 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 474 /* no zooming */ 475 for (row=0; row<drawHeight; row++) { 476 (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY, 477 src, NULL); 478 src += rowLength; 479 destY++; 480 } 481 return GL_TRUE; 482 } 483 else { 484 /* with zooming */ 485 return GL_FALSE; 486 } 487 } 488 } 489 else { 490 /* can't handle this pixel format and/or data type here */ 491 return GL_FALSE; 492 } 493 } 494 495 /* can't do a simple draw, have to use slow path */ 496 return GL_FALSE; 497} 498 499 500 501/* 502 * Do glDrawPixels of index pixels. 503 */ 504static void 505draw_index_pixels( GLcontext *ctx, GLint x, GLint y, 506 GLsizei width, GLsizei height, 507 GLenum type, const GLvoid *pixels ) 508{ 509 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 510 const GLint desty = y; 511 GLint row, drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 512 struct sw_span span; 513 514 INIT_SPAN(span, GL_BITMAP, drawWidth, 0, SPAN_INDEX); 515 /*span.arrayMask |= SPAN_INDEX;*/ 516 517 if (ctx->Depth.Test) 518 _mesa_span_default_z(ctx, &span); 519 if (ctx->Fog.Enabled) 520 _mesa_span_default_fog(ctx, &span); 521 522 /* 523 * General solution 524 */ 525 for (row = 0; row < height; row++, y++) { 526 const GLvoid *source = _mesa_image_address(&ctx->Unpack, 527 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0); 528 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, 529 span.color.index, 530 type, source, &ctx->Unpack, 531 ctx->_ImageTransferState); 532 span.x = x; 533 span.y = y; 534 span.end = drawWidth; 535 if (zoom) 536 _mesa_write_zoomed_index_span(ctx, &span, desty); 537 else 538 _mesa_write_index_span(ctx, &span); 539 } 540} 541 542 543 544/* 545 * Do glDrawPixels of stencil image. The image datatype may either 546 * be GLubyte or GLbitmap. 547 */ 548static void 549draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, 550 GLsizei width, GLsizei height, 551 GLenum type, const GLvoid *pixels ) 552{ 553 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 554 const GLint desty = y; 555 GLint row, drawWidth; 556 557 if (type != GL_BYTE && 558 type != GL_UNSIGNED_BYTE && 559 type != GL_SHORT && 560 type != GL_UNSIGNED_SHORT && 561 type != GL_INT && 562 type != GL_UNSIGNED_INT && 563 type != GL_FLOAT && 564 type != GL_BITMAP) { 565 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)"); 566 return; 567 } 568 569 if (ctx->Visual.stencilBits == 0) { 570 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)"); 571 return; 572 } 573 574 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 575 576 for (row = 0; row < height; row++, y++) { 577 GLstencil values[MAX_WIDTH]; 578 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) 579 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; 580 const GLvoid *source = _mesa_image_address(&ctx->Unpack, 581 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0); 582 _mesa_unpack_index_span(ctx, drawWidth, destType, values, 583 type, source, &ctx->Unpack, 584 ctx->_ImageTransferState); 585 if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) { 586 _mesa_shift_and_offset_stencil( ctx, drawWidth, values ); 587 } 588 if (ctx->Pixel.MapStencilFlag) { 589 _mesa_map_stencil( ctx, drawWidth, values ); 590 } 591 592 if (zoom) { 593 _mesa_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y, 594 values, desty ); 595 } 596 else { 597 _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values ); 598 } 599 } 600} 601 602 603/* 604 * Do a glDrawPixels of depth values. 605 */ 606static void 607draw_depth_pixels( GLcontext *ctx, GLint x, GLint y, 608 GLsizei width, GLsizei height, 609 GLenum type, const GLvoid *pixels ) 610{ 611 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0; 612 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 613 const GLint desty = y; 614 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 615 struct sw_span span; 616 617 INIT_SPAN(span, GL_BITMAP, drawWidth, 0, SPAN_Z); 618 /*span.arrayMask |= SPAN_Z; 619 span.end = drawWidth;*/ 620 621 if (type != GL_BYTE 622 && type != GL_UNSIGNED_BYTE 623 && type != GL_SHORT 624 && type != GL_UNSIGNED_SHORT 625 && type != GL_INT 626 && type != GL_UNSIGNED_INT 627 && type != GL_FLOAT) { 628 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)"); 629 return; 630 } 631 632 _mesa_span_default_color(ctx, &span); 633 634 if (ctx->Fog.Enabled) 635 _mesa_span_default_fog(ctx, &span); 636 637 if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16 638 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) { 639 /* Special case: directly write 16-bit depth values */ 640 GLint row; 641 span.x = x; 642 span.y = y; 643 span.end = drawWidth; 644 for (row = 0; row < height; row++, span.y++) { 645 const GLushort *zptr = (const GLushort *) 646 _mesa_image_address(&ctx->Unpack, pixels, width, height, 647 GL_DEPTH_COMPONENT, type, 0, row, 0); 648 GLint i; 649 for (i = 0; i < drawWidth; i++) 650 span.zArray[i] = zptr[i]; 651 _mesa_write_rgba_span(ctx, &span); 652 } 653 } 654 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32 655 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) { 656 /* Special case: directly write 32-bit depth values */ 657 GLint row; 658 span.x = x; 659 span.y = y; 660 span.end = drawWidth; 661 for (row = 0; row < height; row++, span.y++) { 662 const GLuint *zptr = (const GLuint *) 663 _mesa_image_address(&ctx->Unpack, pixels, width, height, 664 GL_DEPTH_COMPONENT, type, 0, row, 0); 665 MEMCPY(span.zArray, zptr, drawWidth * sizeof(GLdepth)); 666 _mesa_write_rgba_span(ctx, &span); 667 } 668 } 669 else { 670 /* General case */ 671 GLint row; 672 span.x = x; 673 span.y = y; 674 span.end = drawWidth; 675 for (row = 0; row < height; row++, span.y++) { 676 GLfloat fspan[MAX_WIDTH]; 677 const GLvoid *src = _mesa_image_address(&ctx->Unpack, 678 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0); 679 _mesa_unpack_depth_span( ctx, drawWidth, fspan, type, src, 680 &ctx->Unpack ); 681 /* clamp depth values to [0,1] and convert from floats to integers */ 682 { 683 const GLfloat zs = ctx->DepthMaxF; 684 GLint i; 685 for (i = 0; i < drawWidth; i++) { 686 span.zArray[i] = (GLdepth) (fspan[i] * zs + 0.5F); 687 } 688 } 689 if (ctx->Visual.rgbMode) { 690 if (zoom) 691 _mesa_write_zoomed_rgba_span(ctx, &span, 692 (const GLchan (*)[4]) span.color.rgba, desty); 693 else 694 _mesa_write_rgba_span(ctx, &span); 695 } 696 else { 697 if (zoom) 698 _mesa_write_zoomed_index_span(ctx, &span, desty); 699 else 700 _mesa_write_index_span(ctx, &span); 701 } 702 } 703 } 704} 705 706 707/* 708 * Do glDrawPixels of RGBA pixels. 709 */ 710static void 711draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y, 712 GLsizei width, GLsizei height, 713 GLenum format, GLenum type, const GLvoid *pixels ) 714{ 715 SWcontext *swrast = SWRAST_CONTEXT(ctx); 716 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; 717 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 718 const GLint desty = y; 719 GLboolean quickDraw; 720 GLfloat *convImage = NULL; 721 GLuint transferOps = ctx->_ImageTransferState; 722 struct sw_span span; 723 724 INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); 725 /*span.arrayMask |= SPAN_RGBA;*/ 726 727 if (!_mesa_is_legal_format_and_type(format, type)) { 728 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)"); 729 return; 730 } 731 732 /* Try an optimized glDrawPixels first */ 733 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels)) 734 return; 735 736 if (ctx->Depth.Test) 737 _mesa_span_default_z(ctx, &span); 738 if (ctx->Fog.Enabled) 739 _mesa_span_default_fog(ctx, &span); 740 741 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0 742 && x + width <= ctx->DrawBuffer->Width 743 && y + height <= ctx->DrawBuffer->Height) { 744 quickDraw = GL_TRUE; 745 } 746 else { 747 quickDraw = GL_FALSE; 748 } 749 750 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 751 /* Convolution has to be handled specially. We'll create an 752 * intermediate image, applying all pixel transfer operations 753 * up to convolution. Then we'll convolve the image. Then 754 * we'll proceed with the rest of the transfer operations and 755 * rasterize the image. 756 */ 757 GLint row; 758 GLfloat *dest, *tmpImage; 759 760 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 761 if (!tmpImage) { 762 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 763 return; 764 } 765 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 766 if (!convImage) { 767 FREE(tmpImage); 768 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 769 return; 770 } 771 772 /* Unpack the image and apply transfer ops up to convolution */ 773 dest = tmpImage; 774 for (row = 0; row < height; row++) { 775 const GLvoid *source = _mesa_image_address(unpack, 776 pixels, width, height, format, type, 0, row, 0); 777 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest, 778 format, type, source, unpack, 779 transferOps & IMAGE_PRE_CONVOLUTION_BITS, 780 GL_FALSE); 781 dest += width * 4; 782 } 783 784 /* do convolution */ 785 if (ctx->Pixel.Convolution2DEnabled) { 786 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 787 } 788 else { 789 ASSERT(ctx->Pixel.Separable2DEnabled); 790 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 791 } 792 FREE(tmpImage); 793 794 /* continue transfer ops and draw the convolved image */ 795 unpack = &_mesa_native_packing; 796 pixels = convImage; 797 format = GL_RGBA; 798 type = GL_FLOAT; 799 transferOps &= IMAGE_POST_CONVOLUTION_BITS; 800 } 801 802 /* 803 * General solution 804 */ 805 { 806 GLint row; 807 if (width > MAX_WIDTH) 808 width = MAX_WIDTH; 809 for (row = 0; row < height; row++, y++) { 810 const GLvoid *source = _mesa_image_address(unpack, 811 pixels, width, height, format, type, 0, row, 0); 812 _mesa_unpack_chan_color_span(ctx, width, GL_RGBA, 813 (GLchan *) span.color.rgba, 814 format, type, source, unpack, 815 transferOps); 816 817 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) || 818 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink)) 819 continue; 820 821 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._ReallyEnabled) { 822 span.end = width; 823 _swrast_pixel_texture(ctx, &span); 824 } 825 826 if (quickDraw) { 827 (*swrast->Driver.WriteRGBASpan)(ctx, width, x, y, 828 (CONST GLchan (*)[4]) span.color.rgba, NULL); 829 } 830 else if (zoom) { 831 span.x = x; 832 span.y = y; 833 span.end = width; 834 _mesa_write_zoomed_rgba_span(ctx, &span, 835 (CONST GLchan (*)[4]) span.color.rgba, desty); 836 } 837 else { 838 span.x = x; 839 span.y = y; 840 span.end = width; 841 _mesa_write_rgba_span(ctx, &span); 842 } 843 } 844 } 845 846 if (convImage) { 847 FREE(convImage); 848 } 849} 850 851 852 853/* 854 * Execute glDrawPixels 855 */ 856void 857_swrast_DrawPixels( GLcontext *ctx, 858 GLint x, GLint y, 859 GLsizei width, GLsizei height, 860 GLenum format, GLenum type, 861 const struct gl_pixelstore_attrib *unpack, 862 const GLvoid *pixels ) 863{ 864 SWcontext *swrast = SWRAST_CONTEXT(ctx); 865 (void) unpack; 866 867 868 if (swrast->NewState) 869 _swrast_validate_derived( ctx ); 870 871 RENDER_START(swrast,ctx); 872 switch (format) { 873 case GL_STENCIL_INDEX: 874 draw_stencil_pixels( ctx, x, y, width, height, type, pixels ); 875 break; 876 case GL_DEPTH_COMPONENT: 877 draw_depth_pixels( ctx, x, y, width, height, type, pixels ); 878 break; 879 case GL_COLOR_INDEX: 880 if (ctx->Visual.rgbMode) 881 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels); 882 else 883 draw_index_pixels(ctx, x, y, width, height, type, pixels); 884 break; 885 case GL_RED: 886 case GL_GREEN: 887 case GL_BLUE: 888 case GL_ALPHA: 889 case GL_LUMINANCE: 890 case GL_LUMINANCE_ALPHA: 891 case GL_RGB: 892 case GL_BGR: 893 case GL_RGBA: 894 case GL_BGRA: 895 case GL_ABGR_EXT: 896 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels); 897 break; 898 default: 899 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" ); 900 } 901 902 RENDER_FINISH(swrast,ctx); 903} 904