2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2006 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.
25 #include "main/glheader.h"
26 #include "main/macros.h"
27 #include "main/imports.h"
28 #include "main/colormac.h"
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 mage being drawn (gl WindowPos)
41 * \param spanX, spanY position of span being drawing
42 * \param width number of pixels in span
43 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
44 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
45 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
48 compute_zoomed_bounds(GLcontext
*ctx
, GLint imageX
, GLint imageY
,
49 GLint spanX
, GLint spanY
, GLint width
,
50 GLint
*x0
, GLint
*x1
, GLint
*y0
, GLint
*y1
)
52 const struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
55 ASSERT(spanX
>= imageX
);
56 ASSERT(spanY
>= imageY
);
59 * Compute destination columns: [c0, c1)
61 c0
= imageX
+ (GLint
) ((spanX
- imageX
) * ctx
->Pixel
.ZoomX
);
62 c1
= imageX
+ (GLint
) ((spanX
+ width
- imageX
) * ctx
->Pixel
.ZoomX
);
69 c0
= CLAMP(c0
, fb
->_Xmin
, fb
->_Xmax
);
70 c1
= CLAMP(c1
, fb
->_Xmin
, fb
->_Xmax
);
72 return GL_FALSE
; /* no width */
76 * Compute destination rows: [r0, r1)
78 r0
= imageY
+ (GLint
) ((spanY
- imageY
) * ctx
->Pixel
.ZoomY
);
79 r1
= imageY
+ (GLint
) ((spanY
+ 1 - imageY
) * ctx
->Pixel
.ZoomY
);
86 r0
= CLAMP(r0
, fb
->_Ymin
, fb
->_Ymax
);
87 r1
= CLAMP(r1
, fb
->_Ymin
, fb
->_Ymax
);
89 return GL_FALSE
; /* no height */
102 * Convert a zoomed x image coordinate back to an unzoomed x coord.
103 * 'zx' is screen position of a pixel in the zoomed image, who's left edge
105 * return corresponding x coord in the original, unzoomed image.
106 * This can use this for unzooming X or Y values.
109 unzoom_x(GLfloat zoomX
, GLint imageX
, GLint zx
)
112 zx = imageX + (x - imageX) * zoomX;
113 zx - imageX = (x - imageX) * zoomX;
114 (zx - imageX) / zoomX = x - imageX;
119 x
= imageX
+ (GLint
) ((zx
- imageX
) / zoomX
);
126 * Helper function called from _swrast_write_zoomed_rgba/rgb/
127 * index/depth_span().
130 zoom_span( GLcontext
*ctx
, GLint imgX
, GLint imgY
, const SWspan
*span
,
131 const GLvoid
*src
, GLenum format
)
134 SWspanarrays zoomed_arrays
; /* this is big! */
135 GLint x0
, x1
, y0
, y1
;
138 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, span
->x
, span
->y
, span
->end
,
139 &x0
, &x1
, &y0
, &y1
)) {
140 return; /* totally clipped */
143 zoomedWidth
= x1
- x0
;
144 ASSERT(zoomedWidth
> 0);
145 ASSERT(zoomedWidth
<= MAX_WIDTH
);
147 /* no pixel arrays! must be horizontal spans. */
148 ASSERT((span
->arrayMask
& SPAN_XY
) == 0);
149 ASSERT(span
->primitive
== GL_BITMAP
);
151 INIT_SPAN(zoomed
, GL_BITMAP
);
153 zoomed
.end
= zoomedWidth
;
154 zoomed
.array
= &zoomed_arrays
;
155 zoomed_arrays
.ChanType
= span
->array
->ChanType
;
156 if (zoomed_arrays
.ChanType
== GL_UNSIGNED_BYTE
)
157 zoomed_arrays
.rgba
= (GLchan (*)[4]) zoomed_arrays
.rgba8
;
158 else if (zoomed_arrays
.ChanType
== GL_UNSIGNED_SHORT
)
159 zoomed_arrays
.rgba
= (GLchan (*)[4]) zoomed_arrays
.rgba16
;
161 zoomed_arrays
.rgba
= (GLchan (*)[4]) zoomed_arrays
.attribs
[FRAG_ATTRIB_COL0
];
163 COPY_4V(zoomed
.attrStart
[FRAG_ATTRIB_WPOS
], span
->attrStart
[FRAG_ATTRIB_WPOS
]);
164 COPY_4V(zoomed
.attrStepX
[FRAG_ATTRIB_WPOS
], span
->attrStepX
[FRAG_ATTRIB_WPOS
]);
165 COPY_4V(zoomed
.attrStepY
[FRAG_ATTRIB_WPOS
], span
->attrStepY
[FRAG_ATTRIB_WPOS
]);
167 zoomed
.attrStart
[FRAG_ATTRIB_FOGC
][0] = span
->attrStart
[FRAG_ATTRIB_FOGC
][0];
168 zoomed
.attrStepX
[FRAG_ATTRIB_FOGC
][0] = span
->attrStepX
[FRAG_ATTRIB_FOGC
][0];
169 zoomed
.attrStepY
[FRAG_ATTRIB_FOGC
][0] = span
->attrStepY
[FRAG_ATTRIB_FOGC
][0];
171 if (format
== GL_RGBA
|| format
== GL_RGB
) {
174 zoomed
.zStep
= span
->zStep
;
175 /* we'll generate an array of colorss */
176 zoomed
.interpMask
= span
->interpMask
& ~SPAN_RGBA
;
177 zoomed
.arrayMask
|= SPAN_RGBA
;
178 zoomed
.arrayAttribs
|= FRAG_BIT_COL0
; /* we'll produce these values */
179 ASSERT(span
->arrayMask
& SPAN_RGBA
);
181 else if (format
== GL_COLOR_INDEX
) {
184 zoomed
.zStep
= span
->zStep
;
185 /* we'll generate an array of color indexes */
186 zoomed
.interpMask
= span
->interpMask
& ~SPAN_INDEX
;
187 zoomed
.arrayMask
|= SPAN_INDEX
;
188 ASSERT(span
->arrayMask
& SPAN_INDEX
);
190 else if (format
== GL_DEPTH_COMPONENT
) {
191 /* Copy color info */
192 zoomed
.red
= span
->red
;
193 zoomed
.green
= span
->green
;
194 zoomed
.blue
= span
->blue
;
195 zoomed
.alpha
= span
->alpha
;
196 zoomed
.redStep
= span
->redStep
;
197 zoomed
.greenStep
= span
->greenStep
;
198 zoomed
.blueStep
= span
->blueStep
;
199 zoomed
.alphaStep
= span
->alphaStep
;
200 /* we'll generate an array of depth values */
201 zoomed
.interpMask
= span
->interpMask
& ~SPAN_Z
;
202 zoomed
.arrayMask
|= SPAN_Z
;
203 ASSERT(span
->arrayMask
& SPAN_Z
);
206 _mesa_problem(ctx
, "Bad format in zoom_span");
210 /* zoom the span horizontally */
211 if (format
== GL_RGBA
) {
212 if (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
) {
213 const GLubyte (*rgba
)[4] = (const GLubyte (*)[4]) src
;
215 for (i
= 0; i
< zoomedWidth
; i
++) {
216 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
218 ASSERT(j
< (GLint
) span
->end
);
219 COPY_4UBV(zoomed
.array
->rgba8
[i
], rgba
[j
]);
222 else if (zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
) {
223 const GLushort (*rgba
)[4] = (const GLushort (*)[4]) src
;
225 for (i
= 0; i
< zoomedWidth
; i
++) {
226 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
228 ASSERT(j
< (GLint
) span
->end
);
229 COPY_4V(zoomed
.array
->rgba16
[i
], rgba
[j
]);
233 const GLfloat (*rgba
)[4] = (const GLfloat (*)[4]) src
;
235 for (i
= 0; i
< zoomedWidth
; i
++) {
236 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
238 ASSERT(j
< span
->end
);
239 COPY_4V(zoomed
.array
->attribs
[FRAG_ATTRIB_COL0
][i
], rgba
[j
]);
243 else if (format
== GL_RGB
) {
244 if (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
) {
245 const GLubyte (*rgb
)[3] = (const GLubyte (*)[3]) src
;
247 for (i
= 0; i
< zoomedWidth
; i
++) {
248 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
250 ASSERT(j
< (GLint
) span
->end
);
251 zoomed
.array
->rgba8
[i
][0] = rgb
[j
][0];
252 zoomed
.array
->rgba8
[i
][1] = rgb
[j
][1];
253 zoomed
.array
->rgba8
[i
][2] = rgb
[j
][2];
254 zoomed
.array
->rgba8
[i
][3] = 0xff;
257 else if (zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
) {
258 const GLushort (*rgb
)[3] = (const GLushort (*)[3]) src
;
260 for (i
= 0; i
< zoomedWidth
; i
++) {
261 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
263 ASSERT(j
< (GLint
) span
->end
);
264 zoomed
.array
->rgba16
[i
][0] = rgb
[j
][0];
265 zoomed
.array
->rgba16
[i
][1] = rgb
[j
][1];
266 zoomed
.array
->rgba16
[i
][2] = rgb
[j
][2];
267 zoomed
.array
->rgba16
[i
][3] = 0xffff;
271 const GLfloat (*rgb
)[3] = (const GLfloat (*)[3]) src
;
273 for (i
= 0; i
< zoomedWidth
; i
++) {
274 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
276 ASSERT(j
< span
->end
);
277 zoomed
.array
->attribs
[FRAG_ATTRIB_COL0
][i
][0] = rgb
[j
][0];
278 zoomed
.array
->attribs
[FRAG_ATTRIB_COL0
][i
][1] = rgb
[j
][1];
279 zoomed
.array
->attribs
[FRAG_ATTRIB_COL0
][i
][2] = rgb
[j
][2];
280 zoomed
.array
->attribs
[FRAG_ATTRIB_COL0
][i
][3] = 1.0F
;
284 else if (format
== GL_COLOR_INDEX
) {
285 const GLuint
*indexes
= (const GLuint
*) src
;
287 for (i
= 0; i
< zoomedWidth
; i
++) {
288 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
290 ASSERT(j
< (GLint
) span
->end
);
291 zoomed
.array
->index
[i
] = indexes
[j
];
294 else if (format
== GL_DEPTH_COMPONENT
) {
295 const GLuint
*zValues
= (const GLuint
*) src
;
297 for (i
= 0; i
< zoomedWidth
; i
++) {
298 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - span
->x
;
300 ASSERT(j
< (GLint
) span
->end
);
301 zoomed
.array
->z
[i
] = zValues
[j
];
303 /* Now, fall into either the RGB or COLOR_INDEX path below */
304 format
= ctx
->Visual
.rgbMode
? GL_RGBA
: GL_COLOR_INDEX
;
307 /* write the span in rows [r0, r1) */
308 if (format
== GL_RGBA
|| format
== GL_RGB
) {
309 /* Writing the span may modify the colors, so make a backup now if we're
310 * going to call _swrast_write_zoomed_span() more than once.
311 * Also, clipping may change the span end value, so store it as well.
313 const GLint end
= zoomed
.end
; /* save */
314 GLuint rgbaSave
[MAX_WIDTH
][4];
315 const GLint pixelSize
=
316 (zoomed
.array
->ChanType
== GL_UNSIGNED_BYTE
) ? 4 * sizeof(GLubyte
) :
317 ((zoomed
.array
->ChanType
== GL_UNSIGNED_SHORT
) ? 4 * sizeof(GLushort
)
318 : 4 * sizeof(GLfloat
));
320 MEMCPY(rgbaSave
, zoomed
.array
->rgba
, zoomed
.end
* pixelSize
);
322 for (zoomed
.y
= y0
; zoomed
.y
< y1
; zoomed
.y
++) {
323 _swrast_write_rgba_span(ctx
, &zoomed
);
324 zoomed
.end
= end
; /* restore */
326 /* restore the colors */
327 MEMCPY(zoomed
.array
->rgba
, rgbaSave
, zoomed
.end
* pixelSize
);
331 else if (format
== GL_COLOR_INDEX
) {
332 /* use specular color array for temp storage */
333 GLuint
*indexSave
= (GLuint
*) zoomed
.array
->attribs
[FRAG_ATTRIB_FOGC
];
334 const GLint end
= zoomed
.end
; /* save */
336 MEMCPY(indexSave
, zoomed
.array
->index
, zoomed
.end
* sizeof(GLuint
));
338 for (zoomed
.y
= y0
; zoomed
.y
< y1
; zoomed
.y
++) {
339 _swrast_write_index_span(ctx
, &zoomed
);
340 zoomed
.end
= end
; /* restore */
342 /* restore the colors */
343 MEMCPY(zoomed
.array
->index
, indexSave
, zoomed
.end
* sizeof(GLuint
));
351 _swrast_write_zoomed_rgba_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
352 const SWspan
*span
, const GLvoid
*rgba
)
354 zoom_span(ctx
, imgX
, imgY
, span
, rgba
, GL_RGBA
);
359 _swrast_write_zoomed_rgb_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
360 const SWspan
*span
, const GLvoid
*rgb
)
362 zoom_span(ctx
, imgX
, imgY
, span
, rgb
, GL_RGB
);
367 _swrast_write_zoomed_index_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
370 zoom_span(ctx
, imgX
, imgY
, span
,
371 (const GLvoid
*) span
->array
->index
, GL_COLOR_INDEX
);
376 _swrast_write_zoomed_depth_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
379 zoom_span(ctx
, imgX
, imgY
, span
,
380 (const GLvoid
*) span
->array
->z
, GL_DEPTH_COMPONENT
);
385 * Zoom/write stencil values.
386 * No per-fragment operations are applied.
389 _swrast_write_zoomed_stencil_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
390 GLint width
, GLint spanX
, GLint spanY
,
391 const GLstencil stencil
[])
393 GLstencil zoomedVals
[MAX_WIDTH
];
394 GLint x0
, x1
, y0
, y1
, y
;
395 GLint i
, zoomedWidth
;
397 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, spanX
, spanY
, width
,
398 &x0
, &x1
, &y0
, &y1
)) {
399 return; /* totally clipped */
402 zoomedWidth
= x1
- x0
;
403 ASSERT(zoomedWidth
> 0);
404 ASSERT(zoomedWidth
<= MAX_WIDTH
);
406 /* zoom the span horizontally */
407 for (i
= 0; i
< zoomedWidth
; i
++) {
408 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
411 zoomedVals
[i
] = stencil
[j
];
414 /* write the zoomed spans */
415 for (y
= y0
; y
< y1
; y
++) {
416 _swrast_write_stencil_span(ctx
, zoomedWidth
, x0
, y
, zoomedVals
);
422 * Zoom/write z values (16 or 32-bit).
423 * No per-fragment operations are applied.
426 _swrast_write_zoomed_z_span(GLcontext
*ctx
, GLint imgX
, GLint imgY
,
427 GLint width
, GLint spanX
, GLint spanY
,
430 struct gl_renderbuffer
*rb
= ctx
->DrawBuffer
->_DepthBuffer
;
431 GLushort zoomedVals16
[MAX_WIDTH
];
432 GLuint zoomedVals32
[MAX_WIDTH
];
433 GLint x0
, x1
, y0
, y1
, y
;
434 GLint i
, zoomedWidth
;
436 if (!compute_zoomed_bounds(ctx
, imgX
, imgY
, spanX
, spanY
, width
,
437 &x0
, &x1
, &y0
, &y1
)) {
438 return; /* totally clipped */
441 zoomedWidth
= x1
- x0
;
442 ASSERT(zoomedWidth
> 0);
443 ASSERT(zoomedWidth
<= MAX_WIDTH
);
445 /* zoom the span horizontally */
446 if (rb
->DataType
== GL_UNSIGNED_SHORT
) {
447 for (i
= 0; i
< zoomedWidth
; i
++) {
448 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
451 zoomedVals16
[i
] = ((GLushort
*) z
)[j
];
456 ASSERT(rb
->DataType
== GL_UNSIGNED_INT
);
457 for (i
= 0; i
< zoomedWidth
; i
++) {
458 GLint j
= unzoom_x(ctx
->Pixel
.ZoomX
, imgX
, x0
+ i
) - spanX
;
461 zoomedVals32
[i
] = ((GLuint
*) z
)[j
];
466 /* write the zoomed spans */
467 for (y
= y0
; y
< y1
; y
++) {
468 rb
->PutRow(ctx
, rb
, zoomedWidth
, x0
, y
, z
, NULL
);