LOTS of changes, building upon Klaus's work.
[mesa.git] / src / mesa / swrast / s_drawpix.c
1 /* $Id: s_drawpix.c,v 1.26 2002/01/27 18:32:03 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 4.1
6 *
7 * Copyright (C) 1999-2002 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 #include "glheader.h"
29 #include "colormac.h"
30 #include "context.h"
31 #include "convolve.h"
32 #include "image.h"
33 #include "macros.h"
34 #include "mem.h"
35 #include "mmath.h"
36 #include "pixel.h"
37
38 #include "s_context.h"
39 #include "s_drawpix.h"
40 #include "s_fog.h"
41 #include "s_pixeltex.h"
42 #include "s_span.h"
43 #include "s_stencil.h"
44 #include "s_texture.h"
45 #include "s_zoom.h"
46
47
48
49 /*
50 * Given the dest position, size and skipPixels and skipRows values
51 * for a glDrawPixels command, perform clipping of the image bounds
52 * so the result lies withing the context's buffer bounds.
53 * Return: GL_TRUE if image is ready for drawing
54 * GL_FALSE if image was completely clipped away (draw nothing)
55 */
56 GLboolean
57 _mesa_clip_pixelrect(const GLcontext *ctx,
58 GLint *destX, GLint *destY,
59 GLsizei *width, GLsizei *height,
60 GLint *skipPixels, GLint *skipRows)
61 {
62 const GLframebuffer *buffer = ctx->DrawBuffer;
63
64 /* left clipping */
65 if (*destX < buffer->_Xmin) {
66 *skipPixels += (buffer->_Xmin - *destX);
67 *width -= (buffer->_Xmin - *destX);
68 *destX = buffer->_Xmin;
69 }
70 /* right clipping */
71 if (*destX + *width > buffer->_Xmax)
72 *width -= (*destX + *width - buffer->_Xmax);
73
74 if (*width <= 0)
75 return GL_FALSE;
76
77 /* bottom clipping */
78 if (*destY < buffer->_Ymin) {
79 *skipRows += (buffer->_Ymin - *destY);
80 *height -= (buffer->_Ymin - *destY);
81 *destY = buffer->_Ymin;
82 }
83 /* top clipping */
84 if (*destY + *height > buffer->_Ymax)
85 *height -= (*destY + *height - buffer->_Ymax);
86
87 if (*height <= 0)
88 return GL_TRUE;
89
90 return GL_TRUE;
91 }
92
93
94
95 /*
96 * Try to do a fast and simple RGB(a) glDrawPixels.
97 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
98 */
99 static GLboolean
100 fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
101 GLsizei width, GLsizei height,
102 GLenum format, GLenum type, const GLvoid *pixels)
103 {
104 SWcontext *swrast = SWRAST_CONTEXT(ctx);
105 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
106 GLchan rgb[MAX_WIDTH][3];
107 GLchan rgba[MAX_WIDTH][4];
108
109 if (!ctx->Current.RasterPosValid) {
110 return GL_TRUE; /* no-op */
111 }
112
113 if ((SWRAST_CONTEXT(ctx)->_RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
114 && ctx->Texture._ReallyEnabled == 0
115 && unpack->Alignment == 1
116 && !unpack->SwapBytes
117 && !unpack->LsbFirst) {
118
119 GLint destX = x;
120 GLint destY = y;
121 GLint drawWidth = width; /* actual width drawn */
122 GLint drawHeight = height; /* actual height drawn */
123 GLint skipPixels = unpack->SkipPixels;
124 GLint skipRows = unpack->SkipRows;
125 GLint rowLength;
126 GLdepth zSpan[MAX_WIDTH]; /* only used when zooming */
127 GLint zoomY0 = 0;
128
129 if (unpack->RowLength > 0)
130 rowLength = unpack->RowLength;
131 else
132 rowLength = width;
133
134 /* If we're not using pixel zoom then do all clipping calculations
135 * now. Otherwise, we'll let the _mesa_write_zoomed_*_span() functions
136 * handle the clipping.
137 */
138 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
139 /* horizontal clipping */
140 if (destX < ctx->DrawBuffer->_Xmin) {
141 skipPixels += (ctx->DrawBuffer->_Xmin - destX);
142 drawWidth -= (ctx->DrawBuffer->_Xmin - destX);
143 destX = ctx->DrawBuffer->_Xmin;
144 }
145 if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
146 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
147 if (drawWidth <= 0)
148 return GL_TRUE;
149
150 /* vertical clipping */
151 if (destY < ctx->DrawBuffer->_Ymin) {
152 skipRows += (ctx->DrawBuffer->_Ymin - destY);
153 drawHeight -= (ctx->DrawBuffer->_Ymin - destY);
154 destY = ctx->DrawBuffer->_Ymin;
155 }
156 if (destY + drawHeight > ctx->DrawBuffer->_Ymax)
157 drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax);
158 if (drawHeight <= 0)
159 return GL_TRUE;
160 }
161 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
162 /* upside-down image */
163 /* horizontal clipping */
164 if (destX < ctx->DrawBuffer->_Xmin) {
165 skipPixels += (ctx->DrawBuffer->_Xmin - destX);
166 drawWidth -= (ctx->DrawBuffer->_Xmin - destX);
167 destX = ctx->DrawBuffer->_Xmin;
168 }
169 if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
170 drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
171 if (drawWidth <= 0)
172 return GL_TRUE;
173
174 /* vertical clipping */
175 if (destY > ctx->DrawBuffer->_Ymax) {
176 skipRows += (destY - ctx->DrawBuffer->_Ymax);
177 drawHeight -= (destY - ctx->DrawBuffer->_Ymax);
178 destY = ctx->DrawBuffer->_Ymax;
179 }
180 if (destY - drawHeight < ctx->DrawBuffer->_Ymin)
181 drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight));
182 if (drawHeight <= 0)
183 return GL_TRUE;
184 }
185 else {
186 /* setup array of fragment Z value to pass to zoom function */
187 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
188 GLint i;
189 ASSERT(drawWidth < MAX_WIDTH);
190 for (i=0; i<drawWidth; i++)
191 zSpan[i] = z;
192
193 /* save Y value of first row */
194 zoomY0 = IROUND(ctx->Current.RasterPos[1]);
195 }
196
197
198 /*
199 * Ready to draw!
200 * The window region at (destX, destY) of size (drawWidth, drawHeight)
201 * will be written to.
202 * We'll take pixel data from buffer pointed to by "pixels" but we'll
203 * skip "skipRows" rows and skip "skipPixels" pixels/row.
204 */
205
206 if (format == GL_RGBA && type == CHAN_TYPE
207 && ctx->_ImageTransferState==0) {
208 if (ctx->Visual.rgbMode) {
209 GLchan *src = (GLchan *) pixels
210 + (skipRows * rowLength + skipPixels) * 4;
211 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
212 /* no zooming */
213 GLint row;
214 for (row=0; row<drawHeight; row++) {
215 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
216 (CONST GLchan (*)[4]) src, NULL);
217 src += rowLength * 4;
218 destY++;
219 }
220 }
221 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
222 /* upside-down */
223 GLint row;
224 for (row=0; row<drawHeight; row++) {
225 destY--;
226 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
227 (CONST GLchan (*)[4]) src, NULL);
228 src += rowLength * 4;
229 }
230 }
231 else {
232 /* with zooming */
233 GLint row;
234 for (row=0; row<drawHeight; row++) {
235 _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
236 zSpan, 0, (CONST GLchan (*)[4]) src, zoomY0);
237 src += rowLength * 4;
238 destY++;
239 }
240 }
241 }
242 return GL_TRUE;
243 }
244 else if (format == GL_RGB && type == CHAN_TYPE
245 && ctx->_ImageTransferState == 0) {
246 if (ctx->Visual.rgbMode) {
247 GLchan *src = (GLchan *) pixels
248 + (skipRows * rowLength + skipPixels) * 3;
249 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
250 GLint row;
251 for (row=0; row<drawHeight; row++) {
252 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
253 (CONST GLchan (*)[3]) src, NULL);
254 src += rowLength * 3;
255 destY++;
256 }
257 }
258 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
259 /* upside-down */
260 GLint row;
261 for (row=0; row<drawHeight; row++) {
262 destY--;
263 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
264 (CONST GLchan (*)[3]) src, NULL);
265 src += rowLength * 3;
266 }
267 }
268 else {
269 /* with zooming */
270 GLint row;
271 for (row=0; row<drawHeight; row++) {
272 _mesa_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
273 zSpan, 0, (CONST GLchan (*)[3]) src, zoomY0);
274 src += rowLength * 3;
275 destY++;
276 }
277 }
278 }
279 return GL_TRUE;
280 }
281 else if (format == GL_LUMINANCE && type == CHAN_TYPE
282 && ctx->_ImageTransferState==0) {
283 if (ctx->Visual.rgbMode) {
284 GLchan *src = (GLchan *) pixels
285 + (skipRows * rowLength + skipPixels);
286 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
287 /* no zooming */
288 GLint row;
289 ASSERT(drawWidth < MAX_WIDTH);
290 for (row=0; row<drawHeight; row++) {
291 GLint i;
292 for (i=0;i<drawWidth;i++) {
293 rgb[i][0] = src[i];
294 rgb[i][1] = src[i];
295 rgb[i][2] = src[i];
296 }
297 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
298 (CONST GLchan (*)[3]) rgb, NULL);
299 src += rowLength;
300 destY++;
301 }
302 }
303 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
304 /* upside-down */
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 destY--;
315 (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
316 (CONST GLchan (*)[3]) rgb, NULL);
317 src += rowLength;
318 }
319 }
320 else {
321 /* with zooming */
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 _mesa_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
332 zSpan, 0, (CONST GLchan (*)[3]) rgb, zoomY0);
333 src += rowLength;
334 destY++;
335 }
336 }
337 }
338 return GL_TRUE;
339 }
340 else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
341 && ctx->_ImageTransferState == 0) {
342 if (ctx->Visual.rgbMode) {
343 GLchan *src = (GLchan *) pixels
344 + (skipRows * rowLength + skipPixels)*2;
345 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
346 /* no zooming */
347 GLint row;
348 ASSERT(drawWidth < MAX_WIDTH);
349 for (row=0; row<drawHeight; row++) {
350 GLint i;
351 GLchan *ptr = src;
352 for (i=0;i<drawWidth;i++) {
353 rgba[i][0] = *ptr;
354 rgba[i][1] = *ptr;
355 rgba[i][2] = *ptr++;
356 rgba[i][3] = *ptr++;
357 }
358 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
359 (CONST GLchan (*)[4]) rgba, NULL);
360 src += rowLength*2;
361 destY++;
362 }
363 }
364 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
365 /* upside-down */
366 GLint row;
367 ASSERT(drawWidth < MAX_WIDTH);
368 for (row=0; row<drawHeight; row++) {
369 GLint i;
370 GLchan *ptr = src;
371 for (i=0;i<drawWidth;i++) {
372 rgba[i][0] = *ptr;
373 rgba[i][1] = *ptr;
374 rgba[i][2] = *ptr++;
375 rgba[i][3] = *ptr++;
376 }
377 destY--;
378 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
379 (CONST GLchan (*)[4]) rgba, NULL);
380 src += rowLength*2;
381 }
382 }
383 else {
384 /* with zooming */
385 GLint row;
386 ASSERT(drawWidth < MAX_WIDTH);
387 for (row=0; row<drawHeight; row++) {
388 GLchan *ptr = src;
389 GLint i;
390 for (i=0;i<drawWidth;i++) {
391 rgba[i][0] = *ptr;
392 rgba[i][1] = *ptr;
393 rgba[i][2] = *ptr++;
394 rgba[i][3] = *ptr++;
395 }
396 _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
397 zSpan, 0, (CONST GLchan (*)[4]) rgba, zoomY0);
398 src += rowLength*2;
399 destY++;
400 }
401 }
402 }
403 return GL_TRUE;
404 }
405 else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
406 GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
407 if (ctx->Visual.rgbMode) {
408 /* convert CI data to RGBA */
409 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
410 /* no zooming */
411 GLint row;
412 for (row=0; row<drawHeight; row++) {
413 ASSERT(drawWidth < MAX_WIDTH);
414 _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
415 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
416 (const GLchan (*)[4]) rgba,
417 NULL);
418 src += rowLength;
419 destY++;
420 }
421 return GL_TRUE;
422 }
423 else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
424 /* upside-down */
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 destY--;
430 (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
431 (CONST GLchan (*)[4]) rgba,
432 NULL);
433 src += rowLength;
434 }
435 return GL_TRUE;
436 }
437 else {
438 /* with zooming */
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 _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
444 zSpan, 0, (CONST GLchan (*)[4]) rgba, zoomY0);
445 src += rowLength;
446 destY++;
447 }
448 return GL_TRUE;
449 }
450 }
451 else if (ctx->_ImageTransferState==0) {
452 /* write CI data to CI frame buffer */
453 GLint row;
454 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
455 /* no zooming */
456 for (row=0; row<drawHeight; row++) {
457 (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
458 src, NULL);
459 src += rowLength;
460 destY++;
461 }
462 return GL_TRUE;
463 }
464 else {
465 /* with zooming */
466 return GL_FALSE;
467 }
468 }
469 }
470 else {
471 /* can't handle this pixel format and/or data type here */
472 return GL_FALSE;
473 }
474 }
475
476 /* can't do a simple draw, have to use slow path */
477 return GL_FALSE;
478 }
479
480
481
482 /*
483 * Do glDrawPixels of index pixels.
484 */
485 static void
486 draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
487 GLsizei width, GLsizei height,
488 GLenum type, const GLvoid *pixels )
489 {
490 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
491 const GLint desty = y;
492 GLint row, drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
493 struct sw_span span;
494
495 INIT_SPAN(span);
496 span.arrayMask |= SPAN_INDEX;
497
498 if (ctx->Depth.Test)
499 _mesa_span_default_z(ctx, &span);
500 if (ctx->Fog.Enabled)
501 _mesa_span_default_fog(ctx, &span);
502
503 /*
504 * General solution
505 */
506 for (row = 0; row < height; row++, y++) {
507 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
508 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
509 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT,
510 span.color.index,
511 type, source, &ctx->Unpack,
512 ctx->_ImageTransferState);
513 if (zoom) {
514 _mesa_write_zoomed_index_span(ctx, drawWidth, x, y,
515 span.zArray, span.fogArray,
516 span.color.index, desty);
517 }
518 else {
519 span.x = x;
520 span.y = y;
521 span.end = drawWidth;
522 _mesa_write_index_span(ctx, &span, GL_BITMAP);
523 }
524 }
525 }
526
527
528
529 /*
530 * Do glDrawPixels of stencil image. The image datatype may either
531 * be GLubyte or GLbitmap.
532 */
533 static void
534 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
535 GLsizei width, GLsizei height,
536 GLenum type, const GLvoid *pixels )
537 {
538 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
539 const GLint desty = y;
540 GLint row, drawWidth;
541
542 if (type != GL_BYTE &&
543 type != GL_UNSIGNED_BYTE &&
544 type != GL_SHORT &&
545 type != GL_UNSIGNED_SHORT &&
546 type != GL_INT &&
547 type != GL_UNSIGNED_INT &&
548 type != GL_FLOAT &&
549 type != GL_BITMAP) {
550 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
551 return;
552 }
553
554 if (ctx->Visual.stencilBits == 0) {
555 _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)");
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 _mesa_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 * Do a glDrawPixels of depth values.
590 */
591 static void
592 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
593 GLsizei width, GLsizei height,
594 GLenum type, const GLvoid *pixels )
595 {
596 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
597 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
598 const GLint desty = y;
599 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
600 struct sw_span span;
601
602 INIT_SPAN(span);
603 span.arrayMask |= SPAN_Z;
604 span.end = drawWidth;
605
606 if (type != GL_BYTE
607 && type != GL_UNSIGNED_BYTE
608 && type != GL_SHORT
609 && type != GL_UNSIGNED_SHORT
610 && type != GL_INT
611 && type != GL_UNSIGNED_INT
612 && type != GL_FLOAT) {
613 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
614 return;
615 }
616
617 _mesa_span_default_color(ctx, &span);
618
619 if (ctx->Fog.Enabled)
620 _mesa_span_default_fog(ctx, &span);
621
622 if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
623 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
624 /* Special case: directly write 16-bit depth values */
625 GLint row;
626 for (row = 0; row < height; row++, y++) {
627 const GLushort *zptr = (const GLushort *)
628 _mesa_image_address(&ctx->Unpack, pixels, width, height,
629 GL_DEPTH_COMPONENT, type, 0, row, 0);
630 GLint i;
631 for (i = 0; i < drawWidth; i++)
632 span.zArray[i] = zptr[i];
633
634 span.x = x;
635 span.y = y;
636 span.end = drawWidth;
637 span.filledDepth = GL_TRUE; /* XXX temporary */
638 _mesa_write_rgba_span(ctx, &span, GL_BITMAP);
639 }
640 }
641 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
642 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
643 /* Special case: directly write 32-bit depth values */
644 GLint row;
645 for (row = 0; row < height; row++, y++) {
646 const GLuint *zptr = (const GLuint *)
647 _mesa_image_address(&ctx->Unpack, pixels, width, height,
648 GL_DEPTH_COMPONENT, type, 0, row, 0);
649
650 /* XXX get rid of this loop. use zArray pointer in span */
651 GLint i;
652 for (i = 0; i < drawWidth; i++)
653 span.zArray[i] = zptr[i];
654 span.x = x;
655 span.y = y;
656 span.end = drawWidth;
657 _mesa_write_rgba_span(ctx, &span, GL_BITMAP);
658 }
659 }
660 else {
661 /* General case */
662 GLint row;
663 for (row = 0; row < height; row++, y++) {
664 GLfloat fspan[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, fspan, type, src,
668 &ctx->Unpack );
669 /* clamp depth values to [0,1] and convert from floats to integers */
670 {
671 const GLfloat zs = ctx->DepthMaxF;
672 GLint i;
673 for (i = 0; i < drawWidth; i++) {
674 span.zArray[i] = (GLdepth) (fspan[i] * zs);
675 }
676 }
677
678 if (ctx->Visual.rgbMode) {
679 if (zoom) {
680 _mesa_write_zoomed_rgba_span(ctx, width, x, y, span.zArray, 0,
681 (const GLchan (*)[4]) span.color.rgba, desty);
682 }
683 else {
684 span.x = x;
685 span.y = y;
686 span.end = drawWidth;
687 _mesa_write_rgba_span(ctx, &span, GL_BITMAP);
688 }
689 }
690 else {
691 if (zoom) {
692 _mesa_write_zoomed_index_span(ctx, drawWidth, x, y,
693 span.zArray, 0,
694 span.color.index, GL_BITMAP);
695 }
696 else {
697 span.x = x;
698 span.y = y;
699 span.end = drawWidth;
700 _mesa_write_index_span(ctx, &span, GL_BITMAP);
701 }
702 }
703 }
704 }
705 }
706
707
708 /*
709 * Do glDrawPixels of RGBA pixels.
710 */
711 static void
712 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
713 GLsizei width, GLsizei height,
714 GLenum format, GLenum type, const GLvoid *pixels )
715 {
716 SWcontext *swrast = SWRAST_CONTEXT(ctx);
717 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
718 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
719 const GLint desty = y;
720 GLboolean quickDraw;
721 GLfloat *convImage = NULL;
722 GLuint transferOps = ctx->_ImageTransferState;
723 struct sw_span span;
724
725 INIT_SPAN(span);
726 span.arrayMask |= SPAN_RGBA;
727
728 if (!_mesa_is_legal_format_and_type(format, type)) {
729 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
730 return;
731 }
732
733 /* Try an optimized glDrawPixels first */
734 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
735 return;
736
737 /* Fragment depth values */
738 if (ctx->Depth.Test || ctx->Fog.Enabled) {
739 /* fill in array of z values */
740 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
741 GLfloat fog;
742 GLint i;
743
744 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
745 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
746 else
747 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
748
749 for (i=0;i<width;i++) {
750 span.zArray[i] = z;
751 span.fogArray[i] = fog;
752 }
753 }
754
755 if (ctx->Fog.Enabled)
756 _mesa_span_default_fog(ctx, &span);
757 span.arrayMask |= SPAN_Z;
758
759 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
760 && x + width <= ctx->DrawBuffer->Width
761 && y + height <= ctx->DrawBuffer->Height) {
762 quickDraw = GL_TRUE;
763 }
764 else {
765 quickDraw = GL_FALSE;
766 }
767
768 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
769 /* Convolution has to be handled specially. We'll create an
770 * intermediate image, applying all pixel transfer operations
771 * up to convolution. Then we'll convolve the image. Then
772 * we'll proceed with the rest of the transfer operations and
773 * rasterize the image.
774 */
775 GLint row;
776 GLfloat *dest, *tmpImage;
777
778 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
779 if (!tmpImage) {
780 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
781 return;
782 }
783 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
784 if (!convImage) {
785 FREE(tmpImage);
786 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
787 return;
788 }
789
790 /* Unpack the image and apply transfer ops up to convolution */
791 dest = tmpImage;
792 for (row = 0; row < height; row++) {
793 const GLvoid *source = _mesa_image_address(unpack,
794 pixels, width, height, format, type, 0, row, 0);
795 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest,
796 format, type, source, unpack,
797 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
798 GL_FALSE);
799 dest += width * 4;
800 }
801
802 /* do convolution */
803 if (ctx->Pixel.Convolution2DEnabled) {
804 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
805 }
806 else {
807 ASSERT(ctx->Pixel.Separable2DEnabled);
808 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
809 }
810 FREE(tmpImage);
811
812 /* continue transfer ops and draw the convolved image */
813 unpack = &_mesa_native_packing;
814 pixels = convImage;
815 format = GL_RGBA;
816 type = GL_FLOAT;
817 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
818 }
819
820 /*
821 * General solution
822 */
823 {
824 GLint row;
825 if (width > MAX_WIDTH)
826 width = MAX_WIDTH;
827 for (row = 0; row < height; row++, y++) {
828 const GLvoid *source = _mesa_image_address(unpack,
829 pixels, width, height, format, type, 0, row, 0);
830 /* printf("Unpack f=0x%x t=0x%x\n", format, type);*/
831 _mesa_unpack_chan_color_span(ctx, width, GL_RGBA,
832 (GLchan *) span.color.rgba,
833 format, type, source, unpack,
834 transferOps);
835 if (0){
836 int k;
837 for (k = 0; k < width; k++)
838 printf("%02x ", span.color.rgba[k][3]);
839 printf("\n");
840 }
841
842 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
843 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
844 continue;
845
846 if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._ReallyEnabled) {
847 span.end = width;
848 _swrast_pixel_texture(ctx, &span);
849 }
850
851 if (quickDraw) {
852 (*swrast->Driver.WriteRGBASpan)(ctx, width, x, y,
853 (CONST GLchan (*)[4]) span.color.rgba, NULL);
854 }
855 else if (zoom) {
856 _mesa_write_zoomed_rgba_span(ctx, width, x, y, span.zArray,
857 span.fogArray,
858 (CONST GLchan (*)[4]) span.color.rgba, desty);
859 }
860 else {
861 span.x = x;
862 span.y = y;
863 span.end = width;
864 _mesa_write_rgba_span(ctx, &span, GL_BITMAP);
865 }
866 }
867 }
868
869 if (convImage) {
870 FREE(convImage);
871 }
872 }
873
874
875
876 /*
877 * Execute glDrawPixels
878 */
879 void
880 _swrast_DrawPixels( GLcontext *ctx,
881 GLint x, GLint y,
882 GLsizei width, GLsizei height,
883 GLenum format, GLenum type,
884 const struct gl_pixelstore_attrib *unpack,
885 const GLvoid *pixels )
886 {
887 SWcontext *swrast = SWRAST_CONTEXT(ctx);
888 (void) unpack;
889
890
891 if (swrast->NewState)
892 _swrast_validate_derived( ctx );
893
894 RENDER_START(swrast,ctx);
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.rgbMode)
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 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
923 }
924
925 RENDER_FINISH(swrast,ctx);
926 }