Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / 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 "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(struct gl_context *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( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
131            const GLvoid *src, GLenum format )
132 {
133    SWcontext *swrast = SWRAST_CONTEXT(ctx);
134    SWspan zoomed;
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    if (!swrast->ZoomedArrays) {
144       /* allocate on demand */
145       swrast->ZoomedArrays = (SWspanarrays *) CALLOC(sizeof(SWspanarrays));
146       if (!swrast->ZoomedArrays)
147          return;
148    }
149
150    zoomedWidth = x1 - x0;
151    ASSERT(zoomedWidth > 0);
152    ASSERT(zoomedWidth <= MAX_WIDTH);
153
154    /* no pixel arrays! must be horizontal spans. */
155    ASSERT((span->arrayMask & SPAN_XY) == 0);
156    ASSERT(span->primitive == GL_BITMAP);
157
158    INIT_SPAN(zoomed, GL_BITMAP);
159    zoomed.x = x0;
160    zoomed.end = zoomedWidth;
161    zoomed.array = swrast->ZoomedArrays;
162    zoomed.array->ChanType = span->array->ChanType;
163    if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
164       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
165    else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
166       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
167    else
168       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[FRAG_ATTRIB_COL0];
169
170    COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]);
171    COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]);
172    COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]);
173
174    zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0];
175    zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0];
176    zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0];
177
178    if (format == GL_RGBA || format == GL_RGB) {
179       /* copy Z info */
180       zoomed.z = span->z;
181       zoomed.zStep = span->zStep;
182       /* we'll generate an array of colorss */
183       zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
184       zoomed.arrayMask |= SPAN_RGBA;
185       zoomed.arrayAttribs |= FRAG_BIT_COL0;  /* we'll produce these values */
186       ASSERT(span->arrayMask & SPAN_RGBA);
187    }
188    else if (format == GL_DEPTH_COMPONENT) {
189       /* Copy color info */
190       zoomed.red = span->red;
191       zoomed.green = span->green;
192       zoomed.blue = span->blue;
193       zoomed.alpha = span->alpha;
194       zoomed.redStep = span->redStep;
195       zoomed.greenStep = span->greenStep;
196       zoomed.blueStep = span->blueStep;
197       zoomed.alphaStep = span->alphaStep;
198       /* we'll generate an array of depth values */
199       zoomed.interpMask = span->interpMask & ~SPAN_Z;
200       zoomed.arrayMask |= SPAN_Z;
201       ASSERT(span->arrayMask & SPAN_Z);
202    }
203    else {
204       _mesa_problem(ctx, "Bad format in zoom_span");
205       return;
206    }
207
208    /* zoom the span horizontally */
209    if (format == GL_RGBA) {
210       if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
211          const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
212          GLint i;
213          for (i = 0; i < zoomedWidth; i++) {
214             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
215             ASSERT(j >= 0);
216             ASSERT(j < (GLint) span->end);
217             COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
218          }
219       }
220       else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
221          const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
222          GLint i;
223          for (i = 0; i < zoomedWidth; i++) {
224             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
225             ASSERT(j >= 0);
226             ASSERT(j < (GLint) span->end);
227             COPY_4V(zoomed.array->rgba16[i], rgba[j]);
228          }
229       }
230       else {
231          const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
232          GLint i;
233          for (i = 0; i < zoomedWidth; i++) {
234             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
235             ASSERT(j >= 0);
236             ASSERT(j < span->end);
237             COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL0][i], rgba[j]);
238          }
239       }
240    }
241    else if (format == GL_RGB) {
242       if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
243          const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
244          GLint i;
245          for (i = 0; i < zoomedWidth; i++) {
246             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
247             ASSERT(j >= 0);
248             ASSERT(j < (GLint) span->end);
249             zoomed.array->rgba8[i][0] = rgb[j][0];
250             zoomed.array->rgba8[i][1] = rgb[j][1];
251             zoomed.array->rgba8[i][2] = rgb[j][2];
252             zoomed.array->rgba8[i][3] = 0xff;
253          }
254       }
255       else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
256          const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
257          GLint i;
258          for (i = 0; i < zoomedWidth; i++) {
259             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
260             ASSERT(j >= 0);
261             ASSERT(j < (GLint) span->end);
262             zoomed.array->rgba16[i][0] = rgb[j][0];
263             zoomed.array->rgba16[i][1] = rgb[j][1];
264             zoomed.array->rgba16[i][2] = rgb[j][2];
265             zoomed.array->rgba16[i][3] = 0xffff;
266          }
267       }
268       else {
269          const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
270          GLint i;
271          for (i = 0; i < zoomedWidth; i++) {
272             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
273             ASSERT(j >= 0);
274             ASSERT(j < span->end);
275             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][0] = rgb[j][0];
276             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][1] = rgb[j][1];
277             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][2] = rgb[j][2];
278             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][3] = 1.0F;
279          }
280       }
281    }
282    else if (format == GL_DEPTH_COMPONENT) {
283       const GLuint *zValues = (const GLuint *) src;
284       GLint i;
285       for (i = 0; i < zoomedWidth; i++) {
286          GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
287          ASSERT(j >= 0);
288          ASSERT(j < (GLint) span->end);
289          zoomed.array->z[i] = zValues[j];
290       }
291       /* Now, fall into the RGB path below */
292       format = GL_RGBA;
293    }
294
295    /* write the span in rows [r0, r1) */
296    if (format == GL_RGBA || format == GL_RGB) {
297       /* Writing the span may modify the colors, so make a backup now if we're
298        * going to call _swrast_write_zoomed_span() more than once.
299        * Also, clipping may change the span end value, so store it as well.
300        */
301       const GLint end = zoomed.end; /* save */
302       GLuint rgbaSave[MAX_WIDTH][4];
303       const GLint pixelSize =
304          (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
305          ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
306           : 4 * sizeof(GLfloat));
307       if (y1 - y0 > 1) {
308          memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
309       }
310       for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
311          _swrast_write_rgba_span(ctx, &zoomed);
312          zoomed.end = end;  /* restore */
313          if (y1 - y0 > 1) {
314             /* restore the colors */
315             memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
316          }
317       }
318    }
319 }
320
321
322 void
323 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
324                                const SWspan *span, const GLvoid *rgba)
325 {
326    zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
327 }
328
329
330 void
331 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
332                               const SWspan *span, const GLvoid *rgb)
333 {
334    zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
335 }
336
337
338 void
339 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
340                                 const SWspan *span)
341 {
342    zoom_span(ctx, imgX, imgY, span,
343              (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
344 }
345
346
347 /**
348  * Zoom/write stencil values.
349  * No per-fragment operations are applied.
350  */
351 void
352 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
353                                   GLint width, GLint spanX, GLint spanY,
354                                   const GLstencil stencil[])
355 {
356    GLstencil zoomedVals[MAX_WIDTH];
357    GLint x0, x1, y0, y1, y;
358    GLint i, zoomedWidth;
359
360    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
361                               &x0, &x1, &y0, &y1)) {
362       return;  /* totally clipped */
363    }
364
365    zoomedWidth = x1 - x0;
366    ASSERT(zoomedWidth > 0);
367    ASSERT(zoomedWidth <= MAX_WIDTH);
368
369    /* zoom the span horizontally */
370    for (i = 0; i < zoomedWidth; i++) {
371       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
372       ASSERT(j >= 0);
373       ASSERT(j < width);
374       zoomedVals[i] = stencil[j];
375    }
376
377    /* write the zoomed spans */
378    for (y = y0; y < y1; y++) {
379       _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
380    }
381 }
382
383
384 /**
385  * Zoom/write z values (16 or 32-bit).
386  * No per-fragment operations are applied.
387  */
388 void
389 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
390                             GLint width, GLint spanX, GLint spanY,
391                             const GLvoid *z)
392 {
393    struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer;
394    GLushort zoomedVals16[MAX_WIDTH];
395    GLuint zoomedVals32[MAX_WIDTH];
396    GLint x0, x1, y0, y1, y;
397    GLint i, zoomedWidth;
398
399    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
400                               &x0, &x1, &y0, &y1)) {
401       return;  /* totally clipped */
402    }
403
404    zoomedWidth = x1 - x0;
405    ASSERT(zoomedWidth > 0);
406    ASSERT(zoomedWidth <= MAX_WIDTH);
407
408    /* zoom the span horizontally */
409    if (rb->DataType == GL_UNSIGNED_SHORT) {
410       for (i = 0; i < zoomedWidth; i++) {
411          GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
412          ASSERT(j >= 0);
413          ASSERT(j < width);
414          zoomedVals16[i] = ((GLushort *) z)[j];
415       }
416       z = zoomedVals16;
417    }
418    else {
419       ASSERT(rb->DataType == GL_UNSIGNED_INT);
420       for (i = 0; i < zoomedWidth; i++) {
421          GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
422          ASSERT(j >= 0);
423          ASSERT(j < width);
424          zoomedVals32[i] = ((GLuint *) z)[j];
425       }
426       z = zoomedVals32;
427    }
428
429    /* write the zoomed spans */
430    for (y = y0; y < y1; y++) {
431       rb->PutRow(ctx, rb, zoomedWidth, x0, y, z, NULL);
432    }
433 }