4166596ed659633cae688057eb4a7084d59e881f
1 /* $Id: drawpix.c,v 1.7 1999/11/18 15:44:37 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);
133 zoomY0
= 0; /* not used - silence compiler warning */
136 /* setup array of fragment Z value to pass to zoom function */
137 GLdepth z
= (GLdepth
) (ctx
->Current
.RasterPos
[2] * DEPTH_SCALE
);
139 assert(drawWidth
< MAX_WIDTH
);
140 for (i
=0; i
<drawWidth
; i
++)
143 /* save Y value of first row */
144 zoomY0
= (GLint
) (ctx
->Current
.RasterPos
[1] + 0.5F
);
150 * The window region at (destX, destY) of size (drawWidth, drawHeight)
151 * will be written to.
152 * We'll take pixel data from buffer pointed to by "pixels" but we'll
153 * skip "skipRows" rows and skip "skipPixels" pixels/row.
156 if (format
==GL_RGBA
&& type
==GL_UNSIGNED_BYTE
) {
157 if (ctx
->Visual
->RGBAflag
) {
158 GLubyte
*src
= (GLubyte
*) pixels
159 + (skipRows
* rowLength
+ skipPixels
) * 4;
160 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
163 for (row
=0; row
<drawHeight
; row
++) {
164 (*ctx
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
166 src
+= rowLength
* 4;
173 for (row
=0; row
<drawHeight
; row
++) {
174 gl_write_zoomed_rgba_span(ctx
, drawWidth
, destX
, destY
,
175 zSpan
, (void *) src
, zoomY0
);
176 src
+= rowLength
* 4;
183 else if (format
==GL_RGB
&& type
==GL_UNSIGNED_BYTE
) {
184 if (ctx
->Visual
->RGBAflag
) {
185 GLubyte
*src
= (GLubyte
*) pixels
186 + (skipRows
* rowLength
+ skipPixels
) * 3;
187 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
189 for (row
=0; row
<drawHeight
; row
++) {
190 (*ctx
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
192 src
+= rowLength
* 3;
199 for (row
=0; row
<drawHeight
; row
++) {
200 gl_write_zoomed_rgb_span(ctx
, drawWidth
, destX
, destY
,
201 zSpan
, (void *) src
, zoomY0
);
202 src
+= rowLength
* 3;
209 else if (format
==GL_LUMINANCE
&& type
==GL_UNSIGNED_BYTE
) {
210 if (ctx
->Visual
->RGBAflag
) {
211 GLubyte
*src
= (GLubyte
*) pixels
212 + (skipRows
* rowLength
+ skipPixels
);
213 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
216 assert(drawWidth
< MAX_WIDTH
);
217 for (row
=0; row
<drawHeight
; row
++) {
219 for (i
=0;i
<drawWidth
;i
++) {
224 (*ctx
->Driver
.WriteRGBSpan
)(ctx
, drawWidth
, destX
, destY
,
233 assert(drawWidth
< MAX_WIDTH
);
234 for (row
=0; row
<drawHeight
; row
++) {
236 for (i
=0;i
<drawWidth
;i
++) {
241 gl_write_zoomed_rgb_span(ctx
, drawWidth
, destX
, destY
,
242 zSpan
, (void *) rgb
, zoomY0
);
250 else if (format
==GL_LUMINANCE_ALPHA
&& type
==GL_UNSIGNED_BYTE
) {
251 if (ctx
->Visual
->RGBAflag
) {
252 GLubyte
*src
= (GLubyte
*) pixels
253 + (skipRows
* rowLength
+ skipPixels
)*2;
254 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
257 assert(drawWidth
< MAX_WIDTH
);
258 for (row
=0; row
<drawHeight
; row
++) {
261 for (i
=0;i
<drawWidth
;i
++) {
267 (*ctx
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
268 (void *) rgba
, NULL
);
276 assert(drawWidth
< MAX_WIDTH
);
277 for (row
=0; row
<drawHeight
; row
++) {
280 for (i
=0;i
<drawWidth
;i
++) {
286 gl_write_zoomed_rgba_span(ctx
, drawWidth
, destX
, destY
,
287 zSpan
, (void *) rgba
, zoomY0
);
295 else if (format
==GL_COLOR_INDEX
&& type
==GL_UNSIGNED_BYTE
) {
296 GLubyte
*src
= (GLubyte
*) pixels
+ skipRows
* rowLength
+ skipPixels
;
297 if (ctx
->Visual
->RGBAflag
) {
298 /* convert CI data to RGBA */
299 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
302 for (row
=0; row
<drawHeight
; row
++) {
303 assert(drawWidth
< MAX_WIDTH
);
304 gl_map_ci8_to_rgba(ctx
, drawWidth
, src
, rgba
);
305 (*ctx
->Driver
.WriteRGBASpan
)(ctx
, drawWidth
, destX
, destY
,
306 (const GLubyte (*)[4])rgba
,
316 for (row
=0; row
<drawHeight
; row
++) {
317 assert(drawWidth
< MAX_WIDTH
);
318 gl_map_ci8_to_rgba(ctx
, drawWidth
, src
, rgba
);
319 gl_write_zoomed_rgba_span(ctx
, drawWidth
, destX
, destY
,
320 zSpan
, (void *) rgba
, zoomY0
);
328 /* write CI data to CI frame buffer */
330 if (ctx
->Pixel
.ZoomX
==1.0F
&& ctx
->Pixel
.ZoomY
==1.0F
) {
332 for (row
=0; row
<drawHeight
; row
++) {
333 (*ctx
->Driver
.WriteCI8Span
)(ctx
, drawWidth
, destX
, destY
,
347 /* can't handle this pixel format and/or data type here */
352 /* can't do a simple draw, have to use slow path */
359 * Do glDrawPixels of index pixels.
362 draw_index_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
363 GLsizei width
, GLsizei height
,
364 GLenum type
, const GLvoid
*pixels
)
366 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
367 const GLint desty
= y
;
368 GLint row
, drawWidth
;
369 GLdepth zspan
[MAX_WIDTH
];
371 drawWidth
= (width
> MAX_WIDTH
) ? MAX_WIDTH
: width
;
373 /* Fragment depth values */
374 if (ctx
->Depth
.Test
) {
375 GLdepth zval
= (GLdepth
) (ctx
->Current
.RasterPos
[2] * DEPTH_SCALE
);
377 for (i
= 0; i
< drawWidth
; i
++) {
385 for (row
= 0; row
< height
; row
++, y
++) {
386 GLuint indexes
[MAX_WIDTH
];
387 const GLvoid
*source
= gl_pixel_addr_in_image(&ctx
->Unpack
,
388 pixels
, width
, height
, GL_COLOR_INDEX
, type
, 0, row
, 0);
389 _mesa_unpack_index_span(ctx
, drawWidth
, GL_UNSIGNED_INT
, indexes
,
390 type
, source
, &ctx
->Unpack
, GL_TRUE
);
392 gl_write_zoomed_index_span(ctx
, drawWidth
, x
, y
, zspan
, indexes
, desty
);
395 gl_write_index_span(ctx
, drawWidth
, x
, y
, zspan
, indexes
, GL_BITMAP
);
403 * Do glDrawPixels of stencil image. The image datatype may either
404 * be GLubyte or GLbitmap.
407 draw_stencil_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
408 GLsizei width
, GLsizei height
,
409 GLenum type
, const GLvoid
*pixels
)
411 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
412 const GLint desty
= y
;
413 GLint row
, drawWidth
;
415 if (type
!= GL_BYTE
&&
416 type
!= GL_UNSIGNED_BYTE
&&
418 type
!= GL_UNSIGNED_SHORT
&&
420 type
!= GL_UNSIGNED_INT
&&
423 gl_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(stencil type)");
427 drawWidth
= (width
> MAX_WIDTH
) ? MAX_WIDTH
: width
;
429 for (row
= 0; row
< height
; row
++, y
++) {
430 GLstencil values
[MAX_WIDTH
];
431 GLenum destType
= (sizeof(GLstencil
) == sizeof(GLubyte
))
432 ? GL_UNSIGNED_BYTE
: GL_UNSIGNED_SHORT
;
433 const GLvoid
*source
= gl_pixel_addr_in_image(&ctx
->Unpack
,
434 pixels
, width
, height
, GL_COLOR_INDEX
, type
, 0, row
, 0);
435 _mesa_unpack_index_span(ctx
, drawWidth
, destType
, values
,
436 type
, source
, &ctx
->Unpack
, GL_TRUE
);
439 gl_write_zoomed_stencil_span( ctx
, (GLuint
) drawWidth
, x
, y
,
443 gl_write_stencil_span( ctx
, (GLuint
) drawWidth
, x
, y
, values
);
451 * Do a glDrawPixels of depth values.
454 draw_depth_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
455 GLsizei width
, GLsizei height
,
456 GLenum type
, const GLvoid
*pixels
)
458 const GLboolean bias_or_scale
= ctx
->Pixel
.DepthBias
!=0.0 || ctx
->Pixel
.DepthScale
!=1.0;
459 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
460 const GLint desty
= y
;
461 GLubyte rgba
[MAX_WIDTH
][4];
462 GLuint ispan
[MAX_WIDTH
];
463 GLint drawWidth
= (width
> MAX_WIDTH
) ? MAX_WIDTH
: width
;
465 if (type
!= GL_UNSIGNED_BYTE
466 && type
!= GL_UNSIGNED_BYTE
467 && type
!= GL_UNSIGNED_SHORT
468 && type
!= GL_UNSIGNED_SHORT
469 && type
!= GL_UNSIGNED_INT
470 && type
!= GL_UNSIGNED_INT
471 && type
!= GL_FLOAT
) {
472 gl_error(ctx
, GL_INVALID_ENUM
, "glDrawPixels(type)");
476 /* Colors or indexes */
477 if (ctx
->Visual
->RGBAflag
) {
478 GLint r
= (GLint
) (ctx
->Current
.RasterColor
[0] * 255.0F
);
479 GLint g
= (GLint
) (ctx
->Current
.RasterColor
[1] * 255.0F
);
480 GLint b
= (GLint
) (ctx
->Current
.RasterColor
[2] * 255.0F
);
481 GLint a
= (GLint
) (ctx
->Current
.RasterColor
[3] * 255.0F
);
483 for (i
= 0; i
< drawWidth
; i
++) {
492 for (i
= 0; i
< drawWidth
; i
++) {
493 ispan
[i
] = ctx
->Current
.RasterIndex
;
497 if (type
==GL_UNSIGNED_SHORT
&& sizeof(GLdepth
)==sizeof(GLushort
)
498 && !bias_or_scale
&& !zoom
&& ctx
->Visual
->RGBAflag
) {
499 /* Special case: directly write 16-bit depth values */
501 for (row
= 0; row
< height
; row
++, y
++) {
502 const GLdepth
*zptr
= gl_pixel_addr_in_image(&ctx
->Unpack
,
503 pixels
, width
, height
, GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
504 gl_write_rgba_span( ctx
, width
, x
, y
, zptr
, rgba
, GL_BITMAP
);
507 else if (type
==GL_UNSIGNED_INT
&& sizeof(GLdepth
)==sizeof(GLuint
)
508 && !bias_or_scale
&& !zoom
&& ctx
->Visual
->RGBAflag
) {
509 /* Special case: directly write 32-bit depth values */
511 /* Compute shift value to scale 32-bit uints down to depth values. */
513 GLuint max
= MAX_DEPTH
;
514 while ((max
& 0x80000000) == 0) {
518 for (row
= 0; row
< height
; row
++, y
++) {
519 GLdepth zspan
[MAX_WIDTH
];
520 const GLdepth
*zptr
= gl_pixel_addr_in_image(&ctx
->Unpack
,
521 pixels
, width
, height
, GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
522 for (i
=0;i
<width
;i
++) {
523 zspan
[i
] = zptr
[i
] >> shift
;
525 gl_write_rgba_span( ctx
, width
, x
, y
, zspan
, rgba
, GL_BITMAP
);
531 for (row
= 0; row
< height
; row
++, y
++) {
532 GLdepth zspan
[MAX_WIDTH
];
533 const GLvoid
*src
= gl_pixel_addr_in_image(&ctx
->Unpack
,
534 pixels
, width
, height
, GL_DEPTH_COMPONENT
, type
, 0, row
, 0);
535 _mesa_unpack_depth_span( ctx
, drawWidth
, zspan
, type
, src
,
536 &ctx
->Unpack
, GL_TRUE
);
537 if (ctx
->Visual
->RGBAflag
) {
539 gl_write_zoomed_rgba_span(ctx
, width
, x
, y
, zspan
,
540 (const GLubyte (*)[4])rgba
, desty
);
543 gl_write_rgba_span(ctx
, width
, x
, y
, zspan
, rgba
, GL_BITMAP
);
548 gl_write_zoomed_index_span(ctx
, width
, x
, y
, zspan
,
552 gl_write_index_span(ctx
, width
, x
, y
, zspan
, ispan
, GL_BITMAP
);
562 * Do glDrawPixels of RGBA pixels.
565 draw_rgba_pixels( GLcontext
*ctx
, GLint x
, GLint y
,
566 GLsizei width
, GLsizei height
,
567 GLenum format
, GLenum type
, const GLvoid
*pixels
)
569 const struct gl_pixelstore_attrib
*unpack
= &ctx
->Unpack
;
570 const GLboolean zoom
= ctx
->Pixel
.ZoomX
!=1.0 || ctx
->Pixel
.ZoomY
!=1.0;
571 const GLint desty
= y
;
572 GLdepth zspan
[MAX_WIDTH
];
575 /* Try an optimized glDrawPixels first */
576 if (simple_DrawPixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
))
579 /* Fragment depth values */
580 if (ctx
->Depth
.Test
) {
581 /* fill in array of z values */
582 GLdepth z
= (GLdepth
) (ctx
->Current
.RasterPos
[2] * DEPTH_SCALE
);
584 for (i
=0;i
<width
;i
++) {
590 if (ctx
->RasterMask
== 0 && !zoom
592 && x
+ width
<= ctx
->Buffer
->Width
593 && y
+ height
<= ctx
->Buffer
->Height
) {
597 quickDraw
= GL_FALSE
;
604 GLubyte rgba
[MAX_WIDTH
][4];
606 if (width
> MAX_WIDTH
)
608 for (row
= 0; row
< height
; row
++, y
++) {
609 const GLvoid
*source
= gl_pixel_addr_in_image(unpack
,
610 pixels
, width
, height
, format
, type
, 0, row
, 0);
611 _mesa_unpack_ubyte_color_span(ctx
, width
, GL_RGBA
, (void*) rgba
,
612 format
, type
, source
, unpack
, GL_TRUE
);
615 (*ctx
->Driver
.WriteRGBASpan
)( ctx
, width
, x
, y
,
616 (CONST
GLubyte (*)[]) rgba
, NULL
);
619 gl_write_zoomed_rgba_span( ctx
, width
, x
, y
, zspan
,
620 (CONST
GLubyte (*)[]) rgba
, desty
);
623 gl_write_rgba_span( ctx
, (GLuint
) width
, x
, y
, zspan
, rgba
, GL_BITMAP
);
632 * Execute glDrawPixels
635 _mesa_DrawPixels( GLsizei width
, GLsizei height
,
636 GLenum format
, GLenum type
, const GLvoid
*pixels
)
638 GET_CURRENT_CONTEXT(ctx
);
639 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glDrawPixels");
641 if (ctx
->RenderMode
==GL_RENDER
) {
643 if (!pixels
|| !ctx
->Current
.RasterPosValid
) {
647 x
= (GLint
) (ctx
->Current
.RasterPos
[0] + 0.5F
);
648 y
= (GLint
) (ctx
->Current
.RasterPos
[1] + 0.5F
);
651 case GL_STENCIL_INDEX
:
652 draw_stencil_pixels( ctx
, x
, y
, width
, height
, type
, pixels
);
654 case GL_DEPTH_COMPONENT
:
655 draw_depth_pixels( ctx
, x
, y
, width
, height
, type
, pixels
);
658 if (ctx
->Visual
->RGBAflag
)
659 draw_index_pixels(ctx
, x
, y
, width
, height
, type
, pixels
);
661 draw_rgba_pixels(ctx
, x
,y
, width
, height
, format
, type
, pixels
);
668 case GL_LUMINANCE_ALPHA
:
674 draw_rgba_pixels(ctx
, x
, y
, width
, height
, format
, type
, pixels
);
677 gl_error( ctx
, GL_INVALID_ENUM
, "glDrawPixels(format)" );
681 else if (ctx
->RenderMode
==GL_FEEDBACK
) {
682 if (ctx
->Current
.RasterPosValid
) {
684 GLfloat texcoord
[4], invq
;
685 UBYTE_RGBA_TO_FLOAT_RGBA(color
, ctx
->Current
.ByteColor
);
686 invq
= 1.0F
/ ctx
->Current
.Texcoord
[0][3];
687 texcoord
[0] = ctx
->Current
.Texcoord
[0][0] * invq
;
688 texcoord
[1] = ctx
->Current
.Texcoord
[0][1] * invq
;
689 texcoord
[2] = ctx
->Current
.Texcoord
[0][2] * invq
;
690 texcoord
[3] = ctx
->Current
.Texcoord
[0][3];
691 FEEDBACK_TOKEN( ctx
, (GLfloat
) (GLint
) GL_DRAW_PIXEL_TOKEN
);
692 gl_feedback_vertex( ctx
,
693 ctx
->Current
.RasterPos
,
694 color
, ctx
->Current
.Index
, texcoord
);
697 else if (ctx
->RenderMode
==GL_SELECT
) {
698 if (ctx
->Current
.RasterPosValid
) {
699 gl_update_hitflag( ctx
, ctx
->Current
.RasterPos
[2] );