2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
25 #include "main/errors.h"
26 #include "main/glheader.h"
27 #include "main/macros.h"
29 #include "main/format_pack.h"
31 #include "s_context.h"
33 #include "s_stencil.h"
38 * Compute the bounds of the region resulting from zooming a pixel span.
39 * The resulting region will be entirely inside the window/scissor bounds
40 * so no additional clipping is needed.
41 * \param imageX, imageY position of the mage being drawn (gl WindowPos)
42 * \param spanX, spanY position of span being drawing
43 * \param width number of pixels in span
44 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
45 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
46 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
49 compute_zoomed_bounds(struct gl_context
*ctx
, GLint imageX
, GLint imageY
,
50 GLint spanX
, GLint spanY
, GLint width
,
51 GLint
*x0
, GLint
*x1
, GLint
*y0
, GLint
*y1
)
53 const struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
56 assert(spanX
>= imageX
);
57 assert(spanY
>= imageY
);
60 * Compute destination columns: [c0, c1)
62 c0
= imageX
+ (GLint
) ((spanX
- imageX
) * ctx
->Pixel
.ZoomX
);
63 c1
= imageX
+ (GLint
) ((spanX
+ width
- imageX
) * ctx
->Pixel
.ZoomX
);
70 c0
= CLAMP(c0
, fb
->_Xmin
, fb
->_Xmax
);
71 c1
= CLAMP(c1
, fb
->_Xmin
, fb
->_Xmax
);
73 return GL_FALSE
; /* no width */
77 * Compute destination rows: [r0, r1)
79 r0
= imageY
+ (GLint
) ((spanY
- imageY
) * ctx
->Pixel
.ZoomY
);
80 r1
= imageY
+ (GLint
) ((spanY
+ 1 - imageY
) * ctx
->Pixel
.ZoomY
);
87 r0
= CLAMP(r0
, fb
->_Ymin
, fb
->_Ymax
);
88 r1
= CLAMP(r1
, fb
->_Ymin
, fb
->_Ymax
);
90 return GL_FALSE
; /* no height */
103 * Convert a zoomed x image coordinate back to an unzoomed x coord.
104 * 'zx' is screen position of a pixel in the zoomed image, who's left edge
106 * return corresponding x coord in the original, unzoomed image.
107 * This can use this for unzooming X or Y values.
110 unzoom_x(GLfloat zoomX
, GLint imageX
, GLint zx
)
113 zx = imageX + (x - imageX) * zoomX;
114 zx - imageX = (x - imageX) * zoomX;
115 (zx - imageX) / zoomX = x - imageX;
120 x
= imageX
+ (GLint
) ((zx
- imageX
) / zoomX
);
127 * Helper function called from _swrast_write_zoomed_rgba/rgb/
128 * index/depth_span().
131 zoom_span( struct gl_context
*ctx
, GLint imgX
, GLint imgY
, const SWspan
*span
,
132 const GLvoid
*src
, GLenum format
)
134 SWcontext
*swrast
= SWRAST_CONTEXT(ctx
);
136 GLint x0
, x1
, y0
, y1
;
139 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, span
->x
, span
->y
, span
->end
,
140 &x0
, &x1
, &y0
, &y1
)) {
141 return; /* totally clipped */
144 if (!swrast
->ZoomedArrays
) {
145 /* allocate on demand */
146 swrast
->ZoomedArrays
= (SWspanarrays
*) calloc(1, sizeof(SWspanarrays
));
147 if (!swrast
->ZoomedArrays
)
151 zoomedWidth
= x1
- x0
;
152 assert(zoomedWidth
> 0);
153 assert(zoomedWidth
<= SWRAST_MAX_WIDTH
);
155 /* no pixel arrays! must be horizontal spans. */
156 assert((span
->arrayMask
& SPAN_XY
) == 0);
157 assert(span
->primitive
== GL_BITMAP
);
159 INIT_SPAN(zoomed
, GL_BITMAP
);
161 zoomed
.end
= zoomedWidth
;
162 zoomed
.array
= swrast
->ZoomedArrays
;
163 zoomed
.array
->ChanType
= span
->array
->ChanType
;
164 if (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
)
165 zoomed
.array
->rgba
= (GLchan (*)[4]) zoomed
.array
->rgba8
;
166 else if (zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
)
167 zoomed
.array
->rgba
= (GLchan (*)[4]) zoomed
.array
->rgba16
;
169 zoomed
.array
->rgba
= (GLchan (*)[4]) zoomed
.array
->attribs
[VARYING_SLOT_COL0
];
171 COPY_4V(zoomed
.attrStart
[VARYING_SLOT_POS
], span
->attrStart
[VARYING_SLOT_POS
]);
172 COPY_4V(zoomed
.attrStepX
[VARYING_SLOT_POS
], span
->attrStepX
[VARYING_SLOT_POS
]);
173 COPY_4V(zoomed
.attrStepY
[VARYING_SLOT_POS
], span
->attrStepY
[VARYING_SLOT_POS
]);
175 zoomed
.attrStart
[VARYING_SLOT_FOGC
][0] = span
->attrStart
[VARYING_SLOT_FOGC
][0];
176 zoomed
.attrStepX
[VARYING_SLOT_FOGC
][0] = span
->attrStepX
[VARYING_SLOT_FOGC
][0];
177 zoomed
.attrStepY
[VARYING_SLOT_FOGC
][0] = span
->attrStepY
[VARYING_SLOT_FOGC
][0];
179 if (format
== GL_RGBA
|| format
== GL_RGB
) {
182 zoomed
.zStep
= span
->zStep
;
183 /* we'll generate an array of colorss */
184 zoomed
.interpMask
= span
->interpMask
& ~SPAN_RGBA
;
185 zoomed
.arrayMask
|= SPAN_RGBA
;
186 zoomed
.arrayAttribs
|= VARYING_BIT_COL0
; /* we'll produce these values */
187 assert(span
->arrayMask
& SPAN_RGBA
);
189 else if (format
== GL_DEPTH_COMPONENT
) {
190 /* Copy color info */
191 zoomed
.red
= span
->red
;
192 zoomed
.green
= span
->green
;
193 zoomed
.blue
= span
->blue
;
194 zoomed
.alpha
= span
->alpha
;
195 zoomed
.redStep
= span
->redStep
;
196 zoomed
.greenStep
= span
->greenStep
;
197 zoomed
.blueStep
= span
->blueStep
;
198 zoomed
.alphaStep
= span
->alphaStep
;
199 /* we'll generate an array of depth values */
200 zoomed
.interpMask
= span
->interpMask
& ~SPAN_Z
;
201 zoomed
.arrayMask
|= SPAN_Z
;
202 assert(span
->arrayMask
& SPAN_Z
);
205 _mesa_problem(ctx
, "Bad format in zoom_span");
209 /* zoom the span horizontally */
210 if (format
== GL_RGBA
) {
211 if (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
) {
212 const GLubyte (*rgba
)[4] = (const GLubyte (*)[4]) src
;
214 for (i
= 0; i
< zoomedWidth
; i
++) {
215 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
217 assert(j
< (GLint
) span
->end
);
218 COPY_4UBV(zoomed
.array
->rgba8
[i
], rgba
[j
]);
221 else if (zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
) {
222 const GLushort (*rgba
)[4] = (const GLushort (*)[4]) src
;
224 for (i
= 0; i
< zoomedWidth
; i
++) {
225 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
227 assert(j
< (GLint
) span
->end
);
228 COPY_4V(zoomed
.array
->rgba16
[i
], rgba
[j
]);
232 const GLfloat (*rgba
)[4] = (const GLfloat (*)[4]) src
;
234 for (i
= 0; i
< zoomedWidth
; i
++) {
235 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
237 assert(j
< (GLint
) span
->end
);
238 COPY_4V(zoomed
.array
->attribs
[VARYING_SLOT_COL0
][i
], rgba
[j
]);
242 else if (format
== GL_RGB
) {
243 if (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
) {
244 const GLubyte (*rgb
)[3] = (const GLubyte (*)[3]) src
;
246 for (i
= 0; i
< zoomedWidth
; i
++) {
247 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
249 assert(j
< (GLint
) span
->end
);
250 zoomed
.array
->rgba8
[i
][0] = rgb
[j
][0];
251 zoomed
.array
->rgba8
[i
][1] = rgb
[j
][1];
252 zoomed
.array
->rgba8
[i
][2] = rgb
[j
][2];
253 zoomed
.array
->rgba8
[i
][3] = 0xff;
256 else if (zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
) {
257 const GLushort (*rgb
)[3] = (const GLushort (*)[3]) src
;
259 for (i
= 0; i
< zoomedWidth
; i
++) {
260 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
262 assert(j
< (GLint
) span
->end
);
263 zoomed
.array
->rgba16
[i
][0] = rgb
[j
][0];
264 zoomed
.array
->rgba16
[i
][1] = rgb
[j
][1];
265 zoomed
.array
->rgba16
[i
][2] = rgb
[j
][2];
266 zoomed
.array
->rgba16
[i
][3] = 0xffff;
270 const GLfloat (*rgb
)[3] = (const GLfloat (*)[3]) src
;
272 for (i
= 0; i
< zoomedWidth
; i
++) {
273 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
275 assert(j
< (GLint
) span
->end
);
276 zoomed
.array
->attribs
[VARYING_SLOT_COL0
][i
][0] = rgb
[j
][0];
277 zoomed
.array
->attribs
[VARYING_SLOT_COL0
][i
][1] = rgb
[j
][1];
278 zoomed
.array
->attribs
[VARYING_SLOT_COL0
][i
][2] = rgb
[j
][2];
279 zoomed
.array
->attribs
[VARYING_SLOT_COL0
][i
][3] = 1.0F
;
283 else if (format
== GL_DEPTH_COMPONENT
) {
284 const GLuint
*zValues
= (const GLuint
*) src
;
286 for (i
= 0; i
< zoomedWidth
; i
++) {
287 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
289 assert(j
< (GLint
) span
->end
);
290 zoomed
.array
->z
[i
] = zValues
[j
];
292 /* Now, fall into the RGB path below */
296 /* write the span in rows [r0, r1) */
297 if (format
== GL_RGBA
|| format
== GL_RGB
) {
298 /* Writing the span may modify the colors, so make a backup now if we're
299 * going to call _swrast_write_zoomed_span() more than once.
300 * Also, clipping may change the span end value, so store it as well.
302 const GLint end
= zoomed
.end
; /* save */
304 const GLint pixelSize
=
305 (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
) ? 4 * sizeof(GLubyte
) :
306 ((zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
) ? 4 * sizeof(GLushort
)
307 : 4 * sizeof(GLfloat
));
309 rgbaSave
= malloc(zoomed
.end
* pixelSize
);
315 memcpy(rgbaSave
, zoomed
.array
->rgba
, zoomed
.end
* pixelSize
);
317 for (zoomed
.y
= y0
; zoomed
.y
< y1
; zoomed
.y
++) {
318 _swrast_write_rgba_span(ctx
, &zoomed
);
319 zoomed
.end
= end
; /* restore */
321 /* restore the colors */
322 memcpy(zoomed
.array
->rgba
, rgbaSave
, zoomed
.end
* pixelSize
);
332 _swrast_write_zoomed_rgba_span(struct gl_context
*ctx
, GLint imgX
, GLint imgY
,
333 const SWspan
*span
, const GLvoid
*rgba
)
335 zoom_span(ctx
, imgX
, imgY
, span
, rgba
, GL_RGBA
);
340 _swrast_write_zoomed_rgb_span(struct gl_context
*ctx
, GLint imgX
, GLint imgY
,
341 const SWspan
*span
, const GLvoid
*rgb
)
343 zoom_span(ctx
, imgX
, imgY
, span
, rgb
, GL_RGB
);
348 _swrast_write_zoomed_depth_span(struct gl_context
*ctx
, GLint imgX
, GLint imgY
,
351 zoom_span(ctx
, imgX
, imgY
, span
,
352 (const GLvoid
*) span
->array
->z
, GL_DEPTH_COMPONENT
);
357 * Zoom/write stencil values.
358 * No per-fragment operations are applied.
361 _swrast_write_zoomed_stencil_span(struct gl_context
*ctx
, GLint imgX
, GLint imgY
,
362 GLint width
, GLint spanX
, GLint spanY
,
363 const GLubyte stencil
[])
366 GLint x0
, x1
, y0
, y1
, y
;
367 GLint i
, zoomedWidth
;
369 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, spanX
, spanY
, width
,
370 &x0
, &x1
, &y0
, &y1
)) {
371 return; /* totally clipped */
374 zoomedWidth
= x1
- x0
;
375 assert(zoomedWidth
> 0);
376 assert(zoomedWidth
<= SWRAST_MAX_WIDTH
);
378 zoomedVals
= malloc(zoomedWidth
* sizeof(GLubyte
));
382 /* zoom the span horizontally */
383 for (i
= 0; i
< zoomedWidth
; i
++) {
384 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
387 zoomedVals
[i
] = stencil
[j
];
390 /* write the zoomed spans */
391 for (y
= y0
; y
< y1
; y
++) {
392 _swrast_write_stencil_span(ctx
, zoomedWidth
, x0
, y
, zoomedVals
);
400 * Zoom/write 32-bit Z values.
401 * No per-fragment operations are applied.
404 _swrast_write_zoomed_z_span(struct gl_context
*ctx
, GLint imgX
, GLint imgY
,
405 GLint width
, GLint spanX
, GLint spanY
,
408 struct gl_renderbuffer
*rb
=
409 ctx
->DrawBuffer
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
411 GLint x0
, x1
, y0
, y1
, y
;
412 GLint i
, zoomedWidth
;
414 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, spanX
, spanY
, width
,
415 &x0
, &x1
, &y0
, &y1
)) {
416 return; /* totally clipped */
419 zoomedWidth
= x1
- x0
;
420 assert(zoomedWidth
> 0);
421 assert(zoomedWidth
<= SWRAST_MAX_WIDTH
);
423 zoomedVals
= malloc(zoomedWidth
* sizeof(GLuint
));
427 /* zoom the span horizontally */
428 for (i
= 0; i
< zoomedWidth
; i
++) {
429 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
432 zoomedVals
[i
] = zVals
[j
];
435 /* write the zoomed spans */
436 for (y
= y0
; y
< y1
; y
++) {
437 GLubyte
*dst
= _swrast_pixel_address(rb
, x0
, y
);
438 _mesa_pack_uint_z_row(rb
->Format
, zoomedWidth
, zoomedVals
, dst
);