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