drawpix.c revision 48c6a6ecd2b94d73317f1579193d98101566217a
1/* $Id: drawpix.c,v 1.33 2000/09/08 21:28:04 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 /* Try an optimized glDrawPixels first */ 717 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels)) 718 return; 719 720 /* Fragment depth values */ 721 if (ctx->Depth.Test || ctx->Fog.Enabled) { 722 /* fill in array of z values */ 723 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF); 724 GLint i; 725 for (i=0;i<width;i++) { 726 zspan[i] = z; 727 } 728 } 729 730 731 if (ctx->RasterMask == 0 && !zoom && x >= 0 && y >= 0 732 && x + width <= ctx->DrawBuffer->Width 733 && y + height <= ctx->DrawBuffer->Height) { 734 quickDraw = GL_TRUE; 735 } 736 else { 737 quickDraw = GL_FALSE; 738 } 739 740 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { 741 /* Convolution has to be handled specially. We'll create an 742 * intermediate image, applying all pixel transfer operations 743 * up to convolution. Then we'll convolve the image. Then 744 * we'll proceed with the rest of the transfer operations and 745 * rasterize the image. 746 */ 747 GLint row; 748 GLfloat *dest, *tmpImage; 749 750 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 751 if (!tmpImage) { 752 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 753 return; 754 } 755 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); 756 if (!convImage) { 757 FREE(tmpImage); 758 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); 759 return; 760 } 761 762 /* Unpack the image and apply transfer ops up to convolution */ 763 dest = tmpImage; 764 for (row = 0; row < height; row++) { 765 const GLvoid *source = _mesa_image_address(unpack, 766 pixels, width, height, format, type, 0, row, 0); 767 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest, 768 format, type, source, unpack, 769 transferOps & IMAGE_PRE_CONVOLUTION_BITS, 770 GL_FALSE); 771 dest += width * 4; 772 } 773 774 /* do convolution */ 775 if (ctx->Pixel.Convolution2DEnabled) { 776 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); 777 } 778 else { 779 ASSERT(ctx->Pixel.Separable2DEnabled); 780 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); 781 } 782 FREE(tmpImage); 783 784 /* continue transfer ops and draw the convolved image */ 785 unpack = &_mesa_native_packing; 786 pixels = convImage; 787 format = GL_RGBA; 788 type = GL_FLOAT; 789 transferOps &= IMAGE_POST_CONVOLUTION_BITS; 790 } 791 792 /* 793 * General solution 794 */ 795 { 796 GLubyte rgba[MAX_WIDTH][4]; 797 GLint row; 798 if (width > MAX_WIDTH) 799 width = MAX_WIDTH; 800 for (row = 0; row < height; row++, y++) { 801 const GLvoid *source = _mesa_image_address(unpack, 802 pixels, width, height, format, type, 0, row, 0); 803 _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba, 804 format, type, source, unpack, 805 transferOps); 806 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) || 807 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink)) 808 continue; 809 810 if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) { 811 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH]; 812 GLubyte primary_rgba[MAX_WIDTH][4]; 813 GLuint unit; 814 /* XXX not sure how multitexture is supposed to work here */ 815 816 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLubyte)); 817 818 for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) { 819 _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba, 820 s, t, r, q); 821 gl_texture_pixels(ctx, unit, width, s, t, r, NULL, 822 primary_rgba, rgba); 823 } 824 } 825 826 if (quickDraw) { 827 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y, 828 (CONST GLubyte (*)[]) rgba, NULL); 829 } 830 else if (zoom) { 831 gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 832 (CONST GLubyte (*)[]) rgba, desty ); 833 } 834 else { 835 gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP); 836 } 837 } 838 } 839 840 if (convImage) { 841 FREE(convImage); 842 } 843} 844 845 846 847/* 848 * Execute glDrawPixels 849 */ 850void 851_mesa_DrawPixels( GLsizei width, GLsizei height, 852 GLenum format, GLenum type, const GLvoid *pixels ) 853{ 854 GET_CURRENT_CONTEXT(ctx); 855 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels"); 856 857 if (ctx->RenderMode==GL_RENDER) { 858 GLint x, y; 859 if (!pixels || !ctx->Current.RasterPosValid) { 860 return; 861 } 862 863 if (ctx->NewState) { 864 gl_update_state(ctx); 865 } 866 867 if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE) 868 _mesa_update_image_transfer_state(ctx); 869 870 x = (GLint) (ctx->Current.RasterPos[0] + 0.5F); 871 y = (GLint) (ctx->Current.RasterPos[1] + 0.5F); 872 873 ctx->OcclusionResult = GL_TRUE; 874 875 /* see if device driver can do the drawpix */ 876 if (ctx->Driver.DrawPixels 877 && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type, 878 &ctx->Unpack, pixels)) { 879 return; 880 } 881 882 switch (format) { 883 case GL_STENCIL_INDEX: 884 draw_stencil_pixels( ctx, x, y, width, height, type, pixels ); 885 break; 886 case GL_DEPTH_COMPONENT: 887 draw_depth_pixels( ctx, x, y, width, height, type, pixels ); 888 break; 889 case GL_COLOR_INDEX: 890 if (ctx->Visual->RGBAflag) 891 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels); 892 else 893 draw_index_pixels(ctx, x, y, width, height, type, pixels); 894 break; 895 case GL_RED: 896 case GL_GREEN: 897 case GL_BLUE: 898 case GL_ALPHA: 899 case GL_LUMINANCE: 900 case GL_LUMINANCE_ALPHA: 901 case GL_RGB: 902 case GL_BGR: 903 case GL_RGBA: 904 case GL_BGRA: 905 case GL_ABGR_EXT: 906 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels); 907 break; 908 default: 909 gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" ); 910 return; 911 } 912 } 913 else if (ctx->RenderMode==GL_FEEDBACK) { 914 if (ctx->Current.RasterPosValid) { 915 GLfloat color[4]; 916 GLfloat texcoord[4], invq; 917 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor); 918 invq = 1.0F / ctx->Current.Texcoord[0][3]; 919 texcoord[0] = ctx->Current.Texcoord[0][0] * invq; 920 texcoord[1] = ctx->Current.Texcoord[0][1] * invq; 921 texcoord[2] = ctx->Current.Texcoord[0][2] * invq; 922 texcoord[3] = ctx->Current.Texcoord[0][3]; 923 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN ); 924 gl_feedback_vertex( ctx, 925 ctx->Current.RasterPos, 926 color, ctx->Current.Index, texcoord ); 927 } 928 } 929 else if (ctx->RenderMode==GL_SELECT) { 930 if (ctx->Current.RasterPosValid) { 931 gl_update_hitflag( ctx, ctx->Current.RasterPos[2] ); 932 } 933 } 934} 935 936