2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2005 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.
30 #include "s_context.h"
32 #include "s_stencil.h"
37 * Helper function called from _swrast_write_zoomed_rgba/rgb/index_span().
40 zoom_span( GLcontext
*ctx
, const struct sw_span
*span
,
41 const GLvoid
*src
, GLint y0
, GLenum format
, GLint skipPixels
)
44 GLint c0
, c1
, skipCol
;
46 const GLuint maxWidth
= MIN2( ctx
->DrawBuffer
->Width
, MAX_WIDTH
);
47 struct sw_span zoomed
;
48 struct span_arrays zoomed_arrays
; /* this is big! */
50 /* no pixel arrays! must be horizontal spans. */
51 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
52 ASSERT(span
->primitive
== GL_BITMAP
);
54 INIT_SPAN(zoomed
, GL_BITMAP
, 0, 0, 0);
55 zoomed
.array
= &zoomed_arrays
;
57 /* copy fog interp info */
58 zoomed
.fog
= span
->fog
;
59 zoomed
.fogStep
= span
->fogStep
;
60 /* XXX copy texcoord info? */
62 if (format
== GL_RGBA
|| format
== GL_RGB
) {
65 zoomed
.zStep
= span
->zStep
;
66 /* we'll generate an array of colorss */
67 zoomed
.interpMask
= span
->interpMask
& ~SPAN_RGBA
;
68 zoomed
.arrayMask
|= SPAN_RGBA
;
70 else if (format
== GL_COLOR_INDEX
) {
73 zoomed
.zStep
= span
->zStep
;
74 /* we'll generate an array of color indexes */
75 zoomed
.interpMask
= span
->interpMask
& ~SPAN_INDEX
;
76 zoomed
.arrayMask
|= SPAN_INDEX
;
78 else if (format
== GL_DEPTH_COMPONENT
) {
80 zoomed
.red
= span
->red
;
81 zoomed
.green
= span
->green
;
82 zoomed
.blue
= span
->blue
;
83 zoomed
.alpha
= span
->alpha
;
84 zoomed
.redStep
= span
->redStep
;
85 zoomed
.greenStep
= span
->greenStep
;
86 zoomed
.blueStep
= span
->blueStep
;
87 zoomed
.alphaStep
= span
->alphaStep
;
88 /* we'll generate an array of depth values */
89 zoomed
.interpMask
= span
->interpMask
& ~SPAN_Z
;
90 zoomed
.arrayMask
|= SPAN_Z
;
92 else if (format
== GL_DEPTH_COMPONENT16
||
93 format
== GL_DEPTH_COMPONENT32
) {
94 /* writing Z values directly to depth buffer, bypassing fragment ops */
97 _mesa_problem(ctx
, "Bad format in zoom_span");
102 * Compute which columns to draw: [c0, c1)
104 c0
= (GLint
) (span
->x
+ skipPixels
* ctx
->Pixel
.ZoomX
);
105 c1
= (GLint
) (span
->x
+ (skipPixels
+ span
->end
) * ctx
->Pixel
.ZoomX
);
124 zoomed
.end
= c1
- c0
;
127 if (zoomed
.end
> maxWidth
)
128 zoomed
.end
= maxWidth
;
131 * Compute which rows to draw: [r0, r1)
134 r0
= y0
+ (GLint
) (row
* ctx
->Pixel
.ZoomY
);
135 r1
= y0
+ (GLint
) ((row
+1) * ctx
->Pixel
.ZoomY
);
150 * Trivial clip rejection testing.
152 if (r1
< 0) /* below window */
154 if (r0
>= (GLint
) ctx
->DrawBuffer
->Height
) /* above window */
156 if (c1
< 0) /* left of window */
158 if (c0
>= (GLint
) ctx
->DrawBuffer
->Width
) /* right of window */
161 /* zoom the span horizontally */
162 if (format
== GL_RGBA
) {
163 const GLchan (*rgba
)[4] = (const GLchan (*)[4]) src
;
164 if (ctx
->Pixel
.ZoomX
== -1.0F
) {
166 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
167 i
= span
->end
- (j
+ skipCol
) - 1;
168 COPY_CHAN4(zoomed
.array
->rgba
[j
], rgba
[i
]);
172 /* general solution */
173 const GLfloat xscale
= 1.0F
/ ctx
->Pixel
.ZoomX
;
174 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
175 i
= (GLint
) ((j
+ skipCol
) * xscale
);
176 if (ctx
->Pixel
.ZoomX
< 0.0) {
178 i
= span
->end
+ i
- 1;
181 ASSERT(i
< (GLint
) span
->end
);
182 COPY_CHAN4(zoomed
.array
->rgba
[j
], rgba
[i
]);
186 else if (format
== GL_RGB
) {
187 const GLchan (*rgb
)[3] = (const GLchan (*)[3]) src
;
188 if (ctx
->Pixel
.ZoomX
== -1.0F
) {
190 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
191 i
= span
->end
- (j
+ skipCol
) - 1;
192 zoomed
.array
->rgba
[j
][0] = rgb
[i
][0];
193 zoomed
.array
->rgba
[j
][1] = rgb
[i
][1];
194 zoomed
.array
->rgba
[j
][2] = rgb
[i
][2];
195 zoomed
.array
->rgba
[j
][3] = CHAN_MAX
;
199 /* general solution */
200 const GLfloat xscale
= 1.0F
/ ctx
->Pixel
.ZoomX
;
201 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
202 i
= (GLint
) ((j
+ skipCol
) * xscale
);
203 if (ctx
->Pixel
.ZoomX
< 0.0) {
205 i
= span
->end
+ i
- 1;
208 ASSERT(i
< (GLint
) span
->end
);
209 zoomed
.array
->rgba
[j
][0] = rgb
[i
][0];
210 zoomed
.array
->rgba
[j
][1] = rgb
[i
][1];
211 zoomed
.array
->rgba
[j
][2] = rgb
[i
][2];
212 zoomed
.array
->rgba
[j
][3] = CHAN_MAX
;
216 else if (format
== GL_COLOR_INDEX
) {
217 const GLuint
*indexes
= (const GLuint
*) src
;
218 if (ctx
->Pixel
.ZoomX
== -1.0F
) {
220 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
221 i
= span
->end
- (j
+ skipCol
) - 1;
222 zoomed
.array
->index
[j
] = indexes
[i
];
226 /* general solution */
227 const GLfloat xscale
= 1.0F
/ ctx
->Pixel
.ZoomX
;
228 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
229 i
= (GLint
) ((j
+ skipCol
) * xscale
);
230 if (ctx
->Pixel
.ZoomX
< 0.0) {
232 i
= span
->end
+ i
- 1;
235 ASSERT(i
< (GLint
) span
->end
);
236 zoomed
.array
->index
[j
] = indexes
[i
];
240 else if (format
== GL_DEPTH_COMPONENT
) {
241 const GLuint
*zValues
= (const GLuint
*) src
;
242 if (ctx
->Pixel
.ZoomX
== -1.0F
) {
244 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
245 i
= span
->end
- (j
+ skipCol
) - 1;
246 zoomed
.array
->z
[j
] = zValues
[i
];
250 /* general solution */
251 const GLfloat xscale
= 1.0F
/ ctx
->Pixel
.ZoomX
;
252 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
253 i
= (GLint
) ((j
+ skipCol
) * xscale
);
254 if (ctx
->Pixel
.ZoomX
< 0.0) {
256 i
= span
->end
+ i
- 1;
259 ASSERT(i
< (GLint
) span
->end
);
260 zoomed
.array
->z
[j
] = zValues
[i
];
263 /* Now, fall into either the RGB or COLOR_INDEX path below */
264 if (ctx
->Visual
.rgbMode
)
267 format
= GL_COLOR_INDEX
;
269 else if (format
== GL_DEPTH_COMPONENT32
) {
270 /* 32-bit Z values */
271 struct gl_renderbuffer
*rb
272 = ctx
->DrawBuffer
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
273 const GLuint
*zSrc32
= (const GLuint
*) src
;
274 GLuint zDst32
[MAX_WIDTH
];
275 const GLfloat xscale
= 1.0F
/ ctx
->Pixel
.ZoomX
;
276 for (j
= (GLint
) zoomed
.start
; j
< (GLint
) zoomed
.end
; j
++) {
277 i
= (GLint
) ((j
+ skipCol
) * xscale
);
278 if (ctx
->Pixel
.ZoomX
< 0.0) {
280 i
= span
->end
+ i
- 1;
283 ASSERT(i
< (GLint
) span
->end
);
284 zDst32
[j
] = zSrc32
[i
];
286 rb
->PutRow(ctx
, rb
, zoomed
.end
, zoomed
.x
, zoomed
.y
, zDst32
, NULL
);
290 /* write the span in rows [r0, r1) */
291 if (format
== GL_RGBA
|| format
== GL_RGB
) {
292 /* Writing the span may modify the colors, so make a backup now if we're
293 * going to call _swrast_write_zoomed_span() more than once.
294 * Also, clipping may change the span end value, so store it as well.
296 GLchan rgbaSave
[MAX_WIDTH
][4];
297 const GLint end
= zoomed
.end
; /* save */
299 MEMCPY(rgbaSave
, zoomed
.array
->rgba
, zoomed
.end
* 4 * sizeof(GLchan
));
301 for (zoomed
.y
= r0
; zoomed
.y
< r1
; zoomed
.y
++) {
302 _swrast_write_rgba_span(ctx
, &zoomed
);
303 zoomed
.end
= end
; /* restore */
305 /* restore the colors */
306 MEMCPY(zoomed
.array
->rgba
, rgbaSave
, zoomed
.end
*4 * sizeof(GLchan
));
310 else if (format
== GL_COLOR_INDEX
) {
311 GLuint indexSave
[MAX_WIDTH
];
312 const GLint end
= zoomed
.end
; /* save */
314 MEMCPY(indexSave
, zoomed
.array
->index
, zoomed
.end
* sizeof(GLuint
));
316 for (zoomed
.y
= r0
; zoomed
.y
< r1
; zoomed
.y
++) {
317 _swrast_write_index_span(ctx
, &zoomed
);
318 zoomed
.end
= end
; /* restore */
320 /* restore the colors */
321 MEMCPY(zoomed
.array
->index
, indexSave
, zoomed
.end
* sizeof(GLuint
));
329 _swrast_write_zoomed_rgba_span( GLcontext
*ctx
, const struct sw_span
*span
,
330 CONST GLchan rgba
[][4], GLint y0
,
333 zoom_span(ctx
, span
, (const GLvoid
*) rgba
, y0
, GL_RGBA
, skipPixels
);
338 _swrast_write_zoomed_rgb_span( GLcontext
*ctx
, const struct sw_span
*span
,
339 CONST GLchan rgb
[][3], GLint y0
,
342 zoom_span(ctx
, span
, (const GLvoid
*) rgb
, y0
, GL_RGB
, skipPixels
);
347 _swrast_write_zoomed_index_span( GLcontext
*ctx
, const struct sw_span
*span
,
348 GLint y0
, GLint skipPixels
)
350 zoom_span(ctx
, span
, (const GLvoid
*) span
->array
->index
, y0
,
351 GL_COLOR_INDEX
, skipPixels
);
356 _swrast_write_zoomed_depth_span( GLcontext
*ctx
, const struct sw_span
*span
,
357 GLint y0
, GLint skipPixels
)
359 zoom_span(ctx
, span
, (const GLvoid
*) span
->array
->z
, y0
,
360 GL_DEPTH_COMPONENT
, skipPixels
);
365 * As above, but write stencil values.
368 _swrast_write_zoomed_stencil_span( GLcontext
*ctx
,
369 GLuint n
, GLint x
, GLint y
,
370 const GLstencil stencil
[], GLint y0
,
374 GLint r0
, r1
, row
, r
;
376 GLstencil zstencil
[MAX_WIDTH
]; /* zoomed stencil values */
377 GLint maxwidth
= MIN2( ctx
->DrawBuffer
->Width
, MAX_WIDTH
);
379 (void) skipPixels
; /* XXX this shouldn't be ignored */
381 /* compute width of output row */
382 m
= (GLint
) FABSF( n
* ctx
->Pixel
.ZoomX
);
386 if (ctx
->Pixel
.ZoomX
<0.0) {
387 /* adjust x coordinate for left/right mirroring */
391 /* compute which rows to draw */
393 r0
= y0
+ (GLint
) (row
* ctx
->Pixel
.ZoomY
);
394 r1
= y0
+ (GLint
) ((row
+1) * ctx
->Pixel
.ZoomY
);
404 /* return early if r0...r1 is above or below window */
409 if (r0
>= (GLint
) ctx
->DrawBuffer
->Height
&&
410 r1
>= (GLint
) ctx
->DrawBuffer
->Height
) {
415 /* check if left edge is outside window */
421 /* make sure span isn't too long or short */
429 ASSERT( m
<= MAX_WIDTH
);
431 /* zoom the span horizontally */
432 if (ctx
->Pixel
.ZoomX
==-1.0F
) {
435 i
= n
- (j
+skipcol
) - 1;
436 zstencil
[j
] = stencil
[i
];
440 GLfloat xscale
= 1.0F
/ ctx
->Pixel
.ZoomX
;
442 i
= (GLint
) ((j
+skipcol
) * xscale
);
443 if (i
<0) i
= n
+ i
- 1;
444 zstencil
[j
] = stencil
[i
];
449 for (r
=r0
; r
<r1
; r
++) {
450 _swrast_write_stencil_span( ctx
, m
, x
+skipcol
, r
, zstencil
);