drawing color-index image to RGB window was broken
[mesa.git] / src / mesa / main / drawpix.c
1 /* $Id: drawpix.c,v 1.37 2000/10/05 16:22:23 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 */
59 GLboolean
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 */
102 static GLboolean
103 fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
104 GLsizei width, GLsizei height,
105 GLenum format, GLenum type, const GLvoid *pixels)
106 {
107 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
108 GLubyte rgb[MAX_WIDTH][3];
109 GLubyte rgba[MAX_WIDTH][4];
110
111 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels",
112 GL_FALSE);
113
114
115 if (!ctx->Current.RasterPosValid) {
116 return GL_TRUE; /* no-op */
117 }
118
119 if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_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 gl_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->Visual.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 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
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==GL_UNSIGNED_BYTE
213 && ctx->ImageTransferState==0) {
214 if (ctx->Visual.RGBAflag) {
215 GLubyte *src = (GLubyte *) 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 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
222 (void *) 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 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
233 (void *) src, NULL);
234 src += rowLength * 4;
235 }
236 }
237 else {
238 /* with zooming */
239 GLint row;
240 for (row=0; row<drawHeight; row++) {
241 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
242 zSpan, (void *) src, zoomY0);
243 src += rowLength * 4;
244 destY++;
245 }
246 }
247 }
248 return GL_TRUE;
249 }
250 else if (format==GL_RGB && type==GL_UNSIGNED_BYTE
251 && ctx->ImageTransferState==0) {
252 if (ctx->Visual.RGBAflag) {
253 GLubyte *src = (GLubyte *) pixels
254 + (skipRows * rowLength + skipPixels) * 3;
255 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
256 GLint row;
257 for (row=0; row<drawHeight; row++) {
258 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
259 (void *) src, NULL);
260 src += rowLength * 3;
261 destY++;
262 }
263 }
264 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
265 /* upside-down */
266 GLint row;
267 for (row=0; row<drawHeight; row++) {
268 destY--;
269 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
270 (void *) src, NULL);
271 src += rowLength * 3;
272 }
273 }
274 else {
275 /* with zooming */
276 GLint row;
277 for (row=0; row<drawHeight; row++) {
278 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
279 zSpan, (void *) src, zoomY0);
280 src += rowLength * 3;
281 destY++;
282 }
283 }
284 }
285 return GL_TRUE;
286 }
287 else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE
288 && ctx->ImageTransferState==0) {
289 if (ctx->Visual.RGBAflag) {
290 GLubyte *src = (GLubyte *) pixels
291 + (skipRows * rowLength + skipPixels);
292 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
293 /* no zooming */
294 GLint row;
295 ASSERT(drawWidth < MAX_WIDTH);
296 for (row=0; row<drawHeight; row++) {
297 GLint i;
298 for (i=0;i<drawWidth;i++) {
299 rgb[i][0] = src[i];
300 rgb[i][1] = src[i];
301 rgb[i][2] = src[i];
302 }
303 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
304 (void *) rgb, NULL);
305 src += rowLength;
306 destY++;
307 }
308 }
309 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
310 /* upside-down */
311 GLint row;
312 ASSERT(drawWidth < MAX_WIDTH);
313 for (row=0; row<drawHeight; row++) {
314 GLint i;
315 for (i=0;i<drawWidth;i++) {
316 rgb[i][0] = src[i];
317 rgb[i][1] = src[i];
318 rgb[i][2] = src[i];
319 }
320 destY--;
321 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
322 (void *) rgb, NULL);
323 src += rowLength;
324 }
325 }
326 else {
327 /* with zooming */
328 GLint row;
329 ASSERT(drawWidth < MAX_WIDTH);
330 for (row=0; row<drawHeight; row++) {
331 GLint i;
332 for (i=0;i<drawWidth;i++) {
333 rgb[i][0] = src[i];
334 rgb[i][1] = src[i];
335 rgb[i][2] = src[i];
336 }
337 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
338 zSpan, (void *) rgb, zoomY0);
339 src += rowLength;
340 destY++;
341 }
342 }
343 }
344 return GL_TRUE;
345 }
346 else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE
347 && ctx->ImageTransferState==0) {
348 if (ctx->Visual.RGBAflag) {
349 GLubyte *src = (GLubyte *) pixels
350 + (skipRows * rowLength + skipPixels)*2;
351 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
352 /* no zooming */
353 GLint row;
354 ASSERT(drawWidth < MAX_WIDTH);
355 for (row=0; row<drawHeight; row++) {
356 GLint i;
357 GLubyte *ptr = src;
358 for (i=0;i<drawWidth;i++) {
359 rgba[i][0] = *ptr;
360 rgba[i][1] = *ptr;
361 rgba[i][2] = *ptr++;
362 rgba[i][3] = *ptr++;
363 }
364 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
365 (void *) rgba, NULL);
366 src += rowLength*2;
367 destY++;
368 }
369 }
370 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
371 /* upside-down */
372 GLint row;
373 ASSERT(drawWidth < MAX_WIDTH);
374 for (row=0; row<drawHeight; row++) {
375 GLint i;
376 GLubyte *ptr = src;
377 for (i=0;i<drawWidth;i++) {
378 rgba[i][0] = *ptr;
379 rgba[i][1] = *ptr;
380 rgba[i][2] = *ptr++;
381 rgba[i][3] = *ptr++;
382 }
383 destY--;
384 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
385 (void *) rgba, NULL);
386 src += rowLength*2;
387 }
388 }
389 else {
390 /* with zooming */
391 GLint row;
392 ASSERT(drawWidth < MAX_WIDTH);
393 for (row=0; row<drawHeight; row++) {
394 GLubyte *ptr = src;
395 GLint i;
396 for (i=0;i<drawWidth;i++) {
397 rgba[i][0] = *ptr;
398 rgba[i][1] = *ptr;
399 rgba[i][2] = *ptr++;
400 rgba[i][3] = *ptr++;
401 }
402 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
403 zSpan, (void *) rgba, zoomY0);
404 src += rowLength*2;
405 destY++;
406 }
407 }
408 }
409 return GL_TRUE;
410 }
411 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
412 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
413 if (ctx->Visual.RGBAflag
414 && ctx->ImageTransferState==IMAGE_MAP_COLOR_BIT) {
415 /* convert CI data to RGBA */
416 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
417 /* no zooming */
418 GLint row;
419 for (row=0; row<drawHeight; row++) {
420 ASSERT(drawWidth < MAX_WIDTH);
421 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
422 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
423 (const GLubyte (*)[4])rgba,
424 NULL);
425 src += rowLength;
426 destY++;
427 }
428 return GL_TRUE;
429 }
430 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
431 /* upside-down */
432 GLint row;
433 for (row=0; row<drawHeight; row++) {
434 ASSERT(drawWidth < MAX_WIDTH);
435 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
436 destY--;
437 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
438 (const GLubyte (*)[4])rgba,
439 NULL);
440 src += rowLength;
441 }
442 return GL_TRUE;
443 }
444 else {
445 /* with zooming */
446 GLint row;
447 for (row=0; row<drawHeight; row++) {
448 ASSERT(drawWidth < MAX_WIDTH);
449 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
450 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
451 zSpan, (void *) rgba, zoomY0);
452 src += rowLength;
453 destY++;
454 }
455 return GL_TRUE;
456 }
457 }
458 else if (ctx->ImageTransferState==0) {
459 /* write CI data to CI frame buffer */
460 GLint row;
461 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
462 /* no zooming */
463 for (row=0; row<drawHeight; row++) {
464 (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
465 src, NULL);
466 src += rowLength;
467 destY++;
468 }
469 return GL_TRUE;
470 }
471 else {
472 /* with zooming */
473 return GL_FALSE;
474 }
475 }
476 }
477 else {
478 /* can't handle this pixel format and/or data type here */
479 return GL_FALSE;
480 }
481 }
482
483 /* can't do a simple draw, have to use slow path */
484 return GL_FALSE;
485 }
486
487
488
489 /*
490 * Do glDrawPixels of index pixels.
491 */
492 static void
493 draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
494 GLsizei width, GLsizei height,
495 GLenum type, const GLvoid *pixels )
496 {
497 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
498 const GLint desty = y;
499 GLint row, drawWidth;
500 GLdepth zspan[MAX_WIDTH];
501
502 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
503
504 /* Fragment depth values */
505 if (ctx->Depth.Test || ctx->Fog.Enabled) {
506 GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
507 GLint i;
508 for (i = 0; i < drawWidth; i++) {
509 zspan[i] = zval;
510 }
511 }
512
513 /*
514 * General solution
515 */
516 for (row = 0; row < height; row++, y++) {
517 GLuint indexes[MAX_WIDTH];
518 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
519 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
520 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
521 type, source, &ctx->Unpack,
522 ctx->ImageTransferState);
523 if (zoom) {
524 gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty);
525 }
526 else {
527 gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP);
528 }
529 }
530 }
531
532
533
534 /*
535 * Do glDrawPixels of stencil image. The image datatype may either
536 * be GLubyte or GLbitmap.
537 */
538 static void
539 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
540 GLsizei width, GLsizei height,
541 GLenum type, const GLvoid *pixels )
542 {
543 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
544 const GLint desty = y;
545 GLint row, drawWidth;
546
547 if (type != GL_BYTE &&
548 type != GL_UNSIGNED_BYTE &&
549 type != GL_SHORT &&
550 type != GL_UNSIGNED_SHORT &&
551 type != GL_INT &&
552 type != GL_UNSIGNED_INT &&
553 type != GL_FLOAT &&
554 type != GL_BITMAP) {
555 gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
556 return;
557 }
558
559 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
560
561 for (row = 0; row < height; row++, y++) {
562 GLstencil values[MAX_WIDTH];
563 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
564 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
565 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
566 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
567 _mesa_unpack_index_span(ctx, drawWidth, destType, values,
568 type, source, &ctx->Unpack,
569 ctx->ImageTransferState);
570 if (ctx->ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
571 _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
572 }
573 if (ctx->Pixel.MapStencilFlag) {
574 _mesa_map_stencil( ctx, drawWidth, values );
575 }
576
577 if (zoom) {
578 gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
579 values, desty );
580 }
581 else {
582 _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
583 }
584 }
585 }
586
587
588
589 /*
590 * Do a glDrawPixels of depth values.
591 */
592 static void
593 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
594 GLsizei width, GLsizei height,
595 GLenum type, const GLvoid *pixels )
596 {
597 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
598 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
599 const GLint desty = y;
600 GLubyte rgba[MAX_WIDTH][4];
601 GLuint ispan[MAX_WIDTH];
602 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
603
604 if (type != GL_BYTE
605 && type != GL_UNSIGNED_BYTE
606 && type != GL_SHORT
607 && type != GL_UNSIGNED_SHORT
608 && type != GL_INT
609 && type != GL_UNSIGNED_INT
610 && type != GL_FLOAT) {
611 gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
612 return;
613 }
614
615 /* Colors or indexes */
616 if (ctx->Visual.RGBAflag) {
617 GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
618 GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
619 GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
620 GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
621 GLint i;
622 for (i = 0; i < drawWidth; i++) {
623 rgba[i][RCOMP] = r;
624 rgba[i][GCOMP] = g;
625 rgba[i][BCOMP] = b;
626 rgba[i][ACOMP] = a;
627 }
628 }
629 else {
630 GLint i;
631 for (i = 0; i < drawWidth; i++) {
632 ispan[i] = ctx->Current.RasterIndex;
633 }
634 }
635
636 if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
637 && !bias_or_scale && !zoom && ctx->Visual.RGBAflag) {
638 /* Special case: directly write 16-bit depth values */
639 GLint row;
640 for (row = 0; row < height; row++, y++) {
641 GLdepth zspan[MAX_WIDTH];
642 const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
643 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
644 GLint i;
645 for (i = 0; i < width; i++)
646 zspan[i] = zptr[i];
647 gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
648 }
649 }
650 else if (type==GL_UNSIGNED_INT && ctx->Visual.DepthBits == 32
651 && !bias_or_scale && !zoom && ctx->Visual.RGBAflag) {
652 /* Special case: directly write 32-bit depth values */
653 GLint row;
654 for (row = 0; row < height; row++, y++) {
655 const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
656 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
657 gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
658 }
659 }
660 else {
661 /* General case */
662 GLint row;
663 for (row = 0; row < height; row++, y++) {
664 GLdepth zspan[MAX_WIDTH];
665 const GLvoid *src = _mesa_image_address(&ctx->Unpack,
666 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
667 _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
668 &ctx->Unpack, ctx->ImageTransferState );
669 if (ctx->Visual.RGBAflag) {
670 if (zoom) {
671 gl_write_zoomed_rgba_span(ctx, width, x, y, zspan,
672 (const GLubyte (*)[4])rgba, desty);
673 }
674 else {
675 gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
676 }
677 }
678 else {
679 if (zoom) {
680 gl_write_zoomed_index_span(ctx, width, x, y, zspan,
681 ispan, GL_BITMAP);
682 }
683 else {
684 gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
685 }
686 }
687
688 }
689 }
690 }
691
692
693 /*
694 * Do glDrawPixels of RGBA pixels.
695 */
696 static void
697 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
698 GLsizei width, GLsizei height,
699 GLenum format, GLenum type, const GLvoid *pixels )
700 {
701 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
702 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
703 const GLint desty = y;
704 GLdepth zspan[MAX_WIDTH];
705 GLboolean quickDraw;
706 GLfloat *convImage = NULL;
707 GLuint transferOps = ctx->ImageTransferState;
708
709 if (!_mesa_is_legal_format_and_type(format, type)) {
710 gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
711 return;
712 }
713
714 /* Try an optimized glDrawPixels first */
715 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
716 return;
717
718 /* Fragment depth values */
719 if (ctx->Depth.Test || ctx->Fog.Enabled) {
720 /* fill in array of z values */
721 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
722 GLint i;
723 for (i=0;i<width;i++) {
724 zspan[i] = z;
725 }
726 }
727
728
729 if (ctx->RasterMask == 0 && !zoom && x >= 0 && y >= 0
730 && x + width <= ctx->DrawBuffer->Width
731 && y + height <= ctx->DrawBuffer->Height) {
732 quickDraw = GL_TRUE;
733 }
734 else {
735 quickDraw = GL_FALSE;
736 }
737
738 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
739 /* Convolution has to be handled specially. We'll create an
740 * intermediate image, applying all pixel transfer operations
741 * up to convolution. Then we'll convolve the image. Then
742 * we'll proceed with the rest of the transfer operations and
743 * rasterize the image.
744 */
745 GLint row;
746 GLfloat *dest, *tmpImage;
747
748 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
749 if (!tmpImage) {
750 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
751 return;
752 }
753 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
754 if (!convImage) {
755 FREE(tmpImage);
756 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
757 return;
758 }
759
760 /* Unpack the image and apply transfer ops up to convolution */
761 dest = tmpImage;
762 for (row = 0; row < height; row++) {
763 const GLvoid *source = _mesa_image_address(unpack,
764 pixels, width, height, format, type, 0, row, 0);
765 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest,
766 format, type, source, unpack,
767 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
768 GL_FALSE);
769 dest += width * 4;
770 }
771
772 /* do convolution */
773 if (ctx->Pixel.Convolution2DEnabled) {
774 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
775 }
776 else {
777 ASSERT(ctx->Pixel.Separable2DEnabled);
778 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
779 }
780 FREE(tmpImage);
781
782 /* continue transfer ops and draw the convolved image */
783 unpack = &_mesa_native_packing;
784 pixels = convImage;
785 format = GL_RGBA;
786 type = GL_FLOAT;
787 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
788 }
789
790 /*
791 * General solution
792 */
793 {
794 GLubyte rgba[MAX_WIDTH][4];
795 GLint row;
796 if (width > MAX_WIDTH)
797 width = MAX_WIDTH;
798 for (row = 0; row < height; row++, y++) {
799 const GLvoid *source = _mesa_image_address(unpack,
800 pixels, width, height, format, type, 0, row, 0);
801 _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
802 format, type, source, unpack,
803 transferOps);
804 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
805 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
806 continue;
807
808 if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
809 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
810 GLubyte primary_rgba[MAX_WIDTH][4];
811 GLuint unit;
812 /* XXX not sure how multitexture is supposed to work here */
813
814 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLubyte));
815
816 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
817 if (ctx->Texture.Unit[unit].ReallyEnabled) {
818 _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
819 s, t, r, q);
820 gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
821 primary_rgba, rgba);
822 }
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 */
850 void
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