added missing \'s
[mesa.git] / src / mesa / swrast / s_drawpix.c
1 /* $Id: s_drawpix.c,v 1.22 2001/06/26 21:15:36 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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;
493 GLdepth zspan[MAX_WIDTH];
494 GLfloat fogSpan[MAX_WIDTH];
495
496 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
497
498 /* Fragment depth values */
499 if (ctx->Depth.Test || ctx->Fog.Enabled) {
500 GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
501 GLfloat fog;
502 GLint i;
503
504 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
505 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
506 else
507 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
508
509 for (i = 0; i < drawWidth; i++) {
510 zspan[i] = zval;
511 fogSpan[i] = fog;
512 }
513 }
514
515 /*
516 * General solution
517 */
518 for (row = 0; row < height; row++, y++) {
519 GLuint indexes[MAX_WIDTH];
520 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
521 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
522 _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
523 type, source, &ctx->Unpack,
524 ctx->_ImageTransferState);
525 if (zoom) {
526 _mesa_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, fogSpan,
527 indexes, desty);
528 }
529 else {
530 _mesa_write_index_span(ctx, drawWidth, x, y, zspan, fogSpan, indexes,
531 NULL, GL_BITMAP);
532 }
533 }
534 }
535
536
537
538 /*
539 * Do glDrawPixels of stencil image. The image datatype may either
540 * be GLubyte or GLbitmap.
541 */
542 static void
543 draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
544 GLsizei width, GLsizei height,
545 GLenum type, const GLvoid *pixels )
546 {
547 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
548 const GLint desty = y;
549 GLint row, drawWidth;
550
551 if (type != GL_BYTE &&
552 type != GL_UNSIGNED_BYTE &&
553 type != GL_SHORT &&
554 type != GL_UNSIGNED_SHORT &&
555 type != GL_INT &&
556 type != GL_UNSIGNED_INT &&
557 type != GL_FLOAT &&
558 type != GL_BITMAP) {
559 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
560 return;
561 }
562
563 drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
564
565 for (row = 0; row < height; row++, y++) {
566 GLstencil values[MAX_WIDTH];
567 GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
568 ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
569 const GLvoid *source = _mesa_image_address(&ctx->Unpack,
570 pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
571 _mesa_unpack_index_span(ctx, drawWidth, destType, values,
572 type, source, &ctx->Unpack,
573 ctx->_ImageTransferState);
574 if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
575 _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
576 }
577 if (ctx->Pixel.MapStencilFlag) {
578 _mesa_map_stencil( ctx, drawWidth, values );
579 }
580
581 if (zoom) {
582 _mesa_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
583 values, desty );
584 }
585 else {
586 _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
587 }
588 }
589 }
590
591
592
593 /*
594 * Do a glDrawPixels of depth values.
595 */
596 static void
597 draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
598 GLsizei width, GLsizei height,
599 GLenum type, const GLvoid *pixels )
600 {
601 const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
602 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
603 const GLint desty = y;
604 GLchan rgba[MAX_WIDTH][4];
605 GLuint ispan[MAX_WIDTH];
606 GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
607
608 if (type != GL_BYTE
609 && type != GL_UNSIGNED_BYTE
610 && type != GL_SHORT
611 && type != GL_UNSIGNED_SHORT
612 && type != GL_INT
613 && type != GL_UNSIGNED_INT
614 && type != GL_FLOAT) {
615 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
616 return;
617 }
618
619 /* Colors or indexes */
620 if (ctx->Visual.rgbMode) {
621 GLint i;
622 GLint r, g, b, a;
623 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
624 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
625 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
626 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
627 for (i = 0; i < drawWidth; i++) {
628 rgba[i][RCOMP] = r;
629 rgba[i][GCOMP] = g;
630 rgba[i][BCOMP] = b;
631 rgba[i][ACOMP] = a;
632 }
633 }
634 else {
635 GLint i;
636 for (i = 0; i < drawWidth; i++) {
637 ispan[i] = ctx->Current.RasterIndex;
638 }
639 }
640
641 if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
642 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
643 /* Special case: directly write 16-bit depth values */
644 GLint row;
645 for (row = 0; row < height; row++, y++) {
646 GLdepth zspan[MAX_WIDTH];
647 const GLushort *zptr = (const GLushort *)
648 _mesa_image_address(&ctx->Unpack, pixels, width, height,
649 GL_DEPTH_COMPONENT, type, 0, row, 0);
650 GLint i;
651 for (i = 0; i < width; i++)
652 zspan[i] = zptr[i];
653 _mesa_write_rgba_span(ctx, width, x, y, zspan, 0, rgba,
654 NULL, GL_BITMAP);
655 }
656 }
657 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
658 && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
659 /* Special case: directly write 32-bit depth values */
660 GLint row;
661 for (row = 0; row < height; row++, y++) {
662 const GLuint *zptr = (const GLuint *)
663 _mesa_image_address(&ctx->Unpack, pixels, width, height,
664 GL_DEPTH_COMPONENT, type, 0, row, 0);
665 _mesa_write_rgba_span(ctx, width, x, y, zptr, 0, rgba,
666 NULL, GL_BITMAP);
667 }
668 }
669 else {
670 /* General case */
671 GLint row;
672 for (row = 0; row < height; row++, y++) {
673 GLfloat fspan[MAX_WIDTH];
674 GLdepth zspan[MAX_WIDTH];
675 const GLvoid *src = _mesa_image_address(&ctx->Unpack,
676 pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
677 _mesa_unpack_depth_span( ctx, drawWidth, fspan, type, src,
678 &ctx->Unpack );
679 /* clamp depth values to [0,1] and convert from floats to integers */
680 {
681 const GLfloat zs = ctx->DepthMaxF;
682 GLint i;
683 for (i = 0; i < drawWidth; i++) {
684 zspan[i] = (GLdepth) (fspan[i] * zs);
685 }
686 }
687
688 if (ctx->Visual.rgbMode) {
689 if (zoom) {
690 _mesa_write_zoomed_rgba_span(ctx, width, x, y, zspan, 0,
691 (const GLchan (*)[4]) rgba, desty);
692 }
693 else {
694 _mesa_write_rgba_span(ctx, width, x, y, zspan, 0,
695 rgba, NULL, GL_BITMAP);
696 }
697 }
698 else {
699 if (zoom) {
700 _mesa_write_zoomed_index_span(ctx, width, x, y, zspan, 0,
701 ispan, GL_BITMAP);
702 }
703 else {
704 _mesa_write_index_span(ctx, width, x, y, zspan, 0,
705 ispan, NULL, GL_BITMAP);
706 }
707 }
708
709 }
710 }
711 }
712
713
714 /*
715 * Do glDrawPixels of RGBA pixels.
716 */
717 static void
718 draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
719 GLsizei width, GLsizei height,
720 GLenum format, GLenum type, const GLvoid *pixels )
721 {
722 SWcontext *swrast = SWRAST_CONTEXT(ctx);
723 const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
724 const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
725 const GLint desty = y;
726 GLdepth zspan[MAX_WIDTH];
727 GLfloat fogSpan[MAX_WIDTH];
728 GLboolean quickDraw;
729 GLfloat *convImage = NULL;
730 GLuint transferOps = ctx->_ImageTransferState;
731
732 if (!_mesa_is_legal_format_and_type(format, type)) {
733 _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
734 return;
735 }
736
737 /* Try an optimized glDrawPixels first */
738 if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
739 return;
740
741 /* Fragment depth values */
742 if (ctx->Depth.Test || ctx->Fog.Enabled) {
743 /* fill in array of z values */
744 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
745 GLfloat fog;
746 GLint i;
747
748 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
749 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
750 else
751 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
752
753 for (i=0;i<width;i++) {
754 zspan[i] = z;
755 fogSpan[i] = fog;
756 }
757 }
758
759
760 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
761 && x + width <= ctx->DrawBuffer->Width
762 && y + height <= ctx->DrawBuffer->Height) {
763 quickDraw = GL_TRUE;
764 }
765 else {
766 quickDraw = GL_FALSE;
767 }
768
769 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
770 /* Convolution has to be handled specially. We'll create an
771 * intermediate image, applying all pixel transfer operations
772 * up to convolution. Then we'll convolve the image. Then
773 * we'll proceed with the rest of the transfer operations and
774 * rasterize the image.
775 */
776 GLint row;
777 GLfloat *dest, *tmpImage;
778
779 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
780 if (!tmpImage) {
781 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
782 return;
783 }
784 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
785 if (!convImage) {
786 FREE(tmpImage);
787 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
788 return;
789 }
790
791 /* Unpack the image and apply transfer ops up to convolution */
792 dest = tmpImage;
793 for (row = 0; row < height; row++) {
794 const GLvoid *source = _mesa_image_address(unpack,
795 pixels, width, height, format, type, 0, row, 0);
796 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest,
797 format, type, source, unpack,
798 transferOps & IMAGE_PRE_CONVOLUTION_BITS,
799 GL_FALSE);
800 dest += width * 4;
801 }
802
803 /* do convolution */
804 if (ctx->Pixel.Convolution2DEnabled) {
805 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
806 }
807 else {
808 ASSERT(ctx->Pixel.Separable2DEnabled);
809 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
810 }
811 FREE(tmpImage);
812
813 /* continue transfer ops and draw the convolved image */
814 unpack = &_mesa_native_packing;
815 pixels = convImage;
816 format = GL_RGBA;
817 type = GL_FLOAT;
818 transferOps &= IMAGE_POST_CONVOLUTION_BITS;
819 }
820
821 /*
822 * General solution
823 */
824 {
825 GLchan rgba[MAX_WIDTH][4];
826 GLint row;
827 if (width > MAX_WIDTH)
828 width = MAX_WIDTH;
829 for (row = 0; row < height; row++, y++) {
830 const GLvoid *source = _mesa_image_address(unpack,
831 pixels, width, height, format, type, 0, row, 0);
832 _mesa_unpack_chan_color_span(ctx, width, GL_RGBA, (GLchan *) rgba,
833 format, type, source, unpack,
834 transferOps);
835 if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
836 (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
837 continue;
838
839 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
840 GLchan primary_rgba[MAX_WIDTH][4];
841 GLuint unit;
842 DEFARRAY(GLfloat, s, MAX_WIDTH); /* mac 32k limitation */
843 DEFARRAY(GLfloat, t, MAX_WIDTH);
844 DEFARRAY(GLfloat, r, MAX_WIDTH);
845 DEFARRAY(GLfloat, q, MAX_WIDTH);
846 CHECKARRAY(s, return); /* mac 32k limitation */
847 CHECKARRAY(t, return);
848 CHECKARRAY(r, return);
849 CHECKARRAY(q, return);
850
851 /* XXX not sure how multitexture is supposed to work here */
852 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
853
854 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
855 if (ctx->Texture.Unit[unit]._ReallyEnabled) {
856 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
857 s, t, r, q);
858 _swrast_texture_fragments(ctx, unit, width, s, t, r, NULL,
859 (CONST GLchan (*)[4]) primary_rgba,
860 rgba);
861 }
862 }
863 UNDEFARRAY(s); /* mac 32k limitation */
864 UNDEFARRAY(t);
865 UNDEFARRAY(r);
866 UNDEFARRAY(q);
867 }
868
869 if (quickDraw) {
870 (*swrast->Driver.WriteRGBASpan)(ctx, width, x, y,
871 (CONST GLchan (*)[4]) rgba, NULL);
872 }
873 else if (zoom) {
874 _mesa_write_zoomed_rgba_span(ctx, width, x, y, zspan, fogSpan,
875 (CONST GLchan (*)[4]) rgba, desty);
876 }
877 else {
878 _mesa_write_rgba_span(ctx, (GLuint) width, x, y, zspan, fogSpan,
879 rgba, NULL, GL_BITMAP);
880 }
881 }
882 }
883
884 if (convImage) {
885 FREE(convImage);
886 }
887 }
888
889
890
891 /*
892 * Execute glDrawPixels
893 */
894 void
895 _swrast_DrawPixels( GLcontext *ctx,
896 GLint x, GLint y,
897 GLsizei width, GLsizei height,
898 GLenum format, GLenum type,
899 const struct gl_pixelstore_attrib *unpack,
900 const GLvoid *pixels )
901 {
902 SWcontext *swrast = SWRAST_CONTEXT(ctx);
903 (void) unpack;
904
905
906 if (swrast->NewState)
907 _swrast_validate_derived( ctx );
908
909 RENDER_START(swrast,ctx);
910
911 switch (format) {
912 case GL_STENCIL_INDEX:
913 draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
914 break;
915 case GL_DEPTH_COMPONENT:
916 draw_depth_pixels( ctx, x, y, width, height, type, pixels );
917 break;
918 case GL_COLOR_INDEX:
919 if (ctx->Visual.rgbMode)
920 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
921 else
922 draw_index_pixels(ctx, x, y, width, height, type, pixels);
923 break;
924 case GL_RED:
925 case GL_GREEN:
926 case GL_BLUE:
927 case GL_ALPHA:
928 case GL_LUMINANCE:
929 case GL_LUMINANCE_ALPHA:
930 case GL_RGB:
931 case GL_BGR:
932 case GL_RGBA:
933 case GL_BGRA:
934 case GL_ABGR_EXT:
935 draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
936 break;
937 default:
938 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
939 }
940
941 RENDER_FINISH(swrast,ctx);
942 }