drawpix.c revision 9c05c0494d06dcf429d8489107be49e339305690
1/* $Id: drawpix.c,v 1.36 2000/09/30 18:42:29 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 3.5 6 * 7 * Copyright (C) 1999-2000 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#ifdef PC_HEADER 29#include "all.h" 30#else 31#include "glheader.h" 32#include "context.h" 33#include "convolve.h" 34#include "drawpix.h" 35#include "feedback.h" 36#include "image.h" 37#include "macros.h" 38#include "mem.h" 39#include "mmath.h" 40#include "pixel.h" 41#include "pixeltex.h" 42#include "span.h" 43#include "state.h" 44#include "stencil.h" 45#include "texture.h" 46#include "types.h" 47#include "zoom.h" 48#endif 49 50 51 52/* 53 * Given the dest position, size and skipPixels and skipRows values 54 * for a glDrawPixels command, perform clipping of the image bounds 55 * so the result lies withing the context's buffer bounds. 56 * Return: GL_TRUE if image is ready for drawing 57 * GL_FALSE if image was completely clipped away (draw nothing) 58 */ 59GLboolean 60_mesa_clip_pixelrect(const GLcontext *ctx, 61 GLint *destX, GLint *destY, 62 GLsizei *width, GLsizei *height, 63 GLint *skipPixels, GLint *skipRows) 64{ 65 const GLframebuffer *buffer = ctx->DrawBuffer; 66 67 /* left clipping */ 68 if (*destX < buffer->Xmin) { 69 *skipPixels += (buffer->Xmin - *destX); 70 *width -= (buffer->Xmin - *destX); 71 *destX = buffer->Xmin; 72 } 73 /* right clipping */ 74 if (*destX + *width > buffer->Xmax) 75 *width -= (*destX + *width - buffer->Xmax); 76 77 if (*width <= 0) 78 return GL_FALSE; 79 80 /* bottom clipping */ 81 if (*destY < buffer->Ymin) { 82 *skipRows += (buffer->Ymin - *destY); 83 *height -= (buffer->Ymin - *destY); 84 *destY = buffer->Ymin; 85 } 86 /* top clipping */ 87 if (*destY + *height > buffer->Ymax) 88 *height -= (*destY + *height - buffer->Ymax); 89 90 if (*height <= 0) 91 return GL_TRUE; 92 93 return GL_TRUE; 94} 95 96 97 98/* 99 * Try to do a fast and simple RGB(a) glDrawPixels. 100 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead 101 */ 102static GLboolean 103fast_draw_pixels(GLcontext *ctx, GLint x, GLint y, 104 GLsizei width, GLsizei height, 105 GLenum format, GLenum type, const GLvoid *pixels) 106{ 107 const GLuint cantTransferBits = 108 IMAGE_SCALE_BIAS_BIT | 109 IMAGE_SHIFT_OFFSET_BIT | 110 IMAGE_MAP_COLOR_BIT | 111 IMAGE_COLOR_TABLE_BIT | 112 IMAGE_CONVOLUTION_BIT | 113 IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT | 114 IMAGE_COLOR_MATRIX_BIT | 115 IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT | 116 IMAGE_HISTOGRAM_BIT | 117 IMAGE_MIN_MAX_BIT; 118 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; 119 GLubyte rgb[MAX_WIDTH][3]; 120 GLubyte rgba[MAX_WIDTH][4]; 121 122 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels", 123 GL_FALSE); 124 125 126 if (!ctx->Current.RasterPosValid) { 127 return GL_TRUE; /* no-op */ 128 } 129 130 if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0 131 && (ctx->ImageTransferState & cantTransferBits) == 0 132 && ctx->Texture.ReallyEnabled == 0 133 && unpack->Alignment == 1 134 && !unpack->SwapBytes 135 && !unpack->LsbFirst) { 136 137 GLint destX = x; 138 GLint destY = y; 139 GLint drawWidth = width; /* actual width drawn */ 140 GLint drawHeight = height; /* actual height drawn */ 141 GLint skipPixels = unpack->SkipPixels; 142 GLint skipRows = unpack->SkipRows; 143 GLint rowLength; 144 GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */ 145 GLint zoomY0 = 0; 146 147 if (unpack->RowLength > 0) 148 rowLength = unpack->RowLength; 149 else 150 rowLength = width; 151 152 /* If we're not using pixel zoom then do all clipping calculations 153 * now. Otherwise, we'll let the gl_write_zoomed_*_span() functions 154 * handle the clipping. 155 */ 156 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 157 /* horizontal clipping */ 158 if (destX < ctx->DrawBuffer->Xmin) { 159 skipPixels += (ctx->DrawBuffer->Xmin - destX); 160 drawWidth -= (ctx->DrawBuffer->Xmin - destX); 161 destX = ctx->DrawBuffer->Xmin; 162 } 163 if (destX + drawWidth > ctx->DrawBuffer->Xmax) 164 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax); 165 if (drawWidth <= 0) 166 return GL_TRUE; 167 168 /* vertical clipping */ 169 if (destY < ctx->DrawBuffer->Ymin) { 170 skipRows += (ctx->DrawBuffer->Ymin - destY); 171 drawHeight -= (ctx->DrawBuffer->Ymin - destY); 172 destY = ctx->DrawBuffer->Ymin; 173 } 174 if (destY + drawHeight > ctx->DrawBuffer->Ymax) 175 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax); 176 if (drawHeight <= 0) 177 return GL_TRUE; 178 } 179 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 180 /* upside-down image */ 181 /* horizontal clipping */ 182 if (destX < ctx->DrawBuffer->Xmin) { 183 skipPixels += (ctx->DrawBuffer->Xmin - destX); 184 drawWidth -= (ctx->DrawBuffer->Xmin - destX); 185 destX = ctx->DrawBuffer->Xmin; 186 } 187 if (destX + drawWidth > ctx->DrawBuffer->Xmax) 188 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax); 189 if (drawWidth <= 0) 190 return GL_TRUE; 191 192 /* vertical clipping */ 193 if (destY > ctx->DrawBuffer->Ymax) { 194 skipRows += (destY - ctx->DrawBuffer->Ymax); 195 drawHeight -= (destY - ctx->DrawBuffer->Ymax); 196 destY = ctx->DrawBuffer->Ymax; 197 } 198 if (destY - drawHeight < ctx->DrawBuffer->Ymin) 199 drawHeight -= (ctx->DrawBuffer->Ymin - (destY - drawHeight)); 200 if (drawHeight <= 0) 201 return GL_TRUE; 202 } 203 else { 204 /* setup array of fragment Z value to pass to zoom function */ 205 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF); 206 GLint i; 207 ASSERT(drawWidth < MAX_WIDTH); 208 for (i=0; i<drawWidth; i++) 209 zSpan[i] = z; 210 211 /* save Y value of first row */ 212 zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F); 213 } 214 215 216 /* 217 * Ready to draw! 218 * The window region at (destX, destY) of size (drawWidth, drawHeight) 219 * will be written to. 220 * We'll take pixel data from buffer pointed to by "pixels" but we'll 221 * skip "skipRows" rows and skip "skipPixels" pixels/row. 222 */ 223 224 if (format==GL_RGBA && type==GL_UNSIGNED_BYTE) { 225 if (ctx->Visual.RGBAflag) { 226 GLubyte *src = (GLubyte *) pixels 227 + (skipRows * rowLength + skipPixels) * 4; 228 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 229 /* no zooming */ 230 GLint row; 231 for (row=0; row<drawHeight; row++) { 232 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 233 (void *) src, NULL); 234 src += rowLength * 4; 235 destY++; 236 } 237 } 238 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 239 /* upside-down */ 240 GLint row; 241 for (row=0; row<drawHeight; row++) { 242 destY--; 243 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 244 (void *) src, NULL); 245 src += rowLength * 4; 246 } 247 } 248 else { 249 /* with zooming */ 250 GLint row; 251 for (row=0; row<drawHeight; row++) { 252 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY, 253 zSpan, (void *) src, zoomY0); 254 src += rowLength * 4; 255 destY++; 256 } 257 } 258 } 259 return GL_TRUE; 260 } 261 else if (format==GL_RGB && type==GL_UNSIGNED_BYTE) { 262 if (ctx->Visual.RGBAflag) { 263 GLubyte *src = (GLubyte *) pixels 264 + (skipRows * rowLength + skipPixels) * 3; 265 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 266 GLint row; 267 for (row=0; row<drawHeight; row++) { 268 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 269 (void *) src, NULL); 270 src += rowLength * 3; 271 destY++; 272 } 273 } 274 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 275 /* upside-down */ 276 GLint row; 277 for (row=0; row<drawHeight; row++) { 278 destY--; 279 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 280 (void *) src, NULL); 281 src += rowLength * 3; 282 } 283 } 284 else { 285 /* with zooming */ 286 GLint row; 287 for (row=0; row<drawHeight; row++) { 288 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY, 289 zSpan, (void *) src, zoomY0); 290 src += rowLength * 3; 291 destY++; 292 } 293 } 294 } 295 return GL_TRUE; 296 } 297 else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE) { 298 if (ctx->Visual.RGBAflag) { 299 GLubyte *src = (GLubyte *) pixels 300 + (skipRows * rowLength + skipPixels); 301 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 302 /* no zooming */ 303 GLint row; 304 ASSERT(drawWidth < MAX_WIDTH); 305 for (row=0; row<drawHeight; row++) { 306 GLint i; 307 for (i=0;i<drawWidth;i++) { 308 rgb[i][0] = src[i]; 309 rgb[i][1] = src[i]; 310 rgb[i][2] = src[i]; 311 } 312 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 313 (void *) rgb, NULL); 314 src += rowLength; 315 destY++; 316 } 317 } 318 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 319 /* upside-down */ 320 GLint row; 321 ASSERT(drawWidth < MAX_WIDTH); 322 for (row=0; row<drawHeight; row++) { 323 GLint i; 324 for (i=0;i<drawWidth;i++) { 325 rgb[i][0] = src[i]; 326 rgb[i][1] = src[i]; 327 rgb[i][2] = src[i]; 328 } 329 destY--; 330 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY, 331 (void *) rgb, NULL); 332 src += rowLength; 333 } 334 } 335 else { 336 /* with zooming */ 337 GLint row; 338 ASSERT(drawWidth < MAX_WIDTH); 339 for (row=0; row<drawHeight; row++) { 340 GLint i; 341 for (i=0;i<drawWidth;i++) { 342 rgb[i][0] = src[i]; 343 rgb[i][1] = src[i]; 344 rgb[i][2] = src[i]; 345 } 346 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY, 347 zSpan, (void *) rgb, zoomY0); 348 src += rowLength; 349 destY++; 350 } 351 } 352 } 353 return GL_TRUE; 354 } 355 else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE) { 356 if (ctx->Visual.RGBAflag) { 357 GLubyte *src = (GLubyte *) pixels 358 + (skipRows * rowLength + skipPixels)*2; 359 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 360 /* no zooming */ 361 GLint row; 362 ASSERT(drawWidth < MAX_WIDTH); 363 for (row=0; row<drawHeight; row++) { 364 GLint i; 365 GLubyte *ptr = src; 366 for (i=0;i<drawWidth;i++) { 367 rgba[i][0] = *ptr; 368 rgba[i][1] = *ptr; 369 rgba[i][2] = *ptr++; 370 rgba[i][3] = *ptr++; 371 } 372 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 373 (void *) rgba, NULL); 374 src += rowLength*2; 375 destY++; 376 } 377 } 378 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 379 /* upside-down */ 380 GLint row; 381 ASSERT(drawWidth < MAX_WIDTH); 382 for (row=0; row<drawHeight; row++) { 383 GLint i; 384 GLubyte *ptr = src; 385 for (i=0;i<drawWidth;i++) { 386 rgba[i][0] = *ptr; 387 rgba[i][1] = *ptr; 388 rgba[i][2] = *ptr++; 389 rgba[i][3] = *ptr++; 390 } 391 destY--; 392 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 393 (void *) rgba, NULL); 394 src += rowLength*2; 395 } 396 } 397 else { 398 /* with zooming */ 399 GLint row; 400 ASSERT(drawWidth < MAX_WIDTH); 401 for (row=0; row<drawHeight; row++) { 402 GLubyte *ptr = src; 403 GLint i; 404 for (i=0;i<drawWidth;i++) { 405 rgba[i][0] = *ptr; 406 rgba[i][1] = *ptr; 407 rgba[i][2] = *ptr++; 408 rgba[i][3] = *ptr++; 409 } 410 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY, 411 zSpan, (void *) rgba, zoomY0); 412 src += rowLength*2; 413 destY++; 414 } 415 } 416 } 417 return GL_TRUE; 418 } 419 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) { 420 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels; 421 if (ctx->Visual.RGBAflag) { 422 /* convert CI data to RGBA */ 423 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 424 /* no zooming */ 425 GLint row; 426 for (row=0; row<drawHeight; row++) { 427 ASSERT(drawWidth < MAX_WIDTH); 428 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba); 429 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 430 (const GLubyte (*)[4])rgba, 431 NULL); 432 src += rowLength; 433 destY++; 434 } 435 return GL_TRUE; 436 } 437 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) { 438 /* upside-down */ 439 GLint row; 440 for (row=0; row<drawHeight; row++) { 441 ASSERT(drawWidth < MAX_WIDTH); 442 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba); 443 destY--; 444 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY, 445 (const GLubyte (*)[4])rgba, 446 NULL); 447 src += rowLength; 448 } 449 return GL_TRUE; 450 } 451 else { 452 /* with zooming */ 453 GLint row; 454 for (row=0; row<drawHeight; row++) { 455 ASSERT(drawWidth < MAX_WIDTH); 456 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba); 457 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY, 458 zSpan, (void *) rgba, zoomY0); 459 src += rowLength; 460 destY++; 461 } 462 return GL_TRUE; 463 } 464 } 465 else { 466 /* write CI data to CI frame buffer */ 467 GLint row; 468 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 469 /* no zooming */ 470 for (row=0; row<drawHeight; row++) { 471 (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY, 472 src, NULL); 473 src += rowLength; 474 destY++; 475 } 476 return GL_TRUE; 477 } 478 else { 479 /* with zooming */ 480 return GL_FALSE; 481 } 482 } 483 } 484 else { 485 /* can't handle this pixel format and/or data type here */ 486 return GL_FALSE; 487 } 488 } 489 490 /* can't do a simple draw, have to use slow path */ 491 return GL_FALSE; 492} 493 494 495 496/* 497 * Do glDrawPixels of index pixels. 498 */ 499static void 500draw_index_pixels( GLcontext *ctx, GLint x, GLint y, 501 GLsizei width, GLsizei height, 502 GLenum type, const GLvoid *pixels ) 503{ 504 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 505 const GLint desty = y; 506 GLint row, drawWidth; 507 GLdepth zspan[MAX_WIDTH]; 508 509 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 510 511 /* Fragment depth values */ 512 if (ctx->Depth.Test || ctx->Fog.Enabled) { 513 GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF); 514 GLint i; 515 for (i = 0; i < drawWidth; i++) { 516 zspan[i] = zval; 517 } 518 } 519 520 /* 521 * General solution 522 */ 523 for (row = 0; row < height; row++, y++) { 524 GLuint indexes[MAX_WIDTH]; 525 const GLvoid *source = _mesa_image_address(&ctx->Unpack, 526 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0); 527 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes, 528 type, source, &ctx->Unpack, 529 ctx->ImageTransferState); 530 if (zoom) { 531 gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty); 532 } 533 else { 534 gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP); 535 } 536 } 537} 538 539 540 541/* 542 * Do glDrawPixels of stencil image. The image datatype may either 543 * be GLubyte or GLbitmap. 544 */ 545static void 546draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y, 547 GLsizei width, GLsizei height, 548 GLenum type, const GLvoid *pixels ) 549{ 550 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 551 const GLint desty = y; 552 GLint row, drawWidth; 553 554 if (type != GL_BYTE && 555 type != GL_UNSIGNED_BYTE && 556 type != GL_SHORT && 557 type != GL_UNSIGNED_SHORT && 558 type != GL_INT && 559 type != GL_UNSIGNED_INT && 560 type != GL_FLOAT && 561 type != GL_BITMAP) { 562 gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)"); 563 return; 564 } 565 566 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 567 568 for (row = 0; row < height; row++, y++) { 569 GLstencil values[MAX_WIDTH]; 570 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte)) 571 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT; 572 const GLvoid *source = _mesa_image_address(&ctx->Unpack, 573 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0); 574 _mesa_unpack_index_span(ctx, drawWidth, destType, values, 575 type, source, &ctx->Unpack, 576 ctx->ImageTransferState); 577 if (ctx->ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) { 578 _mesa_shift_and_offset_stencil( ctx, drawWidth, values ); 579 } 580 if (ctx->Pixel.MapStencilFlag) { 581 _mesa_map_stencil( ctx, drawWidth, values ); 582 } 583 584 if (zoom) { 585 gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y, 586 values, desty ); 587 } 588 else { 589 _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values ); 590 } 591 } 592} 593 594 595 596/* 597 * Do a glDrawPixels of depth values. 598 */ 599static void 600draw_depth_pixels( GLcontext *ctx, GLint x, GLint y, 601 GLsizei width, GLsizei height, 602 GLenum type, const GLvoid *pixels ) 603{ 604 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0; 605 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0; 606 const GLint desty = y; 607 GLubyte rgba[MAX_WIDTH][4]; 608 GLuint ispan[MAX_WIDTH]; 609 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width; 610 611 if (type != GL_BYTE 612 && type != GL_UNSIGNED_BYTE 613 && type != GL_SHORT 614 && type != GL_UNSIGNED_SHORT 615 && type != GL_INT 616 && type != GL_UNSIGNED_INT 617 && type != GL_FLOAT) { 618 gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)"); 619 return; 620 } 621 622 /* Colors or indexes */ 623 if (ctx->Visual.RGBAflag) { 624 GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F); 625 GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F); 626 GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F); 627 GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F); 628 GLint i; 629 for (i = 0; i < drawWidth; i++) { 630 rgba[i][RCOMP] = r; 631 rgba[i][GCOMP] = g; 632 rgba[i][BCOMP] = b; 633 rgba[i][ACOMP] = a; 634 } 635 } 636 else { 637 GLint i; 638 for (i = 0; i < drawWidth; i++) { 639 ispan[i] = ctx->Current.RasterIndex; 640 } 641 } 642 643 if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort) 644 && !bias_or_scale && !zoom && ctx->Visual.RGBAflag) { 645 /* Special case: directly write 16-bit depth values */ 646 GLint row; 647 for (row = 0; row < height; row++, y++) { 648 GLdepth zspan[MAX_WIDTH]; 649 const GLushort *zptr = _mesa_image_address(&ctx->Unpack, 650 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0); 651 GLint i; 652 for (i = 0; i < width; i++) 653 zspan[i] = zptr[i]; 654 gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP ); 655 } 656 } 657 else if (type==GL_UNSIGNED_INT && ctx->Visual.DepthBits == 32 658 && !bias_or_scale && !zoom && ctx->Visual.RGBAflag) { 659 /* Special case: directly write 32-bit depth values */ 660 GLint row; 661 for (row = 0; row < height; row++, y++) { 662 const GLuint *zptr = _mesa_image_address(&ctx->Unpack, 663 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0); 664 gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP ); 665 } 666 } 667 else { 668 /* General case */ 669 GLint row; 670 for (row = 0; row < height; row++, y++) { 671 GLdepth zspan[MAX_WIDTH]; 672 const GLvoid *src = _mesa_image_address(&ctx->Unpack, 673 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0); 674 _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src, 675 &ctx->Unpack, ctx->ImageTransferState ); 676 if (ctx->Visual.RGBAflag) { 677 if (zoom) { 678 gl_write_zoomed_rgba_span(ctx, width, x, y, zspan, 679 (const GLubyte (*)[4])rgba, desty); 680 } 681 else { 682 gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP); 683 } 684 } 685 else { 686 if (zoom) { 687 gl_write_zoomed_index_span(ctx, width, x, y, zspan, 688 ispan, GL_BITMAP); 689 } 690 else { 691 gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP); 692 } 693 } 694 695 } 696 } 697} 698 699 700/* 701 * Do glDrawPixels of RGBA pixels. 702 */ 703static void 704draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y, 705 GLsizei width, GLsizei height, 706 GLenum format, GLenum type, const GLvoid *pixels ) 707{ 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 gl_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->Visual.DepthMaxF); 729 GLint i; 730 for (i=0;i<width;i++) { 731 zspan[i] = z; 732 } 733 } 734 735 736 if (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 gl_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 gl_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, (void *) 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 GLubyte 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_ubyte_color_span(ctx, width, GL_RGBA, (void*) 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 GLubyte 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(GLubyte)); 822 823 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) { 824 if (ctx->Texture.Unit[unit].ReallyEnabled) { 825 _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba, 826 s, t, r, q); 827 gl_texture_pixels(ctx, unit, width, s, t, r, NULL, 828 primary_rgba, rgba); 829 } 830 } 831 } 832 833 if (quickDraw) { 834 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y, 835 (CONST GLubyte (*)[]) rgba, NULL); 836 } 837 else if (zoom) { 838 gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 839 (CONST GLubyte (*)[]) rgba, desty ); 840 } 841 else { 842 gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP); 843 } 844 } 845 } 846 847 if (convImage) { 848 FREE(convImage); 849 } 850} 851 852 853 854/* 855 * Execute glDrawPixels 856 */ 857void 858_mesa_DrawPixels( GLsizei width, GLsizei height, 859 GLenum format, GLenum type, const GLvoid *pixels ) 860{ 861 GET_CURRENT_CONTEXT(ctx); 862 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels"); 863 864 if (ctx->RenderMode==GL_RENDER) { 865 GLint x, y; 866 if (!pixels || !ctx->Current.RasterPosValid) { 867 return; 868 } 869 870 if (ctx->NewState) { 871 gl_update_state(ctx); 872 } 873 874 if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE) 875 _mesa_update_image_transfer_state(ctx); 876 877 x = (GLint) (ctx->Current.RasterPos[0] + 0.5F); 878 y = (GLint) (ctx->Current.RasterPos[1] + 0.5F); 879 880 ctx->OcclusionResult = GL_TRUE; 881 882 /* see if device driver can do the drawpix */ 883 if (ctx->Driver.DrawPixels 884 && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type, 885 &ctx->Unpack, pixels)) { 886 return; 887 } 888 889 switch (format) { 890 case GL_STENCIL_INDEX: 891 draw_stencil_pixels( ctx, x, y, width, height, type, pixels ); 892 break; 893 case GL_DEPTH_COMPONENT: 894 draw_depth_pixels( ctx, x, y, width, height, type, pixels ); 895 break; 896 case GL_COLOR_INDEX: 897 if (ctx->Visual.RGBAflag) 898 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels); 899 else 900 draw_index_pixels(ctx, x, y, width, height, type, pixels); 901 break; 902 case GL_RED: 903 case GL_GREEN: 904 case GL_BLUE: 905 case GL_ALPHA: 906 case GL_LUMINANCE: 907 case GL_LUMINANCE_ALPHA: 908 case GL_RGB: 909 case GL_BGR: 910 case GL_RGBA: 911 case GL_BGRA: 912 case GL_ABGR_EXT: 913 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels); 914 break; 915 default: 916 gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" ); 917 return; 918 } 919 } 920 else if (ctx->RenderMode==GL_FEEDBACK) { 921 if (ctx->Current.RasterPosValid) { 922 GLfloat color[4]; 923 GLfloat texcoord[4], invq; 924 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor); 925 invq = 1.0F / ctx->Current.Texcoord[0][3]; 926 texcoord[0] = ctx->Current.Texcoord[0][0] * invq; 927 texcoord[1] = ctx->Current.Texcoord[0][1] * invq; 928 texcoord[2] = ctx->Current.Texcoord[0][2] * invq; 929 texcoord[3] = ctx->Current.Texcoord[0][3]; 930 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 931 gl_feedback_vertex( ctx, 932 ctx->Current.RasterPos, 933 color, ctx->Current.Index, texcoord ); 934 } 935 } 936 else if (ctx->RenderMode==GL_SELECT) { 937 if (ctx->Current.RasterPosValid) { 938 gl_update_hitflag( ctx, ctx->Current.RasterPos[2] ); 939 } 940 } 941} 942 943