562db485b5381d3af86ad1b7965b3870c5ce40fd
[mesa.git] / src / mesa / main / drawpix.c
1 /* $Id: drawpix.c,v 1.30 2000/08/23 14:32:06 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 - 1);
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 - 1);
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 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;
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 - 1);
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 - 1);
176 if (drawHeight <= 0)
177 return GL_TRUE;
178
179 zoomY0 = 0; /* not used - silence compiler warning */
180 }
181 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
182 /* upside-down image */
183 /* horizontal clipping */
184 if (destX < ctx->DrawBuffer->Xmin) {
185 skipPixels += (ctx->DrawBuffer->Xmin - destX);
186 drawWidth -= (ctx->DrawBuffer->Xmin - destX);
187 destX = ctx->DrawBuffer->Xmin;
188 }
189 if (destX + drawWidth > ctx->DrawBuffer->Xmax)
190 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax - 1);
191 if (drawWidth <= 0)
192 return GL_TRUE;
193
194 /* vertical clipping */
195 if (destY > ctx->DrawBuffer->Ymax) {
196 skipRows += (destY - ctx->DrawBuffer->Ymax - 1);
197 drawHeight -= (destY - ctx->DrawBuffer->Ymax - 1);
198 destY = ctx->DrawBuffer->Ymax + 1;
199 }
200 if (destY - drawHeight < ctx->DrawBuffer->Ymin)
201 drawHeight -= (ctx->DrawBuffer->Ymin - (destY - drawHeight));
202 if (drawHeight <= 0)
203 return GL_TRUE;
204 }
205 else {
206 /* setup array of fragment Z value to pass to zoom function */
207 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
208 GLint i;
209 ASSERT(drawWidth < MAX_WIDTH);
210 for (i=0; i<drawWidth; i++)
211 zSpan[i] = z;
212
213 /* save Y value of first row */
214 zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
215 }
216
217
218 /*
219 * Ready to draw!
220 * The window region at (destX, destY) of size (drawWidth, drawHeight)
221 * will be written to.
222 * We'll take pixel data from buffer pointed to by "pixels" but we'll
223 * skip "skipRows" rows and skip "skipPixels" pixels/row.
224 */
225
226 if (format==GL_RGBA && type==GL_UNSIGNED_BYTE) {
227 if (ctx->Visual->RGBAflag) {
228 GLubyte *src = (GLubyte *) pixels
229 + (skipRows * rowLength + skipPixels) * 4;
230 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
231 /* no zooming */
232 GLint row;
233 for (row=0; row<drawHeight; row++) {
234 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
235 (void *) src, NULL);
236 src += rowLength * 4;
237 destY++;
238 }
239 }
240 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
241 /* upside-down */
242 GLint row;
243 for (row=0; row<drawHeight; row++) {
244 destY--;
245 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
246 (void *) src, NULL);
247 src += rowLength * 4;
248 }
249 }
250 else {
251 /* with zooming */
252 GLint row;
253 for (row=0; row<drawHeight; row++) {
254 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
255 zSpan, (void *) src, zoomY0);
256 src += rowLength * 4;
257 destY++;
258 }
259 }
260 }
261 return GL_TRUE;
262 }
263 else if (format==GL_RGB && type==GL_UNSIGNED_BYTE) {
264 if (ctx->Visual->RGBAflag) {
265 GLubyte *src = (GLubyte *) pixels
266 + (skipRows * rowLength + skipPixels) * 3;
267 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
268 GLint row;
269 for (row=0; row<drawHeight; row++) {
270 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
271 (void *) src, NULL);
272 src += rowLength * 3;
273 destY++;
274 }
275 }
276 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
277 /* upside-down */
278 GLint row;
279 for (row=0; row<drawHeight; row++) {
280 destY--;
281 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
282 (void *) src, NULL);
283 src += rowLength * 3;
284 }
285 }
286 else {
287 /* with zooming */
288 GLint row;
289 for (row=0; row<drawHeight; row++) {
290 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
291 zSpan, (void *) src, zoomY0);
292 src += rowLength * 3;
293 destY++;
294 }
295 }
296 }
297 return GL_TRUE;
298 }
299 else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE) {
300 if (ctx->Visual->RGBAflag) {
301 GLubyte *src = (GLubyte *) pixels
302 + (skipRows * rowLength + skipPixels);
303 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
304 /* no zooming */
305 GLint row;
306 ASSERT(drawWidth < MAX_WIDTH);
307 for (row=0; row<drawHeight; row++) {
308 GLint i;
309 for (i=0;i<drawWidth;i++) {
310 rgb[i][0] = src[i];
311 rgb[i][1] = src[i];
312 rgb[i][2] = src[i];
313 }
314 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
315 (void *) rgb, NULL);
316 src += rowLength;
317 destY++;
318 }
319 }
320 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
321 /* upside-down */
322 GLint row;
323 ASSERT(drawWidth < MAX_WIDTH);
324 for (row=0; row<drawHeight; row++) {
325 GLint i;
326 for (i=0;i<drawWidth;i++) {
327 rgb[i][0] = src[i];
328 rgb[i][1] = src[i];
329 rgb[i][2] = src[i];
330 }
331 destY--;
332 (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
333 (void *) rgb, NULL);
334 src += rowLength;
335 }
336 }
337 else {
338 /* with zooming */
339 GLint row;
340 ASSERT(drawWidth < MAX_WIDTH);
341 for (row=0; row<drawHeight; row++) {
342 GLint i;
343 for (i=0;i<drawWidth;i++) {
344 rgb[i][0] = src[i];
345 rgb[i][1] = src[i];
346 rgb[i][2] = src[i];
347 }
348 gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
349 zSpan, (void *) rgb, zoomY0);
350 src += rowLength;
351 destY++;
352 }
353 }
354 }
355 return GL_TRUE;
356 }
357 else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE) {
358 if (ctx->Visual->RGBAflag) {
359 GLubyte *src = (GLubyte *) pixels
360 + (skipRows * rowLength + skipPixels)*2;
361 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
362 /* no zooming */
363 GLint row;
364 ASSERT(drawWidth < MAX_WIDTH);
365 for (row=0; row<drawHeight; row++) {
366 GLint i;
367 GLubyte *ptr = src;
368 for (i=0;i<drawWidth;i++) {
369 rgba[i][0] = *ptr;
370 rgba[i][1] = *ptr;
371 rgba[i][2] = *ptr++;
372 rgba[i][3] = *ptr++;
373 }
374 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
375 (void *) rgba, NULL);
376 src += rowLength*2;
377 destY++;
378 }
379 }
380 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
381 /* upside-down */
382 GLint row;
383 ASSERT(drawWidth < MAX_WIDTH);
384 for (row=0; row<drawHeight; row++) {
385 GLint i;
386 GLubyte *ptr = src;
387 for (i=0;i<drawWidth;i++) {
388 rgba[i][0] = *ptr;
389 rgba[i][1] = *ptr;
390 rgba[i][2] = *ptr++;
391 rgba[i][3] = *ptr++;
392 }
393 destY--;
394 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
395 (void *) rgba, NULL);
396 src += rowLength*2;
397 }
398 }
399 else {
400 /* with zooming */
401 GLint row;
402 ASSERT(drawWidth < MAX_WIDTH);
403 for (row=0; row<drawHeight; row++) {
404 GLubyte *ptr = src;
405 GLint i;
406 for (i=0;i<drawWidth;i++) {
407 rgba[i][0] = *ptr;
408 rgba[i][1] = *ptr;
409 rgba[i][2] = *ptr++;
410 rgba[i][3] = *ptr++;
411 }
412 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
413 zSpan, (void *) rgba, zoomY0);
414 src += rowLength*2;
415 destY++;
416 }
417 }
418 }
419 return GL_TRUE;
420 }
421 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
422 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
423 if (ctx->Visual->RGBAflag) {
424 /* convert CI data to RGBA */
425 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
426 /* no zooming */
427 GLint row;
428 for (row=0; row<drawHeight; row++) {
429 ASSERT(drawWidth < MAX_WIDTH);
430 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
431 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
432 (const GLubyte (*)[4])rgba,
433 NULL);
434 src += rowLength;
435 destY++;
436 }
437 return GL_TRUE;
438 }
439 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
440 /* upside-down */
441 GLint row;
442 for (row=0; row<drawHeight; row++) {
443 ASSERT(drawWidth < MAX_WIDTH);
444 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
445 destY--;
446 (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
447 (const GLubyte (*)[4])rgba,
448 NULL);
449 src += rowLength;
450 }
451 return GL_TRUE;
452 }
453 else {
454 /* with zooming */
455 GLint row;
456 for (row=0; row<drawHeight; row++) {
457 ASSERT(drawWidth < MAX_WIDTH);
458 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
459 gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
460 zSpan, (void *) rgba, zoomY0);
461 src += rowLength;
462 destY++;
463 }
464 return GL_TRUE;
465 }
466 }
467 else {
468 /* write CI data to CI frame buffer */
469 GLint row;
470 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
471 /* no zooming */
472 for (row=0; row<drawHeight; row++) {
473 (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
474 src, NULL);
475 src += rowLength;
476 destY++;
477 }
478 return GL_TRUE;
479 }
480 else {
481 /* with zooming */
482 return GL_FALSE;
483 }
484 }
485 }
486 else {
487 /* can't handle this pixel format and/or data type here */
488 return GL_FALSE;
489 }
490 }
491
492 /* can't do a simple draw, have to use slow path */
493 return GL_FALSE;
494 }
495
496
497
498 /*
499 * Do glDrawPixels of index pixels.
500 */
501 static void
502 draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
503 GLsizei width, GLsizei height,
504 GLenum type, const GLvoid *pixels )
505 {
506 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
507 const GLint desty = y;
508 GLint row, drawWidth;
509 GLdepth zspan[MAX_WIDTH];
510
511 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
512
513 /* Fragment depth values */
514 if (ctx->Depth.Test || ctx->Fog.Enabled) {
515 GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
516 GLint i;
517 for (i = 0; i < drawWidth; i++) {
518 zspan[i] = zval;
519 }
520 }
521
522 /*
523 * General solution
524 */
525 for (row = 0; row < height; row++, y++) {
526 GLuint indexes[MAX_WIDTH];
527 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
528 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
529 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
530 type, source, &ctx->Unpack,
531 ctx->ImageTransferState);
532 if (zoom) {
533 gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty);
534 }
535 else {
536 gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP);
537 }
538 }
539 }
540
541
542
543 /*
544 * Do glDrawPixels of stencil image. The image datatype may either
545 * be GLubyte or GLbitmap.
546 */
547 static void
548 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
549 GLsizei width, GLsizei height,
550 GLenum type, const GLvoid *pixels )
551 {
552 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
553 const GLint desty = y;
554 GLint row, drawWidth;
555
556 if (type != GL_BYTE &&
557 type != GL_UNSIGNED_BYTE &&
558 type != GL_SHORT &&
559 type != GL_UNSIGNED_SHORT &&
560 type != GL_INT &&
561 type != GL_UNSIGNED_INT &&
562 type != GL_FLOAT &&
563 type != GL_BITMAP) {
564 gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
565 return;
566 }
567
568 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
569
570 for (row = 0; row < height; row++, y++) {
571 GLstencil values[MAX_WIDTH];
572 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
573 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
574 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
575 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
576 _mesa_unpack_index_span(ctx, drawWidth, destType, values,
577 type, source, &ctx->Unpack,
578 ctx->ImageTransferState);
579 if (ctx->ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
580 _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
581 }
582 if (ctx->Pixel.MapStencilFlag) {
583 _mesa_map_stencil( ctx, drawWidth, values );
584 }
585
586 if (zoom) {
587 gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
588 values, desty );
589 }
590 else {
591 _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
592 }
593 }
594 }
595
596
597
598 /*
599 * Do a glDrawPixels of depth values.
600 */
601 static void
602 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
603 GLsizei width, GLsizei height,
604 GLenum type, const GLvoid *pixels )
605 {
606 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
607 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
608 const GLint desty = y;
609 GLubyte rgba[MAX_WIDTH][4];
610 GLuint ispan[MAX_WIDTH];
611 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
612
613 if (type != GL_BYTE
614 && type != GL_UNSIGNED_BYTE
615 && type != GL_SHORT
616 && type != GL_UNSIGNED_SHORT
617 && type != GL_INT
618 && type != GL_UNSIGNED_INT
619 && type != GL_FLOAT) {
620 gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
621 return;
622 }
623
624 /* Colors or indexes */
625 if (ctx->Visual->RGBAflag) {
626 GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
627 GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
628 GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
629 GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
630 GLint i;
631 for (i = 0; i < drawWidth; i++) {
632 rgba[i][RCOMP] = r;
633 rgba[i][GCOMP] = g;
634 rgba[i][BCOMP] = b;
635 rgba[i][ACOMP] = a;
636 }
637 }
638 else {
639 GLint i;
640 for (i = 0; i < drawWidth; i++) {
641 ispan[i] = ctx->Current.RasterIndex;
642 }
643 }
644
645 if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
646 && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
647 /* Special case: directly write 16-bit depth values */
648 GLint row;
649 for (row = 0; row < height; row++, y++) {
650 GLdepth zspan[MAX_WIDTH];
651 const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
652 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
653 GLint i;
654 for (i = 0; i < width; i++)
655 zspan[i] = zptr[i];
656 gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
657 }
658 }
659 else if (type==GL_UNSIGNED_INT && ctx->Visual->DepthBits == 32
660 && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
661 /* Special case: directly write 32-bit depth values */
662 GLint row;
663 for (row = 0; row < height; row++, y++) {
664 const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
665 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
666 gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
667 }
668 }
669 else {
670 /* General case */
671 GLint row;
672 for (row = 0; row < height; row++, y++) {
673 GLdepth zspan[MAX_WIDTH];
674 const GLvoid *src = _mesa_image_address(&ctx->Unpack,
675 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
676 _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
677 &ctx->Unpack, ctx->ImageTransferState );
678 if (ctx->Visual->RGBAflag) {
679 if (zoom) {
680 gl_write_zoomed_rgba_span(ctx, width, x, y, zspan,
681 (const GLubyte (*)[4])rgba, desty);
682 }
683 else {
684 gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
685 }
686 }
687 else {
688 if (zoom) {
689 gl_write_zoomed_index_span(ctx, width, x, y, zspan,
690 ispan, GL_BITMAP);
691 }
692 else {
693 gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
694 }
695 }
696
697 }
698 }
699 }
700
701
702 /*
703 * Do glDrawPixels of RGBA pixels.
704 */
705 static void
706 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
707 GLsizei width, GLsizei height,
708 GLenum format, GLenum type, const GLvoid *pixels )
709 {
710 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
711 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
712 const GLint desty = y;
713 GLdepth zspan[MAX_WIDTH];
714 GLboolean quickDraw;
715 GLfloat *convImage = NULL;
716 GLuint transferOps = ctx->ImageTransferState;
717
718 /* Try an optimized glDrawPixels first */
719 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
720 return;
721
722 /* Fragment depth values */
723 if (ctx->Depth.Test || ctx->Fog.Enabled) {
724 /* fill in array of z values */
725 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
726 GLint i;
727 for (i=0;i<width;i++) {
728 zspan[i] = z;
729 }
730 }
731
732
733 if (ctx->RasterMask == 0 && !zoom && x >= 0 && y >= 0
734 && x + width <= ctx->DrawBuffer->Width
735 && y + height <= ctx->DrawBuffer->Height) {
736 quickDraw = GL_TRUE;
737 }
738 else {
739 quickDraw = GL_FALSE;
740 }
741
742 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
743 /* Convolution has to be handled specially. We'll create an
744 * intermediate image, applying all pixel transfer operations
745 * up to convolution. Then we'll convolve the image. Then
746 * we'll proceed with the rest of the transfer operations and
747 * rasterize the image.
748 */
749 const GLuint preConvTransferOps =
750 IMAGE_SCALE_BIAS_BIT |
751 IMAGE_SHIFT_OFFSET_BIT |
752 IMAGE_MAP_COLOR_BIT |
753 IMAGE_COLOR_TABLE_BIT;
754 const GLuint postConvTransferOps =
755 IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT |
756 IMAGE_COLOR_MATRIX_BIT |
757 IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT |
758 IMAGE_HISTOGRAM_BIT |
759 IMAGE_MIN_MAX_BIT;
760 GLint row;
761 GLfloat *dest, *tmpImage;
762
763 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
764 if (!tmpImage) {
765 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
766 return;
767 }
768 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
769 if (!convImage) {
770 FREE(tmpImage);
771 gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
772 return;
773 }
774
775 /* Unpack the image and apply transfer ops up to convolution */
776 dest = tmpImage;
777 for (row = 0; row < height; row++) {
778 const GLvoid *source = _mesa_image_address(unpack,
779 pixels, width, height, format, type, 0, row, 0);
780 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest,
781 format, type, source, unpack,
782 transferOps & preConvTransferOps,
783 GL_FALSE);
784 dest += width * 4;
785 }
786
787 /* do convolution */
788 if (ctx->Pixel.Convolution2DEnabled) {
789 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
790 }
791 else {
792 ASSERT(ctx->Pixel.Separable2DEnabled);
793 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
794 }
795 FREE(tmpImage);
796
797 /* continue transfer ops and draw the convolved image */
798 unpack = &_mesa_native_packing;
799 pixels = convImage;
800 format = GL_RGBA;
801 type = GL_FLOAT;
802 transferOps &= postConvTransferOps;
803 }
804
805 /*
806 * General solution
807 */
808 {
809 GLubyte rgba[MAX_WIDTH][4];
810 GLint row;
811 if (width > MAX_WIDTH)
812 width = MAX_WIDTH;
813 for (row = 0; row < height; row++, y++) {
814 const GLvoid *source = _mesa_image_address(unpack,
815 pixels, width, height, format, type, 0, row, 0);
816 _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
817 format, type, source, unpack,
818 transferOps);
819 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
820 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
821 continue;
822
823 if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
824 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
825 GLubyte primary_rgba[MAX_WIDTH][4];
826 GLuint unit;
827 /* XXX not sure how multitexture is supposed to work here */
828
829 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLubyte));
830
831 for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
832 _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
833 s, t, r, q);
834 gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
835 primary_rgba, rgba);
836 }
837 }
838
839 if (quickDraw) {
840 (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
841 (CONST GLubyte (*)[]) rgba, NULL);
842 }
843 else if (zoom) {
844 gl_write_zoomed_rgba_span( ctx, width, x, y, zspan,
845 (CONST GLubyte (*)[]) rgba, desty );
846 }
847 else {
848 gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP);
849 }
850 }
851 }
852
853 if (convImage) {
854 FREE(convImage);
855 }
856 }
857
858
859
860 /*
861 * Execute glDrawPixels
862 */
863 void
864 _mesa_DrawPixels( GLsizei width, GLsizei height,
865 GLenum format, GLenum type, const GLvoid *pixels )
866 {
867 GET_CURRENT_CONTEXT(ctx);
868 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
869
870 if (ctx->RenderMode==GL_RENDER) {
871 GLint x, y;
872 if (!pixels || !ctx->Current.RasterPosValid) {
873 return;
874 }
875
876 if (ctx->NewState) {
877 gl_update_state(ctx);
878 }
879
880 if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE)
881 _mesa_update_image_transfer_state(ctx);
882
883 x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
884 y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
885
886 ctx->OcclusionResult = GL_TRUE;
887
888 /* see if device driver can do the drawpix */
889 if (ctx->Driver.DrawPixels
890 && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
891 &ctx->Unpack, pixels)) {
892 return;
893 }
894
895 switch (format) {
896 case GL_STENCIL_INDEX:
897 draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
898 break;
899 case GL_DEPTH_COMPONENT:
900 draw_depth_pixels( ctx, x, y, width, height, type, pixels );
901 break;
902 case GL_COLOR_INDEX:
903 if (ctx->Visual->RGBAflag)
904 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
905 else
906 draw_index_pixels(ctx, x, y, width, height, type, pixels);
907 break;
908 case GL_RED:
909 case GL_GREEN:
910 case GL_BLUE:
911 case GL_ALPHA:
912 case GL_LUMINANCE:
913 case GL_LUMINANCE_ALPHA:
914 case GL_RGB:
915 case GL_BGR:
916 case GL_RGBA:
917 case GL_BGRA:
918 case GL_ABGR_EXT:
919 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
920 break;
921 default:
922 gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
923 return;
924 }
925 }
926 else if (ctx->RenderMode==GL_FEEDBACK) {
927 if (ctx->Current.RasterPosValid) {
928 GLfloat color[4];
929 GLfloat texcoord[4], invq;
930 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor);
931 invq = 1.0F / ctx->Current.Texcoord[0][3];
932 texcoord[0] = ctx->Current.Texcoord[0][0] * invq;
933 texcoord[1] = ctx->Current.Texcoord[0][1] * invq;
934 texcoord[2] = ctx->Current.Texcoord[0][2] * invq;
935 texcoord[3] = ctx->Current.Texcoord[0][3];
936 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
937 gl_feedback_vertex( ctx,
938 ctx->Current.RasterPos,
939 color, ctx->Current.Index, texcoord );
940 }
941 }
942 else if (ctx->RenderMode==GL_SELECT) {
943 if (ctx->Current.RasterPosValid) {
944 gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
945 }
946 }
947 }
948