1 /* $Id: drawpix.c,v 1.6 1999/11/11 01:22:26 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
48 * Try to do a fast and simple RGB(a) glDrawPixels.
49 * Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
52 simple_DrawPixels( GLcontext
*ctx
, GLint x
, GLint y
,
53 GLsizei width
, GLsizei height
, GLenum format
, GLenum type
,
54 const GLvoid
*pixels
)
56 const struct gl_pixelstore_attrib
*unpack
= &ctx
->Unpack
;
57 GLubyte rgb
[MAX_WIDTH
][3];
58 GLubyte rgba
[MAX_WIDTH
][4];
60 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx
, "glDrawPixels",
64 if (!ctx
->Current
.RasterPosValid
) {
73 /* see if device driver can do the drawpix */
74 if (ctx
->Driver
.DrawPixels
75 && (*ctx
->Driver
.DrawPixels
)(ctx
, x
, y
, width
, height
, format
, type
,
80 if ((ctx
->RasterMask
&(~(SCISSOR_BIT
|WINCLIP_BIT
)))==0
81 && ctx
->Pixel
.RedBias
==0.0 && ctx
->Pixel
.RedScale
==1.0
82 && ctx
->Pixel
.GreenBias
==0.0 && ctx
->Pixel
.GreenScale
==1.0
83 && ctx
->Pixel
.BlueBias
==0.0 && ctx
->Pixel
.BlueScale
==1.0
84 && ctx
->Pixel
.AlphaBias
==0.0 && ctx
->Pixel
.AlphaScale
==1.0
85 && ctx
->Pixel
.IndexShift
==0 && ctx
->Pixel
.IndexOffset
==0
86 && ctx
->Pixel
.MapColorFlag
==0
87 && unpack
->Alignment
==1
89 && !unpack
->LsbFirst
) {
93 GLint drawWidth
= width
; /* actual width drawn */
94 GLint drawHeight
= height
; /* actual height drawn */
95 GLint skipPixels
= unpack
->SkipPixels
;
96 GLint skipRows
= unpack
->SkipRows
;
98 GLdepth zSpan
[MAX_WIDTH
]; /* only used when zooming */
101 if (unpack
->RowLength
> 0)
102 rowLength
= unpack
->RowLength
;
106 /* If we're not using pixel zoom then do all clipping calculations
107 * now. Otherwise, we'll let the gl_write_zoomed_*_span() functions
108 * handle the clipping.
110 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
111 /* horizontal clipping */
112 if (destX
< ctx
->Buffer
->Xmin
) {
113 skipPixels
+= (ctx
->Buffer
->Xmin
- destX
);
114 drawWidth
-= (ctx
->Buffer
->Xmin
- destX
);
115 destX
= ctx
->Buffer
->Xmin
;
117 if (destX
+ drawWidth
> ctx
->Buffer
->Xmax
)
118 drawWidth
-= (destX
+ drawWidth
- ctx
->Buffer
->Xmax
- 1);
122 /* vertical clipping */
123 if (destY
< ctx
->Buffer
->Ymin
) {
124 skipRows
+= (ctx
->Buffer
->Ymin
- destY
);
125 drawHeight
-= (ctx
->Buffer
->Ymin
- destY
);
126 destY
= ctx
->Buffer
->Ymin
;
128 if (destY
+ drawHeight
> ctx
->Buffer
->Ymax
)
129 drawHeight
-= (destY
+ drawHeight
- ctx
->Buffer
->Ymax
- 1);
134 /* setup array of fragment Z value to pass to zoom function */
135 GLdepth z
= (GLdepth
) (ctx
->Current
.RasterPos
[2] * DEPTH_SCALE
);
137 assert(drawWidth
< MAX_WIDTH
);
138 for (i
=0; i
<drawWidth
; i
++)
141 /* save Y value of first row */
142 zoomY0
= (GLint
) (ctx
->Current
.RasterPos
[1] + 0.5F
);
148 * The window region at (destX, destY) of size (drawWidth, drawHeight)
149 * will be written to.
150 * We'll take pixel data from buffer pointed to by "pixels" but we'll
151 * skip "skipRows" rows and skip "skipPixels" pixels/row.
154 if (format
==GL_RGBA
&& type
==GL_UNSIGNED_BYTE
) {
155 if (ctx
->Visual
->RGBAflag
) {
156 GLubyte
*src
= (GLubyte
*) pixels
157 + (skipRows
* rowLength
+ skipPixels
) * 4;
158 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
161 for (row
=0; row
<drawHeight
; row
++) {
162 (*ctx
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
164 src
+= rowLength
* 4;
171 for (row
=0; row
<drawHeight
; row
++) {
172 gl_write_zoomed_rgba_span(ctx
, drawWidth
, destX
, destY
,
173 zSpan
, (void *) src
, zoomY0
);
174 src
+= rowLength
* 4;
181 else if (format
==GL_RGB
&& type
==GL_UNSIGNED_BYTE
) {
182 if (ctx
->Visual
->RGBAflag
) {
183 GLubyte
*src
= (GLubyte
*) pixels
184 + (skipRows
* rowLength
+ skipPixels
) * 3;
185 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
187 for (row
=0; row
<drawHeight
; row
++) {
188 (*ctx
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
190 src
+= rowLength
* 3;
197 for (row
=0; row
<drawHeight
; row
++) {
198 gl_write_zoomed_rgb_span(ctx
, drawWidth
, destX
, destY
,
199 zSpan
, (void *) src
, zoomY0
);
200 src
+= rowLength
* 3;
207 else if (format
==GL_LUMINANCE
&& type
==GL_UNSIGNED_BYTE
) {
208 if (ctx
->Visual
->RGBAflag
) {
209 GLubyte
*src
= (GLubyte
*) pixels
210 + (skipRows
* rowLength
+ skipPixels
);
211 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
214 assert(drawWidth
< MAX_WIDTH
);
215 for (row
=0; row
<drawHeight
; row
++) {
217 for (i
=0;i
<drawWidth
;i
++) {
222 (*ctx
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
231 assert(drawWidth
< MAX_WIDTH
);
232 for (row
=0; row
<drawHeight
; row
++) {
234 for (i
=0;i
<drawWidth
;i
++) {
239 gl_write_zoomed_rgb_span(ctx
, drawWidth
, destX
, destY
,
240 zSpan
, (void *) rgb
, zoomY0
);
248 else if (format
==GL_LUMINANCE_ALPHA
&& type
==GL_UNSIGNED_BYTE
) {
249 if (ctx
->Visual
->RGBAflag
) {
250 GLubyte
*src
= (GLubyte
*) pixels
251 + (skipRows
* rowLength
+ skipPixels
)*2;
252 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
255 assert(drawWidth
< MAX_WIDTH
);
256 for (row
=0; row
<drawHeight
; row
++) {
259 for (i
=0;i
<drawWidth
;i
++) {
265 (*ctx
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
266 (void *) rgba
, NULL
);
274 assert(drawWidth
< MAX_WIDTH
);
275 for (row
=0; row
<drawHeight
; row
++) {
278 for (i
=0;i
<drawWidth
;i
++) {
284 gl_write_zoomed_rgba_span(ctx
, drawWidth
, destX
, destY
,
285 zSpan
, (void *) rgba
, zoomY0
);
293 else if (format
==GL_COLOR_INDEX
&& type
==GL_UNSIGNED_BYTE
) {
294 GLubyte
*src
= (GLubyte
*) pixels
+ skipRows
* rowLength
+ skipPixels
;
295 if (ctx
->Visual
->RGBAflag
) {
296 /* convert CI data to RGBA */
297 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
300 for (row
=0; row
<drawHeight
; row
++) {
301 assert(drawWidth
< MAX_WIDTH
);
302 gl_map_ci8_to_rgba(ctx
, drawWidth
, src
, rgba
);
303 (*ctx
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
304 (const GLubyte (*)[4])rgba
,
314 for (row
=0; row
<drawHeight
; row
++) {
315 assert(drawWidth
< MAX_WIDTH
);
316 gl_map_ci8_to_rgba(ctx
, drawWidth
, src
, rgba
);
317 gl_write_zoomed_rgba_span(ctx
, drawWidth
, destX
, destY
,
318 zSpan
, (void *) rgba
, zoomY0
);
326 /* write CI data to CI frame buffer */
328 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
330 for (row
=0; row
<drawHeight
; row
++) {
331 (*ctx
->Driver
.WriteCI8Span
)(ctx
, drawWidth
, destX
, destY
,
345 /* can't handle this pixel format and/or data type here */
350 /* can't do a simple draw, have to use slow path */
357 * Do glDrawPixels of index pixels.
360 draw_index_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
361 GLsizei width
, GLsizei height
,
362 GLenum type
, const GLvoid
*pixels
)
364 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
365 const GLint desty
= y
;
366 GLint row
, drawWidth
;
367 GLdepth zspan
[MAX_WIDTH
];
369 drawWidth
= (width
> MAX_WIDTH
) ? MAX_WIDTH
: width
;
371 /* Fragment depth values */
372 if (ctx
->Depth
.Test
) {
373 GLdepth zval
= (GLdepth
) (ctx
->Current
.RasterPos
[2] * DEPTH_SCALE
);
375 for (i
= 0; i
< drawWidth
; i
++) {
383 for (row
= 0; row
< height
; row
++, y
++) {
384 GLuint indexes
[MAX_WIDTH
];
385 const GLvoid
*source
= gl_pixel_addr_in_image(&ctx
->Unpack
,
386 pixels
, width
, height
, GL_COLOR_INDEX
, type
, 0, row
, 0);
387 _mesa_unpack_index_span(ctx
, drawWidth
, GL_UNSIGNED_INT
, indexes
,
388 type
, source
, &ctx
->Unpack
, GL_TRUE
);
390 gl_write_zoomed_index_span(ctx
, drawWidth
, x
, y
, zspan
, indexes
, desty
);
393 gl_write_index_span(ctx
, drawWidth
, x
, y
, zspan
, indexes
, GL_BITMAP
);
401 * Do glDrawPixels of stencil image. The image datatype may either
402 * be GLubyte or GLbitmap.
405 draw_stencil_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
406 GLsizei width
, GLsizei height
,
407 GLenum type
, const GLvoid
*pixels
)
409 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
410 const GLint desty
= y
;
411 GLint row
, drawWidth
;
413 if (type
!= GL_BYTE
&&
414 type
!= GL_UNSIGNED_BYTE
&&
416 type
!= GL_UNSIGNED_SHORT
&&
418 type
!= GL_UNSIGNED_INT
&&
421 gl_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(stencil type)");
425 drawWidth
= (width
> MAX_WIDTH
) ? MAX_WIDTH
: width
;
427 for (row
= 0; row
< height
; row
++, y
++) {
428 GLstencil values
[MAX_WIDTH
];
429 GLenum destType
= (sizeof(GLstencil
) == sizeof(GLubyte
))
430 ? GL_UNSIGNED_BYTE
: GL_UNSIGNED_SHORT
;
431 const GLvoid
*source
= gl_pixel_addr_in_image(&ctx
->Unpack
,
432 pixels
, width
, height
, GL_COLOR_INDEX
, type
, 0, row
, 0);
433 _mesa_unpack_index_span(ctx
, drawWidth
, destType
, values
,
434 type
, source
, &ctx
->Unpack
, GL_TRUE
);
437 gl_write_zoomed_stencil_span( ctx
, (GLuint
) drawWidth
, x
, y
,
441 gl_write_stencil_span( ctx
, (GLuint
) drawWidth
, x
, y
, values
);
449 * Do a glDrawPixels of depth values.
452 draw_depth_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
453 GLsizei width
, GLsizei height
,
454 GLenum type
, const GLvoid
*pixels
)
456 const GLboolean bias_or_scale
= ctx
->Pixel
.DepthBias
!=0.0 || ctx
->Pixel
.DepthScale
!=1.0;
457 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
458 const GLint desty
= y
;
459 GLubyte rgba
[MAX_WIDTH
][4];
460 GLuint ispan
[MAX_WIDTH
];
461 GLint drawWidth
= (width
> MAX_WIDTH
) ? MAX_WIDTH
: width
;
463 if (type
!= GL_UNSIGNED_BYTE
464 && type
!= GL_UNSIGNED_BYTE
465 && type
!= GL_UNSIGNED_SHORT
466 && type
!= GL_UNSIGNED_SHORT
467 && type
!= GL_UNSIGNED_INT
468 && type
!= GL_UNSIGNED_INT
469 && type
!= GL_FLOAT
) {
470 gl_error(ctx
, GL_INVALID_ENUM
, "glDrawPixels(type)");
474 /* Colors or indexes */
475 if (ctx
->Visual
->RGBAflag
) {
476 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0F
);
477 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0F
);
478 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0F
);
479 GLint a
= (GLint
) (ctx
->Current
.RasterColor
[3] * 255.0F
);
481 for (i
= 0; i
< drawWidth
; i
++) {
490 for (i
= 0; i
< drawWidth
; i
++) {
491 ispan
[i
] = ctx
->Current
.RasterIndex
;
495 if (type
==GL_UNSIGNED_SHORT
&& sizeof(GLdepth
)==sizeof(GLushort
)
496 && !bias_or_scale
&& !zoom
&& ctx
->Visual
->RGBAflag
) {
497 /* Special case: directly write 16-bit depth values */
499 for (row
= 0; row
< height
; row
++, y
++) {
500 const GLdepth
*zptr
= gl_pixel_addr_in_image(&ctx
->Unpack
,
501 pixels
, width
, height
, GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
502 gl_write_rgba_span( ctx
, width
, x
, y
, zptr
, rgba
, GL_BITMAP
);
505 else if (type
==GL_UNSIGNED_INT
&& sizeof(GLdepth
)==sizeof(GLuint
)
506 && !bias_or_scale
&& !zoom
&& ctx
->Visual
->RGBAflag
) {
507 /* Special case: directly write 32-bit depth values */
509 /* Compute shift value to scale 32-bit uints down to depth values. */
511 GLuint max
= MAX_DEPTH
;
512 while ((max
& 0x80000000) == 0) {
516 for (row
= 0; row
< height
; row
++, y
++) {
517 GLdepth zspan
[MAX_WIDTH
];
518 const GLdepth
*zptr
= gl_pixel_addr_in_image(&ctx
->Unpack
,
519 pixels
, width
, height
, GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
520 for (i
=0;i
<width
;i
++) {
521 zspan
[i
] = zptr
[i
] >> shift
;
523 gl_write_rgba_span( ctx
, width
, x
, y
, zspan
, rgba
, GL_BITMAP
);
529 for (row
= 0; row
< height
; row
++, y
++) {
530 GLdepth zspan
[MAX_WIDTH
];
531 const GLvoid
*src
= gl_pixel_addr_in_image(&ctx
->Unpack
,
532 pixels
, width
, height
, GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
533 _mesa_unpack_depth_span( ctx
, drawWidth
, zspan
, type
, src
,
534 &ctx
->Unpack
, GL_TRUE
);
535 if (ctx
->Visual
->RGBAflag
) {
537 gl_write_zoomed_rgba_span(ctx
, width
, x
, y
, zspan
,
538 (const GLubyte (*)[4])rgba
, desty
);
541 gl_write_rgba_span(ctx
, width
, x
, y
, zspan
, rgba
, GL_BITMAP
);
546 gl_write_zoomed_index_span(ctx
, width
, x
, y
, zspan
,
550 gl_write_index_span(ctx
, width
, x
, y
, zspan
, ispan
, GL_BITMAP
);
560 * Do glDrawPixels of RGBA pixels.
563 draw_rgba_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
564 GLsizei width
, GLsizei height
,
565 GLenum format
, GLenum type
, const GLvoid
*pixels
)
567 const struct gl_pixelstore_attrib
*unpack
= &ctx
->Unpack
;
568 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
569 const GLint desty
= y
;
570 GLdepth zspan
[MAX_WIDTH
];
573 /* Try an optimized glDrawPixels first */
574 if (simple_DrawPixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
))
577 /* Fragment depth values */
578 if (ctx
->Depth
.Test
) {
579 /* fill in array of z values */
580 GLdepth z
= (GLdepth
) (ctx
->Current
.RasterPos
[2] * DEPTH_SCALE
);
582 for (i
=0;i
<width
;i
++) {
588 if (ctx
->RasterMask
== 0 && !zoom
590 && x
+ width
<= ctx
->Buffer
->Width
591 && y
+ height
<= ctx
->Buffer
->Height
) {
595 quickDraw
= GL_FALSE
;
602 GLubyte rgba
[MAX_WIDTH
][4];
604 if (width
> MAX_WIDTH
)
606 for (row
= 0; row
< height
; row
++, y
++) {
607 const GLvoid
*source
= gl_pixel_addr_in_image(unpack
,
608 pixels
, width
, height
, format
, type
, 0, row
, 0);
609 _mesa_unpack_ubyte_color_span(ctx
, width
, GL_RGBA
, (void*) rgba
,
610 format
, type
, source
, unpack
, GL_TRUE
);
613 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, width
, x
, y
,
614 (CONST
GLubyte (*)[]) rgba
, NULL
);
617 gl_write_zoomed_rgba_span( ctx
, width
, x
, y
, zspan
,
618 (CONST
GLubyte (*)[]) rgba
, desty
);
621 gl_write_rgba_span( ctx
, (GLuint
) width
, x
, y
, zspan
, rgba
, GL_BITMAP
);
630 * Execute glDrawPixels
633 _mesa_DrawPixels( GLsizei width
, GLsizei height
,
634 GLenum format
, GLenum type
, const GLvoid
*pixels
)
636 GET_CURRENT_CONTEXT(ctx
);
637 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glDrawPixels");
639 if (ctx
->RenderMode
==GL_RENDER
) {
641 if (!pixels
|| !ctx
->Current
.RasterPosValid
) {
645 x
= (GLint
) (ctx
->Current
.RasterPos
[0] + 0.5F
);
646 y
= (GLint
) (ctx
->Current
.RasterPos
[1] + 0.5F
);
649 case GL_STENCIL_INDEX
:
650 draw_stencil_pixels( ctx
, x
, y
, width
, height
, type
, pixels
);
652 case GL_DEPTH_COMPONENT
:
653 draw_depth_pixels( ctx
, x
, y
, width
, height
, type
, pixels
);
656 if (ctx
->Visual
->RGBAflag
)
657 draw_index_pixels(ctx
, x
, y
, width
, height
, type
, pixels
);
659 draw_rgba_pixels(ctx
, x
,y
, width
, height
, format
, type
, pixels
);
666 case GL_LUMINANCE_ALPHA
:
672 draw_rgba_pixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
);
675 gl_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(format)" );
679 else if (ctx
->RenderMode
==GL_FEEDBACK
) {
680 if (ctx
->Current
.RasterPosValid
) {
682 GLfloat texcoord
[4], invq
;
683 UBYTE_RGBA_TO_FLOAT_RGBA(color
, ctx
->Current
.ByteColor
);
684 invq
= 1.0F
/ ctx
->Current
.Texcoord
[0][3];
685 texcoord
[0] = ctx
->Current
.Texcoord
[0][0] * invq
;
686 texcoord
[1] = ctx
->Current
.Texcoord
[0][1] * invq
;
687 texcoord
[2] = ctx
->Current
.Texcoord
[0][2] * invq
;
688 texcoord
[3] = ctx
->Current
.Texcoord
[0][3];
689 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_DRAW_PIXEL_TOKEN
);
690 gl_feedback_vertex( ctx
,
691 ctx
->Current
.RasterPos
,
692 color
, ctx
->Current
.Index
, texcoord
);
695 else if (ctx
->RenderMode
==GL_SELECT
) {
696 if (ctx
->Current
.RasterPosValid
) {
697 gl_update_hitflag( ctx
, ctx
->Current
.RasterPos
[2] );