mesa: Prefix main includes with dir to avoid conflicts.
[mesa.git] / src / mesa / swrast / s_zoom.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 "main/glheader.h"
26 #include "main/macros.h"
27 #include "main/imports.h"
28 #include "main/colormac.h"
29
30 #include "s_context.h"
31 #include "s_span.h"
32 #include "s_stencil.h"
33 #include "s_zoom.h"
34
35
36 /**
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
46 */
47 static GLboolean
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)
51 {
52 const struct gl_framebuffer *fb = ctx->DrawBuffer;
53 GLint c0, c1, r0, r1;
54
55 ASSERT(spanX >= imageX);
56 ASSERT(spanY >= imageY);
57
58 /*
59 * Compute destination columns: [c0, c1)
60 */
61 c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
62 c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
63 if (c1 < c0) {
64 /* swap */
65 GLint tmp = c1;
66 c1 = c0;
67 c0 = tmp;
68 }
69 c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
70 c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
71 if (c0 == c1) {
72 return GL_FALSE; /* no width */
73 }
74
75 /*
76 * Compute destination rows: [r0, r1)
77 */
78 r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
79 r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
80 if (r1 < r0) {
81 /* swap */
82 GLint tmp = r1;
83 r1 = r0;
84 r0 = tmp;
85 }
86 r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
87 r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
88 if (r0 == r1) {
89 return GL_FALSE; /* no height */
90 }
91
92 *x0 = c0;
93 *x1 = c1;
94 *y0 = r0;
95 *y1 = r1;
96
97 return GL_TRUE;
98 }
99
100
101 /**
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
104 * is at 'imageX'.
105 * return corresponding x coord in the original, unzoomed image.
106 * This can use this for unzooming X or Y values.
107 */
108 static INLINE GLint
109 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
110 {
111 /*
112 zx = imageX + (x - imageX) * zoomX;
113 zx - imageX = (x - imageX) * zoomX;
114 (zx - imageX) / zoomX = x - imageX;
115 */
116 GLint x;
117 if (zoomX < 0.0)
118 zx++;
119 x = imageX + (GLint) ((zx - imageX) / zoomX);
120 return x;
121 }
122
123
124
125 /**
126 * Helper function called from _swrast_write_zoomed_rgba/rgb/
127 * index/depth_span().
128 */
129 static void
130 zoom_span( GLcontext *ctx, GLint imgX, GLint imgY, const SWspan *span,
131 const GLvoid *src, GLenum format )
132 {
133 SWspan zoomed;
134 SWspanarrays zoomed_arrays; /* this is big! */
135 GLint x0, x1, y0, y1;
136 GLint zoomedWidth;
137
138 if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
139 &x0, &x1, &y0, &y1)) {
140 return; /* totally clipped */
141 }
142
143 zoomedWidth = x1 - x0;
144 ASSERT(zoomedWidth > 0);
145 ASSERT(zoomedWidth <= MAX_WIDTH);
146
147 /* no pixel arrays! must be horizontal spans. */
148 ASSERT((span->arrayMask & SPAN_XY) == 0);
149 ASSERT(span->primitive == GL_BITMAP);
150
151 INIT_SPAN(zoomed, GL_BITMAP);
152 zoomed.x = x0;
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;
160 else
161 zoomed_arrays.rgba = (GLchan (*)[4]) zoomed_arrays.attribs[FRAG_ATTRIB_COL0];
162
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]);
166
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];
170
171 if (format == GL_RGBA || format == GL_RGB) {
172 /* copy Z info */
173 zoomed.z = span->z;
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);
180 }
181 else if (format == GL_COLOR_INDEX) {
182 /* copy Z info */
183 zoomed.z = span->z;
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);
189 }
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);
204 }
205 else {
206 _mesa_problem(ctx, "Bad format in zoom_span");
207 return;
208 }
209
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;
214 GLint i;
215 for (i = 0; i < zoomedWidth; i++) {
216 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
217 ASSERT(j >= 0);
218 ASSERT(j < (GLint) span->end);
219 COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
220 }
221 }
222 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
223 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
224 GLint i;
225 for (i = 0; i < zoomedWidth; i++) {
226 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
227 ASSERT(j >= 0);
228 ASSERT(j < (GLint) span->end);
229 COPY_4V(zoomed.array->rgba16[i], rgba[j]);
230 }
231 }
232 else {
233 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
234 GLint i;
235 for (i = 0; i < zoomedWidth; i++) {
236 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
237 ASSERT(j >= 0);
238 ASSERT(j < span->end);
239 COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL0][i], rgba[j]);
240 }
241 }
242 }
243 else if (format == GL_RGB) {
244 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
245 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
246 GLint i;
247 for (i = 0; i < zoomedWidth; i++) {
248 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
249 ASSERT(j >= 0);
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;
255 }
256 }
257 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
258 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
259 GLint i;
260 for (i = 0; i < zoomedWidth; i++) {
261 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
262 ASSERT(j >= 0);
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;
268 }
269 }
270 else {
271 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
272 GLint i;
273 for (i = 0; i < zoomedWidth; i++) {
274 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
275 ASSERT(j >= 0);
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;
281 }
282 }
283 }
284 else if (format == GL_COLOR_INDEX) {
285 const GLuint *indexes = (const GLuint *) src;
286 GLint i;
287 for (i = 0; i < zoomedWidth; i++) {
288 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
289 ASSERT(j >= 0);
290 ASSERT(j < (GLint) span->end);
291 zoomed.array->index[i] = indexes[j];
292 }
293 }
294 else if (format == GL_DEPTH_COMPONENT) {
295 const GLuint *zValues = (const GLuint *) src;
296 GLint i;
297 for (i = 0; i < zoomedWidth; i++) {
298 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
299 ASSERT(j >= 0);
300 ASSERT(j < (GLint) span->end);
301 zoomed.array->z[i] = zValues[j];
302 }
303 /* Now, fall into either the RGB or COLOR_INDEX path below */
304 format = ctx->Visual.rgbMode ? GL_RGBA : GL_COLOR_INDEX;
305 }
306
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.
312 */
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));
319 if (y1 - y0 > 1) {
320 MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
321 }
322 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
323 _swrast_write_rgba_span(ctx, &zoomed);
324 zoomed.end = end; /* restore */
325 if (y1 - y0 > 1) {
326 /* restore the colors */
327 MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
328 }
329 }
330 }
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 */
335 if (y1 - y0 > 1) {
336 MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
337 }
338 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
339 _swrast_write_index_span(ctx, &zoomed);
340 zoomed.end = end; /* restore */
341 if (y1 - y0 > 1) {
342 /* restore the colors */
343 MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
344 }
345 }
346 }
347 }
348
349
350 void
351 _swrast_write_zoomed_rgba_span(GLcontext *ctx, GLint imgX, GLint imgY,
352 const SWspan *span, const GLvoid *rgba)
353 {
354 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
355 }
356
357
358 void
359 _swrast_write_zoomed_rgb_span(GLcontext *ctx, GLint imgX, GLint imgY,
360 const SWspan *span, const GLvoid *rgb)
361 {
362 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
363 }
364
365
366 void
367 _swrast_write_zoomed_index_span(GLcontext *ctx, GLint imgX, GLint imgY,
368 const SWspan *span)
369 {
370 zoom_span(ctx, imgX, imgY, span,
371 (const GLvoid *) span->array->index, GL_COLOR_INDEX);
372 }
373
374
375 void
376 _swrast_write_zoomed_depth_span(GLcontext *ctx, GLint imgX, GLint imgY,
377 const SWspan *span)
378 {
379 zoom_span(ctx, imgX, imgY, span,
380 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
381 }
382
383
384 /**
385 * Zoom/write stencil values.
386 * No per-fragment operations are applied.
387 */
388 void
389 _swrast_write_zoomed_stencil_span(GLcontext *ctx, GLint imgX, GLint imgY,
390 GLint width, GLint spanX, GLint spanY,
391 const GLstencil stencil[])
392 {
393 GLstencil zoomedVals[MAX_WIDTH];
394 GLint x0, x1, y0, y1, y;
395 GLint i, zoomedWidth;
396
397 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
398 &x0, &x1, &y0, &y1)) {
399 return; /* totally clipped */
400 }
401
402 zoomedWidth = x1 - x0;
403 ASSERT(zoomedWidth > 0);
404 ASSERT(zoomedWidth <= MAX_WIDTH);
405
406 /* zoom the span horizontally */
407 for (i = 0; i < zoomedWidth; i++) {
408 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
409 ASSERT(j >= 0);
410 ASSERT(j < width);
411 zoomedVals[i] = stencil[j];
412 }
413
414 /* write the zoomed spans */
415 for (y = y0; y < y1; y++) {
416 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
417 }
418 }
419
420
421 /**
422 * Zoom/write z values (16 or 32-bit).
423 * No per-fragment operations are applied.
424 */
425 void
426 _swrast_write_zoomed_z_span(GLcontext *ctx, GLint imgX, GLint imgY,
427 GLint width, GLint spanX, GLint spanY,
428 const GLvoid *z)
429 {
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;
435
436 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
437 &x0, &x1, &y0, &y1)) {
438 return; /* totally clipped */
439 }
440
441 zoomedWidth = x1 - x0;
442 ASSERT(zoomedWidth > 0);
443 ASSERT(zoomedWidth <= MAX_WIDTH);
444
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;
449 ASSERT(j >= 0);
450 ASSERT(j < width);
451 zoomedVals16[i] = ((GLushort *) z)[j];
452 }
453 z = zoomedVals16;
454 }
455 else {
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;
459 ASSERT(j >= 0);
460 ASSERT(j < width);
461 zoomedVals32[i] = ((GLuint *) z)[j];
462 }
463 z = zoomedVals32;
464 }
465
466 /* write the zoomed spans */
467 for (y = y0; y < y1; y++) {
468 rb->PutRow(ctx, rb, zoomedWidth, x0, y, z, NULL);
469 }
470 }