Fixed typo
[reactos.git] / dll / opengl / mesa / swrast / s_zoom.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 #include <precomp.h>
26
27 /**
28 * Compute the bounds of the region resulting from zooming a pixel span.
29 * The resulting region will be entirely inside the window/scissor bounds
30 * so no additional clipping is needed.
31 * \param imageX, imageY position of the mage being drawn (gl WindowPos)
32 * \param spanX, spanY position of span being drawing
33 * \param width number of pixels in span
34 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
35 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
36 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
37 */
38 static GLboolean
39 compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
40 GLint spanX, GLint spanY, GLint width,
41 GLint *x0, GLint *x1, GLint *y0, GLint *y1)
42 {
43 const struct gl_framebuffer *fb = ctx->DrawBuffer;
44 GLint c0, c1, r0, r1;
45
46 ASSERT(spanX >= imageX);
47 ASSERT(spanY >= imageY);
48
49 /*
50 * Compute destination columns: [c0, c1)
51 */
52 c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
53 c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
54 if (c1 < c0) {
55 /* swap */
56 GLint tmp = c1;
57 c1 = c0;
58 c0 = tmp;
59 }
60 c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
61 c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
62 if (c0 == c1) {
63 return GL_FALSE; /* no width */
64 }
65
66 /*
67 * Compute destination rows: [r0, r1)
68 */
69 r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
70 r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
71 if (r1 < r0) {
72 /* swap */
73 GLint tmp = r1;
74 r1 = r0;
75 r0 = tmp;
76 }
77 r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
78 r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
79 if (r0 == r1) {
80 return GL_FALSE; /* no height */
81 }
82
83 *x0 = c0;
84 *x1 = c1;
85 *y0 = r0;
86 *y1 = r1;
87
88 return GL_TRUE;
89 }
90
91
92 /**
93 * Convert a zoomed x image coordinate back to an unzoomed x coord.
94 * 'zx' is screen position of a pixel in the zoomed image, who's left edge
95 * is at 'imageX'.
96 * return corresponding x coord in the original, unzoomed image.
97 * This can use this for unzooming X or Y values.
98 */
99 static inline GLint
100 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
101 {
102 /*
103 zx = imageX + (x - imageX) * zoomX;
104 zx - imageX = (x - imageX) * zoomX;
105 (zx - imageX) / zoomX = x - imageX;
106 */
107 GLint x;
108 if (zoomX < 0.0)
109 zx++;
110 x = imageX + (GLint) ((zx - imageX) / zoomX);
111 return x;
112 }
113
114
115
116 /**
117 * Helper function called from _swrast_write_zoomed_rgba/rgb/
118 * index/depth_span().
119 */
120 static void
121 zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
122 const GLvoid *src, GLenum format )
123 {
124 SWcontext *swrast = SWRAST_CONTEXT(ctx);
125 SWspan zoomed;
126 GLint x0, x1, y0, y1;
127 GLint zoomedWidth;
128
129 if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
130 &x0, &x1, &y0, &y1)) {
131 return; /* totally clipped */
132 }
133
134 if (!swrast->ZoomedArrays) {
135 /* allocate on demand */
136 swrast->ZoomedArrays = (SWspanarrays *) CALLOC(sizeof(SWspanarrays));
137 if (!swrast->ZoomedArrays)
138 return;
139 }
140
141 zoomedWidth = x1 - x0;
142 ASSERT(zoomedWidth > 0);
143 ASSERT(zoomedWidth <= MAX_WIDTH);
144
145 /* no pixel arrays! must be horizontal spans. */
146 ASSERT((span->arrayMask & SPAN_XY) == 0);
147 ASSERT(span->primitive == GL_BITMAP);
148
149 INIT_SPAN(zoomed, GL_BITMAP);
150 zoomed.x = x0;
151 zoomed.end = zoomedWidth;
152 zoomed.array = swrast->ZoomedArrays;
153 zoomed.array->ChanType = span->array->ChanType;
154 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
155 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
156 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
157 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
158 else
159 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[FRAG_ATTRIB_COL];
160
161 COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]);
162 COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]);
163 COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]);
164
165 zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0];
166 zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0];
167 zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0];
168
169 if (format == GL_RGBA || format == GL_RGB) {
170 /* copy Z info */
171 zoomed.z = span->z;
172 zoomed.zStep = span->zStep;
173 /* we'll generate an array of colorss */
174 zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
175 zoomed.arrayMask |= SPAN_RGBA;
176 zoomed.arrayAttribs |= FRAG_BIT_COL; /* we'll produce these values */
177 ASSERT(span->arrayMask & SPAN_RGBA);
178 }
179 else if (format == GL_DEPTH_COMPONENT) {
180 /* Copy color info */
181 zoomed.red = span->red;
182 zoomed.green = span->green;
183 zoomed.blue = span->blue;
184 zoomed.alpha = span->alpha;
185 zoomed.redStep = span->redStep;
186 zoomed.greenStep = span->greenStep;
187 zoomed.blueStep = span->blueStep;
188 zoomed.alphaStep = span->alphaStep;
189 /* we'll generate an array of depth values */
190 zoomed.interpMask = span->interpMask & ~SPAN_Z;
191 zoomed.arrayMask |= SPAN_Z;
192 ASSERT(span->arrayMask & SPAN_Z);
193 }
194 else {
195 _mesa_problem(ctx, "Bad format in zoom_span");
196 return;
197 }
198
199 /* zoom the span horizontally */
200 if (format == GL_RGBA) {
201 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
202 const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
203 GLint i;
204 for (i = 0; i < zoomedWidth; i++) {
205 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
206 ASSERT(j >= 0);
207 ASSERT(j < (GLint) span->end);
208 COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
209 }
210 }
211 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
212 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
213 GLint i;
214 for (i = 0; i < zoomedWidth; i++) {
215 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
216 ASSERT(j >= 0);
217 ASSERT(j < (GLint) span->end);
218 COPY_4V(zoomed.array->rgba16[i], rgba[j]);
219 }
220 }
221 else {
222 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
223 GLint i;
224 for (i = 0; i < zoomedWidth; i++) {
225 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
226 ASSERT(j >= 0);
227 ASSERT(j < span->end);
228 COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL][i], rgba[j]);
229 }
230 }
231 }
232 else if (format == GL_RGB) {
233 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
234 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
235 GLint i;
236 for (i = 0; i < zoomedWidth; i++) {
237 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
238 ASSERT(j >= 0);
239 ASSERT(j < (GLint) span->end);
240 zoomed.array->rgba8[i][0] = rgb[j][0];
241 zoomed.array->rgba8[i][1] = rgb[j][1];
242 zoomed.array->rgba8[i][2] = rgb[j][2];
243 zoomed.array->rgba8[i][3] = 0xff;
244 }
245 }
246 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
247 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
248 GLint i;
249 for (i = 0; i < zoomedWidth; i++) {
250 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
251 ASSERT(j >= 0);
252 ASSERT(j < (GLint) span->end);
253 zoomed.array->rgba16[i][0] = rgb[j][0];
254 zoomed.array->rgba16[i][1] = rgb[j][1];
255 zoomed.array->rgba16[i][2] = rgb[j][2];
256 zoomed.array->rgba16[i][3] = 0xffff;
257 }
258 }
259 else {
260 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
261 GLint i;
262 for (i = 0; i < zoomedWidth; i++) {
263 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
264 ASSERT(j >= 0);
265 ASSERT(j < span->end);
266 zoomed.array->attribs[FRAG_ATTRIB_COL][i][0] = rgb[j][0];
267 zoomed.array->attribs[FRAG_ATTRIB_COL][i][1] = rgb[j][1];
268 zoomed.array->attribs[FRAG_ATTRIB_COL][i][2] = rgb[j][2];
269 zoomed.array->attribs[FRAG_ATTRIB_COL][i][3] = 1.0F;
270 }
271 }
272 }
273 else if (format == GL_DEPTH_COMPONENT) {
274 const GLuint *zValues = (const GLuint *) src;
275 GLint i;
276 for (i = 0; i < zoomedWidth; i++) {
277 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
278 ASSERT(j >= 0);
279 ASSERT(j < (GLint) span->end);
280 zoomed.array->z[i] = zValues[j];
281 }
282 /* Now, fall into the RGB path below */
283 format = GL_RGBA;
284 }
285
286 /* write the span in rows [r0, r1) */
287 if (format == GL_RGBA || format == GL_RGB) {
288 /* Writing the span may modify the colors, so make a backup now if we're
289 * going to call _swrast_write_zoomed_span() more than once.
290 * Also, clipping may change the span end value, so store it as well.
291 */
292 const GLint end = zoomed.end; /* save */
293 void *rgbaSave;
294 const GLint pixelSize =
295 (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
296 ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
297 : 4 * sizeof(GLfloat));
298
299 rgbaSave = malloc(zoomed.end * pixelSize);
300 if (!rgbaSave) {
301 return;
302 }
303
304 if (y1 - y0 > 1) {
305 memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
306 }
307 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
308 _swrast_write_rgba_span(ctx, &zoomed);
309 zoomed.end = end; /* restore */
310 if (y1 - y0 > 1) {
311 /* restore the colors */
312 memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
313 }
314 }
315
316 free(rgbaSave);
317 }
318 }
319
320
321 void
322 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
323 const SWspan *span, const GLvoid *rgba)
324 {
325 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
326 }
327
328
329 void
330 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
331 const SWspan *span, const GLvoid *rgb)
332 {
333 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
334 }
335
336
337 void
338 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
339 const SWspan *span)
340 {
341 zoom_span(ctx, imgX, imgY, span,
342 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
343 }
344
345
346 /**
347 * Zoom/write stencil values.
348 * No per-fragment operations are applied.
349 */
350 void
351 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
352 GLint width, GLint spanX, GLint spanY,
353 const GLubyte stencil[])
354 {
355 GLubyte zoomedVals[MAX_WIDTH];
356 GLint x0, x1, y0, y1, y;
357 GLint i, zoomedWidth;
358
359 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
360 &x0, &x1, &y0, &y1)) {
361 return; /* totally clipped */
362 }
363
364 zoomedWidth = x1 - x0;
365 ASSERT(zoomedWidth > 0);
366 ASSERT(zoomedWidth <= MAX_WIDTH);
367
368 /* zoom the span horizontally */
369 for (i = 0; i < zoomedWidth; i++) {
370 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
371 ASSERT(j >= 0);
372 ASSERT(j < width);
373 zoomedVals[i] = stencil[j];
374 }
375
376 /* write the zoomed spans */
377 for (y = y0; y < y1; y++) {
378 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
379 }
380 }
381
382
383 /**
384 * Zoom/write 32-bit Z values.
385 * No per-fragment operations are applied.
386 */
387 void
388 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
389 GLint width, GLint spanX, GLint spanY,
390 const GLuint *zVals)
391 {
392 struct gl_renderbuffer *rb =
393 ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
394 GLuint zoomedVals[MAX_WIDTH];
395 GLint x0, x1, y0, y1, y;
396 GLint i, zoomedWidth;
397
398 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
399 &x0, &x1, &y0, &y1)) {
400 return; /* totally clipped */
401 }
402
403 zoomedWidth = x1 - x0;
404 ASSERT(zoomedWidth > 0);
405 ASSERT(zoomedWidth <= MAX_WIDTH);
406
407 /* zoom the span horizontally */
408 for (i = 0; i < zoomedWidth; i++) {
409 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
410 ASSERT(j >= 0);
411 ASSERT(j < width);
412 zoomedVals[i] = zVals[j];
413 }
414
415 /* write the zoomed spans */
416 for (y = y0; y < y1; y++) {
417 GLubyte *dst = _swrast_pixel_address(rb, x0, y);
418 _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
419 }
420 }