3e030ede61a5f6692a7a0f0a68f9b419788cedd6
[mesa.git] / src / mesa / main / drawpix.c
1 /* $Id: drawpix.c,v 1.43 2000/10/30 16:32:43 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 "colormac.h"
33 #include "context.h"
34 #include "convolve.h"
35 #include "drawpix.h"
36 #include "feedback.h"
37 #include "image.h"
38 #include "macros.h"
39 #include "mem.h"
40 #include "mmath.h"
41 #include "pixel.h"
42 #include "pixeltex.h"
43 #include "span.h"
44 #include "state.h"
45 #include "stencil.h"
46 #include "texture.h"
47 #include "types.h"
48 #include "zoom.h"
49 #endif
50
51
52
53 /*
54 * Given the dest position, size and skipPixels and skipRows values
55 * for a glDrawPixels command, perform clipping of the image bounds
56 * so the result lies withing the context's buffer bounds.
57 * Return: GL_TRUE if image is ready for drawing
58 * GL_FALSE if image was completely clipped away (draw nothing)
59 */
60 GLboolean
61 _mesa_clip_pixelrect(const GLcontext *ctx,
62 GLint *destX, GLint *destY,
63 GLsizei *width, GLsizei *height,
64 GLint *skipPixels, GLint *skipRows)
65 {
66 const GLframebuffer *buffer = ctx->DrawBuffer;
67
68 /* left clipping */
69 if (*destX < buffer->Xmin) {
70 *skipPixels += (buffer->Xmin - *destX);
71 *width -= (buffer->Xmin - *destX);
72 *destX = buffer->Xmin;
73 }
74 /* right clipping */
75 if (*destX + *width > buffer->Xmax)
76 *width -= (*destX + *width - buffer->Xmax);
77
78 if (*width <= 0)
79 return GL_FALSE;
80
81 /* bottom clipping */
82 if (*destY < buffer->Ymin) {
83 *skipRows += (buffer->Ymin - *destY);
84 *height -= (buffer->Ymin - *destY);
85 *destY = buffer->Ymin;
86 }
87 /* top clipping */
88 if (*destY + *height > buffer->Ymax)
89 *height -= (*destY + *height - buffer->Ymax);
90
91 if (*height <= 0)
92 return GL_TRUE;
93
94 return GL_TRUE;
95 }
96
97
98
99 /*
100 * Try to do a fast and simple RGB(a) glDrawPixels.
101 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
102 */
103 static GLboolean
104 fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
105 GLsizei width, GLsizei height,
106 GLenum format, GLenum type, const GLvoid *pixels)
107 {
108 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
109 GLchan rgb[MAX_WIDTH][3];
110 GLchan rgba[MAX_WIDTH][4];
111
112 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels",
113 GL_FALSE);
114
115
116 if (!ctx->Current.RasterPosValid) {
117 return GL_TRUE; /* no-op */
118 }
119
120 if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
121 && ctx->Texture.ReallyEnabled == 0
122 && unpack->Alignment == 1
123 && !unpack->SwapBytes
124 && !unpack->LsbFirst) {
125
126 GLint destX = x;
127 GLint destY = y;
128 GLint drawWidth = width; /* actual width drawn */
129 GLint drawHeight = height; /* actual height drawn */
130 GLint skipPixels = unpack->SkipPixels;
131 GLint skipRows = unpack->SkipRows;
132 GLint rowLength;
133 GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */
134 GLint zoomY0 = 0;
135
136 if (unpack->RowLength > 0)
137 rowLength = unpack->RowLength;
138 else
139 rowLength = width;
140
141 /* If we're not using pixel zoom then do all clipping calculations
142 * now. Otherwise, we'll let the gl_write_zoomed_*_span() functions
143 * handle the clipping.
144 */
145 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
146 /* horizontal clipping */
147 if (destX < ctx->DrawBuffer->Xmin) {
148 skipPixels += (ctx->DrawBuffer->Xmin - destX);
149 drawWidth -= (ctx->DrawBuffer->Xmin - destX);
150 destX = ctx->DrawBuffer->Xmin;
151 }
152 if (destX + drawWidth > ctx->DrawBuffer->Xmax)
153 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
154 if (drawWidth <= 0)
155 return GL_TRUE;
156
157 /* vertical clipping */
158 if (destY < ctx->DrawBuffer->Ymin) {
159 skipRows += (ctx->DrawBuffer->Ymin - destY);
160 drawHeight -= (ctx->DrawBuffer->Ymin - destY);
161 destY = ctx->DrawBuffer->Ymin;
162 }
163 if (destY + drawHeight > ctx->DrawBuffer->Ymax)
164 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax);
165 if (drawHeight <= 0)
166 return GL_TRUE;
167 }
168 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
169 /* upside-down image */
170 /* horizontal clipping */
171 if (destX < ctx->DrawBuffer->Xmin) {
172 skipPixels += (ctx->DrawBuffer->Xmin - destX);
173 drawWidth -= (ctx->DrawBuffer->Xmin - destX);
174 destX = ctx->DrawBuffer->Xmin;
175 }
176 if (destX + drawWidth > ctx->DrawBuffer->Xmax)
177 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
178 if (drawWidth <= 0)
179 return GL_TRUE;
180
181 /* vertical clipping */
182 if (destY > ctx->DrawBuffer->Ymax) {
183 skipRows += (destY - ctx->DrawBuffer->Ymax);
184 drawHeight -= (destY - ctx->DrawBuffer->Ymax);
185 destY = ctx->DrawBuffer->Ymax;
186 }
187 if (destY - drawHeight < ctx->DrawBuffer->Ymin)
188 drawHeight -= (ctx->DrawBuffer->Ymin - (destY - drawHeight));
189 if (drawHeight <= 0)
190 return GL_TRUE;
191 }
192 else {
193 /* setup array of fragment Z value to pass to zoom function */
194 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
195 GLint i;
196 ASSERT(drawWidth < MAX_WIDTH);
197 for (i=0; i<drawWidth; i++)
198 zSpan[i] = z;
199
200 /* save Y value of first row */
201 zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
202 }
203
204
205 /*
206 * Ready to draw!
207 * The window region at (destX, destY) of size (drawWidth, drawHeight)
208 * will be written to.
209 * We'll take pixel data from buffer pointed to by "pixels" but we'll
210 * skip "skipRows" rows and skip "skipPixels" pixels/row.
211 */
212
213 if (format == GL_RGBA && type == CHAN_TYPE
214 && ctx->ImageTransferState==0) {
215 if (ctx->Visual.RGBAflag) {
216 GLchan *src = (GLchan *) pixels
217 + (skipRows * rowLength + skipPixels) * 4;
218 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
219 /* no zooming */
220 GLint row;
221 for (row=0; row<drawHeight; row++) {
222 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
223 (void *) src, NULL);
224 src += rowLength * 4;
225 destY++;
226 }
227 }
228 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
229 /* upside-down */
230 GLint row;
231 for (row=0; row<drawHeight; row++) {
232 destY--;
233 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
234 (void *) src, NULL);
235 src += rowLength * 4;
236 }
237 }
238 else {
239 /* with zooming */
240 GLint row;
241 for (row=0; row<drawHeight; row++) {
242 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
243 zSpan, 0, (void *) src, zoomY0);
244 src += rowLength * 4;
245 destY++;
246 }
247 }
248 }
249 return GL_TRUE;
250 }
251 else if (format == GL_RGB && type == CHAN_TYPE
252 && ctx->ImageTransferState == 0) {
253 if (ctx->Visual.RGBAflag) {
254 GLchan *src = (GLchan *) pixels
255 + (skipRows * rowLength + skipPixels) * 3;
256 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
257 GLint row;
258 for (row=0; row<drawHeight; row++) {
259 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
260 (void *) src, NULL);
261 src += rowLength * 3;
262 destY++;
263 }
264 }
265 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
266 /* upside-down */
267 GLint row;
268 for (row=0; row<drawHeight; row++) {
269 destY--;
270 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
271 (void *) src, NULL);
272 src += rowLength * 3;
273 }
274 }
275 else {
276 /* with zooming */
277 GLint row;
278 for (row=0; row<drawHeight; row++) {
279 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
280 zSpan, 0, (void *) src, zoomY0);
281 src += rowLength * 3;
282 destY++;
283 }
284 }
285 }
286 return GL_TRUE;
287 }
288 else if (format == GL_LUMINANCE && type == CHAN_TYPE
289 && ctx->ImageTransferState==0) {
290 if (ctx->Visual.RGBAflag) {
291 GLchan *src = (GLchan *) pixels
292 + (skipRows * rowLength + skipPixels);
293 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
294 /* no zooming */
295 GLint row;
296 ASSERT(drawWidth < MAX_WIDTH);
297 for (row=0; row<drawHeight; row++) {
298 GLint i;
299 for (i=0;i<drawWidth;i++) {
300 rgb[i][0] = src[i];
301 rgb[i][1] = src[i];
302 rgb[i][2] = src[i];
303 }
304 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
305 (void *) rgb, NULL);
306 src += rowLength;
307 destY++;
308 }
309 }
310 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
311 /* upside-down */
312 GLint row;
313 ASSERT(drawWidth < MAX_WIDTH);
314 for (row=0; row<drawHeight; row++) {
315 GLint i;
316 for (i=0;i<drawWidth;i++) {
317 rgb[i][0] = src[i];
318 rgb[i][1] = src[i];
319 rgb[i][2] = src[i];
320 }
321 destY--;
322 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
323 (void *) rgb, NULL);
324 src += rowLength;
325 }
326 }
327 else {
328 /* with zooming */
329 GLint row;
330 ASSERT(drawWidth < MAX_WIDTH);
331 for (row=0; row<drawHeight; row++) {
332 GLint i;
333 for (i=0;i<drawWidth;i++) {
334 rgb[i][0] = src[i];
335 rgb[i][1] = src[i];
336 rgb[i][2] = src[i];
337 }
338 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
339 zSpan, 0, (void *) rgb, zoomY0);
340 src += rowLength;
341 destY++;
342 }
343 }
344 }
345 return GL_TRUE;
346 }
347 else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
348 && ctx->ImageTransferState == 0) {
349 if (ctx->Visual.RGBAflag) {
350 GLchan *src = (GLchan *) pixels
351 + (skipRows * rowLength + skipPixels)*2;
352 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
353 /* no zooming */
354 GLint row;
355 ASSERT(drawWidth < MAX_WIDTH);
356 for (row=0; row<drawHeight; row++) {
357 GLint i;
358 GLchan *ptr = src;
359 for (i=0;i<drawWidth;i++) {
360 rgba[i][0] = *ptr;
361 rgba[i][1] = *ptr;
362 rgba[i][2] = *ptr++;
363 rgba[i][3] = *ptr++;
364 }
365 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
366 (void *) rgba, NULL);
367 src += rowLength*2;
368 destY++;
369 }
370 }
371 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
372 /* upside-down */
373 GLint row;
374 ASSERT(drawWidth < MAX_WIDTH);
375 for (row=0; row<drawHeight; row++) {
376 GLint i;
377 GLchan *ptr = src;
378 for (i=0;i<drawWidth;i++) {
379 rgba[i][0] = *ptr;
380 rgba[i][1] = *ptr;
381 rgba[i][2] = *ptr++;
382 rgba[i][3] = *ptr++;
383 }
384 destY--;
385 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
386 (void *) rgba, NULL);
387 src += rowLength*2;
388 }
389 }
390 else {
391 /* with zooming */
392 GLint row;
393 ASSERT(drawWidth < MAX_WIDTH);
394 for (row=0; row<drawHeight; row++) {
395 GLchan *ptr = src;
396 GLint i;
397 for (i=0;i<drawWidth;i++) {
398 rgba[i][0] = *ptr;
399 rgba[i][1] = *ptr;
400 rgba[i][2] = *ptr++;
401 rgba[i][3] = *ptr++;
402 }
403 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
404 zSpan, 0, (void *) rgba, zoomY0);
405 src += rowLength*2;
406 destY++;
407 }
408 }
409 }
410 return GL_TRUE;
411 }
412 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
413 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
414 if (ctx->Visual.RGBAflag) {
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 GLchan (*)[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 GLchan (*)[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, 0, (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, 0, indexes, desty);
525 }
526 else {
527 gl_write_index_span(ctx, drawWidth, x, y, zspan, 0, 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 GLchan 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 = FLOAT_TO_CHAN(ctx->Current.RasterColor[0]);
618 GLint g = FLOAT_TO_CHAN(ctx->Current.RasterColor[1]);
619 GLint b = FLOAT_TO_CHAN(ctx->Current.RasterColor[2]);
620 GLint a = FLOAT_TO_CHAN(ctx->Current.RasterColor[3]);
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, 0, 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, 0, 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, 0,
672 (const GLchan (*)[4]) rgba, desty);
673 }
674 else {
675 gl_write_rgba_span(ctx, width, x, y, zspan, 0, rgba, GL_BITMAP);
676 }
677 }
678 else {
679 if (zoom) {
680 gl_write_zoomed_index_span(ctx, width, x, y, zspan, 0,
681 ispan, GL_BITMAP);
682 }
683 else {
684 gl_write_index_span(ctx, width, x, y, zspan, 0,
685 ispan, GL_BITMAP);
686 }
687 }
688
689 }
690 }
691 }
692
693
694 /*
695 * Do glDrawPixels of RGBA pixels.
696 */
697 static void
698 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
699 GLsizei width, GLsizei height,
700 GLenum format, GLenum type, const GLvoid *pixels )
701 {
702 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
703 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
704 const GLint desty = y;
705 GLdepth zspan[MAX_WIDTH];
706 GLboolean quickDraw;
707 GLfloat *convImage = NULL;
708 GLuint transferOps = ctx->ImageTransferState;
709
710 if (!_mesa_is_legal_format_and_type(format, type)) {
711 gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
712 return;
713 }
714
715 /* Try an optimized glDrawPixels first */
716 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
717 return;
718
719 /* Fragment depth values */
720 if (ctx->Depth.Test || ctx->Fog.Enabled) {
721 /* fill in array of z values */
722 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
723 GLint i;
724 for (i=0;i<width;i++) {
725 zspan[i] = z;
726 }
727 }
728
729
730 if (ctx->RasterMask == 0 && !zoom && x >= 0 && y >= 0
731 && x + width <= ctx->DrawBuffer->Width
732 && y + height <= ctx->DrawBuffer->Height) {
733 quickDraw = GL_TRUE;
734 }
735 else {
736 quickDraw = GL_FALSE;
737 }
738
739 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
740 /* Convolution has to be handled specially. We'll create an
741 * intermediate image, applying all pixel transfer operations
742 * up to convolution. Then we'll convolve the image. Then
743 * we'll proceed with the rest of the transfer operations and
744 * rasterize the image.
745 */
746 GLint row;
747 GLfloat *dest, *tmpImage;
748
749 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
750 if (!tmpImage) {
751 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
752 return;
753 }
754 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
755 if (!convImage) {
756 FREE(tmpImage);
757 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
758 return;
759 }
760
761 /* Unpack the image and apply transfer ops up to convolution */
762 dest = tmpImage;
763 for (row = 0; row < height; row++) {
764 const GLvoid *source = _mesa_image_address(unpack,
765 pixels, width, height, format, type, 0, row, 0);
766 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest,
767 format, type, source, unpack,
768 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
769 GL_FALSE);
770 dest += width * 4;
771 }
772
773 /* do convolution */
774 if (ctx->Pixel.Convolution2DEnabled) {
775 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
776 }
777 else {
778 ASSERT(ctx->Pixel.Separable2DEnabled);
779 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
780 }
781 FREE(tmpImage);
782
783 /* continue transfer ops and draw the convolved image */
784 unpack = &_mesa_native_packing;
785 pixels = convImage;
786 format = GL_RGBA;
787 type = GL_FLOAT;
788 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
789 }
790
791 /*
792 * General solution
793 */
794 {
795 GLchan rgba[MAX_WIDTH][4];
796 GLint row;
797 if (width > MAX_WIDTH)
798 width = MAX_WIDTH;
799 for (row = 0; row < height; row++, y++) {
800 const GLvoid *source = _mesa_image_address(unpack,
801 pixels, width, height, format, type, 0, row, 0);
802 _mesa_unpack_chan_color_span(ctx, width, GL_RGBA, (void*) rgba,
803 format, type, source, unpack,
804 transferOps);
805 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
806 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
807 continue;
808
809 if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
810 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
811 GLchan primary_rgba[MAX_WIDTH][4];
812 GLuint unit;
813 /* XXX not sure how multitexture is supposed to work here */
814
815 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
816
817 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
818 if (ctx->Texture.Unit[unit].ReallyEnabled) {
819 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[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
827 if (quickDraw) {
828 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
829 (CONST GLchan (*)[]) rgba, NULL);
830 }
831 else if (zoom) {
832 gl_write_zoomed_rgba_span( ctx, width, x, y, zspan, 0,
833 (CONST GLchan (*)[]) rgba, desty );
834 }
835 else {
836 gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, 0,
837 rgba, GL_BITMAP);
838 }
839 }
840 }
841
842 if (convImage) {
843 FREE(convImage);
844 }
845 }
846
847
848
849 /*
850 * Execute glDrawPixels
851 */
852 void
853 _mesa_DrawPixels( GLsizei width, GLsizei height,
854 GLenum format, GLenum type, const GLvoid *pixels )
855 {
856 GET_CURRENT_CONTEXT(ctx);
857 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
858
859 if (ctx->RenderMode==GL_RENDER) {
860 GLint x, y;
861 if (!pixels || !ctx->Current.RasterPosValid) {
862 return;
863 }
864
865 if (ctx->NewState) {
866 gl_update_state(ctx);
867 }
868
869 x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
870 y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
871
872 ctx->OcclusionResult = GL_TRUE;
873
874 /* see if device driver can do the drawpix */
875 if (ctx->Driver.DrawPixels
876 && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
877 &ctx->Unpack, pixels)) {
878 return;
879 }
880
881 RENDER_START(ctx);
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 }
911 RENDER_FINISH(ctx);
912 }
913 else if (ctx->RenderMode==GL_FEEDBACK) {
914 if (ctx->Current.RasterPosValid) {
915 GLfloat color[4];
916 GLfloat texcoord[4], invq;
917 color[0] = CHAN_TO_FLOAT(ctx->Current.Color[0]);
918 color[1] = CHAN_TO_FLOAT(ctx->Current.Color[1]);
919 color[2] = CHAN_TO_FLOAT(ctx->Current.Color[2]);
920 color[3] = CHAN_TO_FLOAT(ctx->Current.Color[3]);
921 invq = 1.0F / ctx->Current.Texcoord[0][3];
922 texcoord[0] = ctx->Current.Texcoord[0][0] * invq;
923 texcoord[1] = ctx->Current.Texcoord[0][1] * invq;
924 texcoord[2] = ctx->Current.Texcoord[0][2] * invq;
925 texcoord[3] = ctx->Current.Texcoord[0][3];
926 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
927 gl_feedback_vertex( ctx,
928 ctx->Current.RasterPos,
929 color, ctx->Current.Index, texcoord );
930 }
931 }
932 else if (ctx->RenderMode==GL_SELECT) {
933 if (ctx->Current.RasterPosValid) {
934 gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
935 }
936 }
937 }
938