2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include "s_context.h"
35 #include "s_drawpix.h"
36 #include "s_pixeltex.h"
38 #include "s_stencil.h"
44 * Given the dest position, size and skipPixels and skipRows values
45 * for a glDrawPixels command, perform clipping of the image bounds
46 * so the result lies withing the context's buffer bounds.
47 * Return: GL_TRUE if image is ready for drawing
48 * GL_FALSE if image was completely clipped away (draw nothing)
51 _swrast_clip_pixelrect(const GLcontext
*ctx
,
52 GLint
*destX
, GLint
*destY
,
53 GLsizei
*width
, GLsizei
*height
,
54 GLint
*skipPixels
, GLint
*skipRows
)
56 const GLframebuffer
*buffer
= ctx
->DrawBuffer
;
59 if (*destX
< buffer
->_Xmin
) {
60 *skipPixels
+= (buffer
->_Xmin
- *destX
);
61 *width
-= (buffer
->_Xmin
- *destX
);
62 *destX
= buffer
->_Xmin
;
65 if (*destX
+ *width
> buffer
->_Xmax
)
66 *width
-= (*destX
+ *width
- buffer
->_Xmax
);
72 if (*destY
< buffer
->_Ymin
) {
73 *skipRows
+= (buffer
->_Ymin
- *destY
);
74 *height
-= (buffer
->_Ymin
- *destY
);
75 *destY
= buffer
->_Ymin
;
78 if (*destY
+ *height
> buffer
->_Ymax
)
79 *height
-= (*destY
+ *height
- buffer
->_Ymax
);
90 * Try to do a fast and simple RGB(a) glDrawPixels.
91 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
94 fast_draw_pixels(GLcontext
*ctx
, GLint x
, GLint y
,
95 GLsizei width
, GLsizei height
,
96 GLenum format
, GLenum type
, const GLvoid
*pixels
)
98 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
99 const struct gl_pixelstore_attrib
*unpack
= &ctx
->Unpack
;
102 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_RGBA
);
104 if (!ctx
->Current
.RasterPosValid
) {
105 return GL_TRUE
; /* no-op */
109 _swrast_span_default_z(ctx
, &span
);
110 if (ctx
->Fog
.Enabled
)
111 _swrast_span_default_fog(ctx
, &span
);
112 if (ctx
->Texture
._EnabledCoordUnits
)
113 _swrast_span_default_texcoords(ctx
, &span
);
115 if ((SWRAST_CONTEXT(ctx
)->_RasterMask
& ~CLIP_BIT
) == 0
116 && ctx
->Texture
._EnabledCoordUnits
== 0
117 && unpack
->Alignment
== 1
118 && !unpack
->SwapBytes
119 && !unpack
->LsbFirst
) {
123 GLint drawWidth
= width
; /* actual width drawn */
124 GLint drawHeight
= height
; /* actual height drawn */
125 GLint skipPixels
= unpack
->SkipPixels
;
126 GLint skipRows
= unpack
->SkipRows
;
130 if (unpack
->RowLength
> 0)
131 rowLength
= unpack
->RowLength
;
135 /* If we're not using pixel zoom then do all clipping calculations
136 * now. Otherwise, we'll let the _swrast_write_zoomed_*_span() functions
137 * handle the clipping.
139 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
140 /* horizontal clipping */
141 if (destX
< ctx
->DrawBuffer
->_Xmin
) {
142 skipPixels
+= (ctx
->DrawBuffer
->_Xmin
- destX
);
143 drawWidth
-= (ctx
->DrawBuffer
->_Xmin
- destX
);
144 destX
= ctx
->DrawBuffer
->_Xmin
;
146 if (destX
+ drawWidth
> ctx
->DrawBuffer
->_Xmax
)
147 drawWidth
-= (destX
+ drawWidth
- ctx
->DrawBuffer
->_Xmax
);
151 /* vertical clipping */
152 if (destY
< ctx
->DrawBuffer
->_Ymin
) {
153 skipRows
+= (ctx
->DrawBuffer
->_Ymin
- destY
);
154 drawHeight
-= (ctx
->DrawBuffer
->_Ymin
- destY
);
155 destY
= ctx
->DrawBuffer
->_Ymin
;
157 if (destY
+ drawHeight
> ctx
->DrawBuffer
->_Ymax
)
158 drawHeight
-= (destY
+ drawHeight
- ctx
->DrawBuffer
->_Ymax
);
162 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
163 /* upside-down image */
164 /* horizontal clipping */
165 if (destX
< ctx
->DrawBuffer
->_Xmin
) {
166 skipPixels
+= (ctx
->DrawBuffer
->_Xmin
- destX
);
167 drawWidth
-= (ctx
->DrawBuffer
->_Xmin
- destX
);
168 destX
= ctx
->DrawBuffer
->_Xmin
;
170 if (destX
+ drawWidth
> ctx
->DrawBuffer
->_Xmax
)
171 drawWidth
-= (destX
+ drawWidth
- ctx
->DrawBuffer
->_Xmax
);
175 /* vertical clipping */
176 if (destY
> ctx
->DrawBuffer
->_Ymax
) {
177 skipRows
+= (destY
- ctx
->DrawBuffer
->_Ymax
);
178 drawHeight
-= (destY
- ctx
->DrawBuffer
->_Ymax
);
179 destY
= ctx
->DrawBuffer
->_Ymax
;
181 if (destY
- drawHeight
< ctx
->DrawBuffer
->_Ymin
)
182 drawHeight
-= (ctx
->DrawBuffer
->_Ymin
- (destY
- drawHeight
));
187 if (drawWidth
> MAX_WIDTH
)
188 return GL_FALSE
; /* fall back to general case path */
190 /* save Y value of first row */
191 zoomY0
= IROUND(ctx
->Current
.RasterPos
[1]);
197 * The window region at (destX, destY) of size (drawWidth, drawHeight)
198 * will be written to.
199 * We'll take pixel data from buffer pointed to by "pixels" but we'll
200 * skip "skipRows" rows and skip "skipPixels" pixels/row.
203 if (format
== GL_RGBA
&& type
== CHAN_TYPE
204 && ctx
->_ImageTransferState
==0) {
205 if (ctx
->Visual
.rgbMode
) {
206 GLchan
*src
= (GLchan
*) pixels
207 + (skipRows
* rowLength
+ skipPixels
) * 4;
208 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
211 for (row
=0; row
<drawHeight
; row
++) {
212 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
213 (CONST
GLchan (*)[4]) src
, NULL
);
214 src
+= rowLength
* 4;
218 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
221 for (row
=0; row
<drawHeight
; row
++) {
223 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
224 (CONST
GLchan (*)[4]) src
, NULL
);
225 src
+= rowLength
* 4;
231 for (row
=0; row
<drawHeight
; row
++) {
234 span
.end
= drawWidth
;
235 _swrast_write_zoomed_rgba_span(ctx
, &span
,
236 (CONST
GLchan (*)[4]) src
, zoomY0
, 0);
237 src
+= rowLength
* 4;
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
) {
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;
258 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
261 for (row
=0; row
<drawHeight
; row
++) {
263 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
264 (CONST
GLchan (*)[3]) src
, NULL
);
265 src
+= rowLength
* 3;
271 for (row
=0; row
<drawHeight
; row
++) {
274 span
.end
= drawWidth
;
275 _swrast_write_zoomed_rgb_span(ctx
, &span
,
276 (CONST
GLchan (*)[3]) src
, zoomY0
, 0);
277 src
+= rowLength
* 3;
284 else if (format
== GL_LUMINANCE
&& type
== CHAN_TYPE
285 && ctx
->_ImageTransferState
==0) {
286 if (ctx
->Visual
.rgbMode
) {
287 GLchan
*src
= (GLchan
*) pixels
288 + (skipRows
* rowLength
+ skipPixels
);
289 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
292 ASSERT(drawWidth
< MAX_WIDTH
);
293 for (row
=0; row
<drawHeight
; row
++) {
295 for (i
=0;i
<drawWidth
;i
++) {
296 span
.array
->rgb
[i
][0] = src
[i
];
297 span
.array
->rgb
[i
][1] = src
[i
];
298 span
.array
->rgb
[i
][2] = src
[i
];
300 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
301 (CONST
GLchan (*)[3]) span
.array
->rgb
, NULL
);
306 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
309 ASSERT(drawWidth
< MAX_WIDTH
);
310 for (row
=0; row
<drawHeight
; row
++) {
312 for (i
=0;i
<drawWidth
;i
++) {
313 span
.array
->rgb
[i
][0] = src
[i
];
314 span
.array
->rgb
[i
][1] = src
[i
];
315 span
.array
->rgb
[i
][2] = src
[i
];
318 (*swrast
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
319 (CONST
GLchan (*)[3]) span
.array
->rgb
, NULL
);
326 ASSERT(drawWidth
< MAX_WIDTH
);
327 for (row
=0; row
<drawHeight
; row
++) {
329 for (i
=0;i
<drawWidth
;i
++) {
330 span
.array
->rgb
[i
][0] = src
[i
];
331 span
.array
->rgb
[i
][1] = src
[i
];
332 span
.array
->rgb
[i
][2] = src
[i
];
336 span
.end
= drawWidth
;
337 _swrast_write_zoomed_rgb_span(ctx
, &span
,
338 (CONST
GLchan (*)[3]) span
.array
->rgb
, zoomY0
, 0);
346 else if (format
== GL_LUMINANCE_ALPHA
&& type
== CHAN_TYPE
347 && ctx
->_ImageTransferState
== 0) {
348 if (ctx
->Visual
.rgbMode
) {
349 GLchan
*src
= (GLchan
*) pixels
350 + (skipRows
* rowLength
+ skipPixels
)*2;
351 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
354 ASSERT(drawWidth
< MAX_WIDTH
);
355 for (row
=0; row
<drawHeight
; row
++) {
358 for (i
=0;i
<drawWidth
;i
++) {
359 span
.array
->rgba
[i
][0] = *ptr
;
360 span
.array
->rgba
[i
][1] = *ptr
;
361 span
.array
->rgba
[i
][2] = *ptr
++;
362 span
.array
->rgba
[i
][3] = *ptr
++;
364 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
365 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
370 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
373 ASSERT(drawWidth
< MAX_WIDTH
);
374 for (row
=0; row
<drawHeight
; row
++) {
377 for (i
=0;i
<drawWidth
;i
++) {
378 span
.array
->rgba
[i
][0] = *ptr
;
379 span
.array
->rgba
[i
][1] = *ptr
;
380 span
.array
->rgba
[i
][2] = *ptr
++;
381 span
.array
->rgba
[i
][3] = *ptr
++;
384 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
385 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
392 ASSERT(drawWidth
< MAX_WIDTH
);
393 for (row
=0; row
<drawHeight
; row
++) {
396 for (i
=0;i
<drawWidth
;i
++) {
397 span
.array
->rgba
[i
][0] = *ptr
;
398 span
.array
->rgba
[i
][1] = *ptr
;
399 span
.array
->rgba
[i
][2] = *ptr
++;
400 span
.array
->rgba
[i
][3] = *ptr
++;
404 span
.end
= drawWidth
;
405 _swrast_write_zoomed_rgba_span(ctx
, &span
,
406 (CONST
GLchan (*)[4]) span
.array
->rgba
, zoomY0
, 0);
414 else if (format
==GL_COLOR_INDEX
&& type
==GL_UNSIGNED_BYTE
) {
415 GLubyte
*src
= (GLubyte
*) pixels
+ skipRows
* rowLength
+ skipPixels
;
416 if (ctx
->Visual
.rgbMode
) {
417 /* convert CI data to RGBA */
418 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
421 for (row
=0; row
<drawHeight
; row
++) {
422 ASSERT(drawWidth
< MAX_WIDTH
);
423 _mesa_map_ci8_to_rgba(ctx
, drawWidth
, src
, span
.array
->rgba
);
424 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
425 (const GLchan (*)[4]) span
.array
->rgba
, NULL
);
431 else if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==-1.0F
) {
434 for (row
=0; row
<drawHeight
; row
++) {
435 ASSERT(drawWidth
< MAX_WIDTH
);
436 _mesa_map_ci8_to_rgba(ctx
, drawWidth
, src
, span
.array
->rgba
);
438 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
439 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
447 for (row
=0; row
<drawHeight
; row
++) {
448 ASSERT(drawWidth
< MAX_WIDTH
);
449 _mesa_map_ci8_to_rgba(ctx
, drawWidth
, src
, span
.array
->rgba
);
452 span
.end
= drawWidth
;
453 _swrast_write_zoomed_rgba_span(ctx
, &span
,
454 (CONST
GLchan (*)[4]) span
.array
->rgba
, zoomY0
, 0);
461 else if (ctx
->_ImageTransferState
==0) {
462 /* write CI data to CI frame buffer */
464 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
466 for (row
=0; row
<drawHeight
; row
++) {
467 (*swrast
->Driver
.WriteCI8Span
)(ctx
, drawWidth
, destX
, destY
,
481 /* can't handle this pixel format and/or data type here */
486 /* can't do a simple draw, have to use slow path */
493 * Draw color index image.
496 draw_index_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
497 GLsizei width
, GLsizei height
,
498 GLenum type
, const GLvoid
*pixels
)
500 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
501 GLint row
, skipPixels
;
504 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_INDEX
);
507 _swrast_span_default_z(ctx
, &span
);
508 if (ctx
->Fog
.Enabled
)
509 _swrast_span_default_fog(ctx
, &span
);
515 while (skipPixels
< width
) {
516 const GLint spanX
= x
+ (zoom
? 0 : skipPixels
);
518 const GLint spanEnd
= (width
- skipPixels
> MAX_WIDTH
)
519 ? MAX_WIDTH
: (width
- skipPixels
);
520 ASSERT(spanEnd
<= MAX_WIDTH
);
521 for (row
= 0; row
< height
; row
++, span
.y
++) {
522 const GLvoid
*source
= _mesa_image_address(&ctx
->Unpack
, pixels
,
524 GL_COLOR_INDEX
, type
,
526 _mesa_unpack_index_span(ctx
, span
.end
, GL_UNSIGNED_INT
,
527 span
.array
->index
, type
, source
, &ctx
->Unpack
,
528 ctx
->_ImageTransferState
);
530 /* These may get changed during writing/clipping */
536 _swrast_write_zoomed_index_span(ctx
, &span
, y
, skipPixels
);
538 _swrast_write_index_span(ctx
, &span
);
540 skipPixels
+= spanEnd
;
547 * Draw stencil image.
550 draw_stencil_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
551 GLsizei width
, GLsizei height
,
552 GLenum type
, const GLvoid
*pixels
)
554 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
555 const GLint desty
= y
;
556 GLint row
, skipPixels
;
558 if (type
!= GL_BYTE
&&
559 type
!= GL_UNSIGNED_BYTE
&&
561 type
!= GL_UNSIGNED_SHORT
&&
563 type
!= GL_UNSIGNED_INT
&&
566 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(stencil type)");
570 if (ctx
->Visual
.stencilBits
== 0) {
571 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glDrawPixels(no stencil buffer)");
575 /* if width > MAX_WIDTH, have to process image in chunks */
577 while (skipPixels
< width
) {
578 const GLint spanX
= x
;
580 const GLint spanWidth
= (width
- skipPixels
> MAX_WIDTH
)
581 ? MAX_WIDTH
: (width
- skipPixels
);
583 for (row
= 0; row
< height
; row
++, spanY
++) {
584 GLstencil values
[MAX_WIDTH
];
585 GLenum destType
= (sizeof(GLstencil
) == sizeof(GLubyte
))
586 ? GL_UNSIGNED_BYTE
: GL_UNSIGNED_SHORT
;
587 const GLvoid
*source
= _mesa_image_address(&ctx
->Unpack
, pixels
,
589 GL_COLOR_INDEX
, type
,
591 _mesa_unpack_index_span(ctx
, spanWidth
, destType
, values
,
592 type
, source
, &ctx
->Unpack
,
593 ctx
->_ImageTransferState
);
594 if (ctx
->_ImageTransferState
& IMAGE_SHIFT_OFFSET_BIT
) {
595 _mesa_shift_and_offset_stencil(ctx
, spanWidth
, values
);
597 if (ctx
->Pixel
.MapStencilFlag
) {
598 _mesa_map_stencil(ctx
, spanWidth
, values
);
602 _swrast_write_zoomed_stencil_span(ctx
, (GLuint
) spanWidth
,
603 spanX
, spanY
, values
, desty
, 0);
606 _swrast_write_stencil_span(ctx
, (GLuint
) spanWidth
,
607 spanX
, spanY
, values
);
610 skipPixels
+= spanWidth
;
619 draw_depth_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
620 GLsizei width
, GLsizei height
,
621 GLenum type
, const GLvoid
*pixels
)
623 const GLboolean bias_or_scale
= ctx
->Pixel
.DepthBias
!=0.0 || ctx
->Pixel
.DepthScale
!=1.0;
624 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!= 1.0 || ctx
->Pixel
.ZoomY
!= 1.0;
625 const GLint desty
= y
;
628 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_Z
);
631 && type
!= GL_UNSIGNED_BYTE
633 && type
!= GL_UNSIGNED_SHORT
635 && type
!= GL_UNSIGNED_INT
636 && type
!= GL_FLOAT
) {
637 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawPixels(type)");
641 _swrast_span_default_color(ctx
, &span
);
643 if (ctx
->Fog
.Enabled
)
644 _swrast_span_default_fog(ctx
, &span
);
645 if (ctx
->Texture
._EnabledCoordUnits
)
646 _swrast_span_default_texcoords(ctx
, &span
);
648 if (type
== GL_UNSIGNED_SHORT
&& ctx
->Visual
.depthBits
== 16
649 && !bias_or_scale
&& !zoom
&& ctx
->Visual
.rgbMode
650 && width
< MAX_WIDTH
) {
651 /* Special case: directly write 16-bit depth values */
656 for (row
= 0; row
< height
; row
++, span
.y
++) {
657 const GLushort
*zptr
= (const GLushort
*)
658 _mesa_image_address(&ctx
->Unpack
, pixels
, width
, height
,
659 GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
661 for (i
= 0; i
< width
; i
++)
662 span
.array
->z
[i
] = zptr
[i
];
663 _swrast_write_rgba_span(ctx
, &span
);
666 else if (type
== GL_UNSIGNED_INT
&& ctx
->Visual
.depthBits
== 32
667 && !bias_or_scale
&& !zoom
&& ctx
->Visual
.rgbMode
668 && width
< MAX_WIDTH
) {
669 /* Special case: directly write 32-bit depth values */
674 for (row
= 0; row
< height
; row
++, span
.y
++) {
675 const GLuint
*zptr
= (const GLuint
*)
676 _mesa_image_address(&ctx
->Unpack
, pixels
, width
, height
,
677 GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
678 MEMCPY(span
.array
->z
, zptr
, width
* sizeof(GLdepth
));
679 _swrast_write_rgba_span(ctx
, &span
);
684 GLint row
, skipPixels
= 0;
686 /* in case width > MAX_WIDTH do the copy in chunks */
687 while (skipPixels
< width
) {
688 const GLint spanX
= x
+ (zoom
? 0 : skipPixels
);
690 const GLint spanEnd
= (width
- skipPixels
> MAX_WIDTH
)
691 ? MAX_WIDTH
: (width
- skipPixels
);
692 ASSERT(span
.end
<= MAX_WIDTH
);
693 for (row
= 0; row
< height
; row
++, spanY
++) {
694 GLfloat floatSpan
[MAX_WIDTH
];
695 const GLvoid
*src
= _mesa_image_address(&ctx
->Unpack
,
696 pixels
, width
, height
,
697 GL_DEPTH_COMPONENT
, type
,
700 /* Set these for each row since the _swrast_write_* function may
701 * change them while clipping.
707 _mesa_unpack_depth_span(ctx
, span
.end
, floatSpan
, type
,
709 /* clamp depth values to [0,1] and convert from floats to ints */
711 const GLfloat zs
= ctx
->DepthMaxF
;
713 for (i
= 0; i
< span
.end
; i
++) {
714 span
.array
->z
[i
] = (GLdepth
) (floatSpan
[i
] * zs
+ 0.5F
);
718 _swrast_write_zoomed_depth_span(ctx
, &span
, desty
, skipPixels
);
720 else if (ctx
->Visual
.rgbMode
) {
721 _swrast_write_rgba_span(ctx
, &span
);
724 _swrast_write_index_span(ctx
, &span
);
727 skipPixels
+= spanEnd
;
738 draw_rgba_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
739 GLsizei width
, GLsizei height
,
740 GLenum format
, GLenum type
, const GLvoid
*pixels
)
742 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
743 const struct gl_pixelstore_attrib
*unpack
= &ctx
->Unpack
;
744 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
745 const GLint desty
= y
;
747 GLfloat
*convImage
= NULL
;
748 GLuint transferOps
= ctx
->_ImageTransferState
;
751 INIT_SPAN(span
, GL_BITMAP
, 0, 0, SPAN_RGBA
);
753 if (!_mesa_is_legal_format_and_type(format
, type
)) {
754 _mesa_error(ctx
, GL_INVALID_ENUM
, "glDrawPixels(format or type)");
758 /* Try an optimized glDrawPixels first */
759 if (fast_draw_pixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
))
763 _swrast_span_default_z(ctx
, &span
);
764 if (ctx
->Fog
.Enabled
)
765 _swrast_span_default_fog(ctx
, &span
);
766 if (ctx
->Texture
._EnabledCoordUnits
)
767 _swrast_span_default_texcoords(ctx
, &span
);
769 if (SWRAST_CONTEXT(ctx
)->_RasterMask
== 0 && !zoom
&& x
>= 0 && y
>= 0
770 && x
+ width
<= (GLint
) ctx
->DrawBuffer
->Width
771 && y
+ height
<= (GLint
) ctx
->DrawBuffer
->Height
) {
775 quickDraw
= GL_FALSE
;
778 if (ctx
->Pixel
.Convolution2DEnabled
|| ctx
->Pixel
.Separable2DEnabled
) {
779 /* Convolution has to be handled specially. We'll create an
780 * intermediate image, applying all pixel transfer operations
781 * up to convolution. Then we'll convolve the image. Then
782 * we'll proceed with the rest of the transfer operations and
783 * rasterize the image.
786 GLfloat
*dest
, *tmpImage
;
788 tmpImage
= (GLfloat
*) MALLOC(width
* height
* 4 * sizeof(GLfloat
));
790 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glDrawPixels");
793 convImage
= (GLfloat
*) MALLOC(width
* height
* 4 * sizeof(GLfloat
));
796 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glDrawPixels");
800 /* Unpack the image and apply transfer ops up to convolution */
802 for (row
= 0; row
< height
; row
++) {
803 const GLvoid
*source
= _mesa_image_address(unpack
,
804 pixels
, width
, height
, format
, type
, 0, row
, 0);
805 _mesa_unpack_color_span_float(ctx
, width
, GL_RGBA
, (GLfloat
*) dest
,
806 format
, type
, source
, unpack
,
807 transferOps
& IMAGE_PRE_CONVOLUTION_BITS
);
812 if (ctx
->Pixel
.Convolution2DEnabled
) {
813 _mesa_convolve_2d_image(ctx
, &width
, &height
, tmpImage
, convImage
);
816 ASSERT(ctx
->Pixel
.Separable2DEnabled
);
817 _mesa_convolve_sep_image(ctx
, &width
, &height
, tmpImage
, convImage
);
821 /* continue transfer ops and draw the convolved image */
822 unpack
= &_mesa_native_packing
;
826 transferOps
&= IMAGE_POST_CONVOLUTION_BITS
;
833 const GLuint interpMask
= span
.interpMask
;
834 const GLuint arrayMask
= span
.arrayMask
;
835 GLint row
, skipPixels
= 0;
837 /* if the span is wider than MAX_WIDTH we have to do it in chunks */
838 while (skipPixels
< width
) {
839 const GLint spanX
= x
+ (zoom
? 0 : skipPixels
);
841 const GLint spanEnd
= (width
- skipPixels
> MAX_WIDTH
)
842 ? MAX_WIDTH
: (width
- skipPixels
);
843 ASSERT(span
.end
<= MAX_WIDTH
);
845 for (row
= 0; row
< height
; row
++, spanY
++) {
846 const GLvoid
*source
= _mesa_image_address(unpack
,
847 pixels
, width
, height
, format
, type
, 0, row
, skipPixels
);
849 /* Set these for each row since the _swrast_write_* function may
850 * change them while clipping.
855 span
.arrayMask
= arrayMask
;
856 span
.interpMask
= interpMask
;
858 _mesa_unpack_color_span_chan(ctx
, span
.end
, GL_RGBA
,
859 (GLchan
*) span
.array
->rgba
,
860 format
, type
, source
, unpack
,
863 if ((ctx
->Pixel
.MinMaxEnabled
&& ctx
->MinMax
.Sink
) ||
864 (ctx
->Pixel
.HistogramEnabled
&& ctx
->Histogram
.Sink
))
867 if (ctx
->Pixel
.PixelTextureEnabled
&& ctx
->Texture
._EnabledUnits
) {
868 _swrast_pixel_texture(ctx
, &span
);
873 (*swrast
->Driver
.WriteRGBASpan
)(ctx
, span
.end
, span
.x
, span
.y
,
874 (CONST
GLchan (*)[4]) span
.array
->rgba
, NULL
);
877 _swrast_write_zoomed_rgba_span(ctx
, &span
,
878 (CONST
GLchan (*)[4]) span
.array
->rgba
, desty
, skipPixels
);
881 _swrast_write_rgba_span(ctx
, &span
);
885 skipPixels
+= spanEnd
;
897 * Execute glDrawPixels
900 _swrast_DrawPixels( GLcontext
*ctx
,
902 GLsizei width
, GLsizei height
,
903 GLenum format
, GLenum type
,
904 const struct gl_pixelstore_attrib
*unpack
,
905 const GLvoid
*pixels
)
907 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
910 if (swrast
->NewState
)
911 _swrast_validate_derived( ctx
);
913 RENDER_START(swrast
,ctx
);
916 case GL_STENCIL_INDEX
:
917 draw_stencil_pixels( ctx
, x
, y
, width
, height
, type
, pixels
);
919 case GL_DEPTH_COMPONENT
:
920 draw_depth_pixels( ctx
, x
, y
, width
, height
, type
, pixels
);
923 if (ctx
->Visual
.rgbMode
)
924 draw_rgba_pixels(ctx
, x
,y
, width
, height
, format
, type
, pixels
);
926 draw_index_pixels(ctx
, x
, y
, width
, height
, type
, pixels
);
933 case GL_LUMINANCE_ALPHA
:
939 draw_rgba_pixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
);
942 _mesa_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(format)" );
945 RENDER_FINISH(swrast
,ctx
);
950 #if 0 /* experimental */
952 * Execute glDrawDepthPixelsMESA().
955 _swrast_DrawDepthPixelsMESA( GLcontext
*ctx
,
957 GLsizei width
, GLsizei height
,
958 GLenum colorFormat
, GLenum colorType
,
959 const GLvoid
*colors
,
960 GLenum depthType
, const GLvoid
*depths
,
961 const struct gl_pixelstore_attrib
*unpack
)
963 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
966 if (swrast
->NewState
)
967 _swrast_validate_derived( ctx
);
969 RENDER_START(swrast
,ctx
);
971 switch (colorFormat
) {
973 if (ctx
->Visual
.rgbMode
)
974 draw_rgba_pixels(ctx
, x
,y
, width
, height
, colorFormat
, colorType
, colors
);
976 draw_index_pixels(ctx
, x
, y
, width
, height
, colorType
, colors
);
983 case GL_LUMINANCE_ALPHA
:
989 draw_rgba_pixels(ctx
, x
, y
, width
, height
, colorFormat
, colorType
, colors
);
992 _mesa_error( ctx
, GL_INVALID_ENUM
,
993 "glDrawDepthPixelsMESA(colorFormat)" );
996 RENDER_FINISH(swrast
,ctx
);