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 * Compute the bounds of the region resulting from zooming a pixel span.
38 * The resulting region will be entirely inside the window/scissor bounds
39 * so no additional clipping is needed.
40 * \param imageX, imageY position of the overall image being drawn
41 * \param spanX, spanY position of span being drawing
42 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
43 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
44 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
47 compute_zoomed_bounds(GLcontext
*ctx
, GLint imageX
, GLint imageY
,
48 GLint spanX
, GLint spanY
, GLint width
,
49 GLint
*x0
, GLint
*x1
, GLint
*y0
, GLint
*y1
)
51 const struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
54 ASSERT(spanX
>= imageX
);
55 ASSERT(spanY
>= imageY
);
58 * Compute destination columns: [c0, c1)
60 c0
= imageX
+ (GLint
) ((spanX
- imageX
) * ctx
->Pixel
.ZoomX
);
61 c1
= imageX
+ (GLint
) ((spanX
+ width
- imageX
) * ctx
->Pixel
.ZoomX
);
68 c0
= CLAMP(c0
, fb
->_Xmin
, fb
->_Xmax
);
69 c1
= CLAMP(c1
, fb
->_Xmin
, fb
->_Xmax
);
71 return GL_FALSE
; /* no width */
75 * Compute destination rows: [r0, r1)
77 r0
= imageY
+ (GLint
) ((spanY
- imageY
) * ctx
->Pixel
.ZoomY
);
78 r1
= imageY
+ (GLint
) ((spanY
+ 1 - imageY
) * ctx
->Pixel
.ZoomY
);
85 r0
= CLAMP(r0
, fb
->_Ymin
, fb
->_Ymax
);
86 r1
= CLAMP(r1
, fb
->_Ymin
, fb
->_Ymax
);
88 return GL_FALSE
; /* no height */
101 * Can use this for unzooming X or Y values.
104 unzoom_x(GLfloat zoomX
, GLint imageX
, GLint zx
)
107 zx = imageX + (x - imageX) * zoomX;
108 zx - imageX = (x - imageX) * zoomX;
109 (zx - imageX) / zoomX = x - imageX;
111 GLint x
= imageX
+ (GLint
) ((zx
- imageX
) / zoomX
);
118 * Helper function called from _swrast_write_zoomed_rgba/rgb/
119 * index/depth_span().
122 zoom_span( GLcontext
*ctx
, GLint imgX
, GLint imgY
, const struct sw_span
*span
,
123 const GLvoid
*src
, GLenum format
)
125 struct sw_span zoomed
;
126 struct span_arrays zoomed_arrays
; /* this is big! */
127 GLint x0
, x1
, y0
, y1
;
130 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, span
->x
, span
->y
, span
->end
,
131 &x0
, &x1
, &y0
, &y1
)) {
132 return; /* totally clipped */
135 zoomedWidth
= x1
- x0
;
136 ASSERT(zoomedWidth
> 0);
137 ASSERT(zoomedWidth
<= MAX_WIDTH
);
139 /* no pixel arrays! must be horizontal spans. */
140 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
141 ASSERT(span
->primitive
== GL_BITMAP
);
143 INIT_SPAN(zoomed
, GL_BITMAP
, 0, 0, 0);
145 zoomed
.end
= zoomedWidth
;
146 zoomed
.array
= &zoomed_arrays
;
148 /* copy fog interp info */
149 zoomed
.fog
= span
->fog
;
150 zoomed
.fogStep
= span
->fogStep
;
151 /* XXX copy texcoord info? */
153 if (format
== GL_RGBA
|| format
== GL_RGB
) {
156 zoomed
.zStep
= span
->zStep
;
157 /* we'll generate an array of colorss */
158 zoomed
.interpMask
= span
->interpMask
& ~SPAN_RGBA
;
159 zoomed
.arrayMask
|= SPAN_RGBA
;
160 ASSERT(span
->arrayMask
& SPAN_RGBA
);
162 else if (format
== GL_COLOR_INDEX
) {
165 zoomed
.zStep
= span
->zStep
;
166 /* we'll generate an array of color indexes */
167 zoomed
.interpMask
= span
->interpMask
& ~SPAN_INDEX
;
168 zoomed
.arrayMask
|= SPAN_INDEX
;
169 ASSERT(span
->arrayMask
& SPAN_INDEX
);
171 else if (format
== GL_DEPTH_COMPONENT
) {
172 /* Copy color info */
173 zoomed
.red
= span
->red
;
174 zoomed
.green
= span
->green
;
175 zoomed
.blue
= span
->blue
;
176 zoomed
.alpha
= span
->alpha
;
177 zoomed
.redStep
= span
->redStep
;
178 zoomed
.greenStep
= span
->greenStep
;
179 zoomed
.blueStep
= span
->blueStep
;
180 zoomed
.alphaStep
= span
->alphaStep
;
181 /* we'll generate an array of depth values */
182 zoomed
.interpMask
= span
->interpMask
& ~SPAN_Z
;
183 zoomed
.arrayMask
|= SPAN_Z
;
184 ASSERT(span
->arrayMask
& SPAN_Z
);
187 _mesa_problem(ctx
, "Bad format in zoom_span");
191 /* zoom the span horizontally */
192 if (format
== GL_RGBA
) {
193 const GLchan (*rgba
)[4] = (const GLchan (*)[4]) src
;
195 for (i
= 0; i
< zoomedWidth
; i
++) {
196 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
198 ASSERT(j
< span
->end
);
199 COPY_CHAN4(zoomed
.array
->rgba
[i
], rgba
[j
]);
202 else if (format
== GL_RGB
) {
203 const GLchan (*rgb
)[3] = (const GLchan (*)[3]) src
;
205 for (i
= 0; i
< zoomedWidth
; i
++) {
206 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
208 ASSERT(j
< span
->end
);
209 zoomed
.array
->rgba
[i
][0] = rgb
[j
][0];
210 zoomed
.array
->rgba
[i
][1] = rgb
[j
][1];
211 zoomed
.array
->rgba
[i
][2] = rgb
[j
][2];
212 zoomed
.array
->rgba
[i
][3] = CHAN_MAX
;
215 else if (format
== GL_COLOR_INDEX
) {
216 const GLuint
*indexes
= (const GLuint
*) src
;
218 for (i
= 0; i
< zoomedWidth
; i
++) {
219 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
221 ASSERT(j
< span
->end
);
222 zoomed
.array
->index
[i
] = indexes
[j
];
225 else if (format
== GL_DEPTH_COMPONENT
) {
226 const GLuint
*zValues
= (const GLuint
*) src
;
228 for (i
= 0; i
< zoomedWidth
; i
++) {
229 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
231 ASSERT(j
< span
->end
);
232 zoomed
.array
->z
[i
] = zValues
[j
];
234 /* Now, fall into either the RGB or COLOR_INDEX path below */
235 format
= ctx
->Visual
.rgbMode
? GL_RGBA
: GL_COLOR_INDEX
;
238 /* write the span in rows [r0, r1) */
239 if (format
== GL_RGBA
|| format
== GL_RGB
) {
240 /* Writing the span may modify the colors, so make a backup now if we're
241 * going to call _swrast_write_zoomed_span() more than once.
242 * Also, clipping may change the span end value, so store it as well.
244 GLchan rgbaSave
[MAX_WIDTH
][4];
245 const GLint end
= zoomed
.end
; /* save */
247 MEMCPY(rgbaSave
, zoomed
.array
->rgba
, zoomed
.end
* 4 * sizeof(GLchan
));
249 for (zoomed
.y
= y0
; zoomed
.y
< y1
; zoomed
.y
++) {
250 _swrast_write_rgba_span(ctx
, &zoomed
);
251 zoomed
.end
= end
; /* restore */
253 /* restore the colors */
254 MEMCPY(zoomed
.array
->rgba
, rgbaSave
, zoomed
.end
*4 * sizeof(GLchan
));
258 else if (format
== GL_COLOR_INDEX
) {
259 GLuint indexSave
[MAX_WIDTH
];
260 const GLint end
= zoomed
.end
; /* save */
262 MEMCPY(indexSave
, zoomed
.array
->index
, zoomed
.end
* sizeof(GLuint
));
264 for (zoomed
.y
= y0
; zoomed
.y
< y1
; zoomed
.y
++) {
265 _swrast_write_index_span(ctx
, &zoomed
);
266 zoomed
.end
= end
; /* restore */
268 /* restore the colors */
269 MEMCPY(zoomed
.array
->index
, indexSave
, zoomed
.end
* sizeof(GLuint
));
277 _swrast_write_zoomed_rgba_span( GLcontext
*ctx
, GLint imgX
, GLint imgY
,
278 const struct sw_span
*span
,
279 CONST GLchan rgba
[][4])
281 zoom_span(ctx
, imgX
, imgY
, span
, (const GLvoid
*) rgba
, GL_RGBA
);
286 _swrast_write_zoomed_rgb_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
287 const struct sw_span
*span
,
288 CONST GLchan rgb
[][3])
290 zoom_span(ctx
, imgX
, imgY
, span
, (const GLvoid
*) rgb
, GL_RGB
);
295 _swrast_write_zoomed_index_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
296 const struct sw_span
*span
)
298 zoom_span(ctx
, imgX
, imgY
, span
,
299 (const GLvoid
*) span
->array
->index
, GL_COLOR_INDEX
);
304 _swrast_write_zoomed_depth_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
305 const struct sw_span
*span
)
307 zoom_span(ctx
, imgX
, imgY
, span
,
308 (const GLvoid
*) span
->array
->z
, GL_DEPTH_COMPONENT
);
313 * Zoom/write stencil values.
314 * No per-fragment operations are applied.
317 _swrast_write_zoomed_stencil_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
318 GLint width
, GLint spanX
, GLint spanY
,
319 const GLstencil stencil
[])
321 GLstencil zoomedVals
[MAX_WIDTH
];
322 GLint x0
, x1
, y0
, y1
, y
;
323 GLint i
, zoomedWidth
;
325 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, spanX
, spanY
, width
,
326 &x0
, &x1
, &y0
, &y1
)) {
327 return; /* totally clipped */
330 zoomedWidth
= x1
- x0
;
331 ASSERT(zoomedWidth
> 0);
332 ASSERT(zoomedWidth
<= MAX_WIDTH
);
334 /* zoom the span horizontally */
335 for (i
= 0; i
< zoomedWidth
; i
++) {
336 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
339 zoomedVals
[i
] = stencil
[j
];
342 /* write the zoomed spans */
343 for (y
= y0
; y
< y1
; y
++) {
344 _swrast_write_stencil_span(ctx
, zoomedWidth
, x0
, y
, zoomedVals
);
350 * Zoom/write z values (16 or 32-bit).
351 * No per-fragment operations are applied.
354 _swrast_write_zoomed_z_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
355 GLint width
, GLint spanX
, GLint spanY
,
358 struct gl_renderbuffer
*rb
= ctx
->DrawBuffer
->_DepthBuffer
;
359 GLushort zoomedVals16
[MAX_WIDTH
];
360 GLuint zoomedVals32
[MAX_WIDTH
];
361 GLint x0
, x1
, y0
, y1
, y
;
362 GLint i
, zoomedWidth
;
364 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, spanX
, spanY
, width
,
365 &x0
, &x1
, &y0
, &y1
)) {
366 return; /* totally clipped */
369 zoomedWidth
= x1
- x0
;
370 ASSERT(zoomedWidth
> 0);
371 ASSERT(zoomedWidth
<= MAX_WIDTH
);
373 /* zoom the span horizontally */
374 if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
375 for (i
= 0; i
< zoomedWidth
; i
++) {
376 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
379 zoomedVals16
[i
] = ((GLushort
*) z
)[j
];
384 ASSERT(rb
->DataType
== GL_UNSIGNED_INT
);
385 for (i
= 0; i
< zoomedWidth
; i
++) {
386 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
389 zoomedVals32
[i
] = ((GLuint
*) z
)[j
];
394 /* write the zoomed spans */
395 for (y
= y0
; y
< y1
; y
++) {
396 rb
->PutRow(ctx
, rb
, zoomedWidth
, x0
, y
, z
, NULL
);