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/format_pack.h"
29 #include "main/colormac.h"
30 
31 #include "s_context.h"
32 #include "s_span.h"
33 #include "s_stencil.h"
34 #include "s_zoom.h"
35 
36 
37 /**
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
47  */
48 static GLboolean
compute_zoomed_bounds(struct gl_context * ctx,GLint imageX,GLint imageY,GLint spanX,GLint spanY,GLint width,GLint * x0,GLint * x1,GLint * y0,GLint * y1)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)
52 {
53    const struct gl_framebuffer *fb = ctx->DrawBuffer;
54    GLint c0, c1, r0, r1;
55 
56    ASSERT(spanX >= imageX);
57    ASSERT(spanY >= imageY);
58 
59    /*
60     * Compute destination columns: [c0, c1)
61     */
62    c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
63    c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
64    if (c1 < c0) {
65       /* swap */
66       GLint tmp = c1;
67       c1 = c0;
68       c0 = tmp;
69    }
70    c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
71    c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
72    if (c0 == c1) {
73       return GL_FALSE; /* no width */
74    }
75 
76    /*
77     * Compute destination rows: [r0, r1)
78     */
79    r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
80    r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
81    if (r1 < r0) {
82       /* swap */
83       GLint tmp = r1;
84       r1 = r0;
85       r0 = tmp;
86    }
87    r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
88    r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
89    if (r0 == r1) {
90       return GL_FALSE; /* no height */
91    }
92 
93    *x0 = c0;
94    *x1 = c1;
95    *y0 = r0;
96    *y1 = r1;
97 
98    return GL_TRUE;
99 }
100 
101 
102 /**
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
105  * is at 'imageX'.
106  * return corresponding x coord in the original, unzoomed image.
107  * This can use this for unzooming X or Y values.
108  */
109 static inline GLint
unzoom_x(GLfloat zoomX,GLint imageX,GLint zx)110 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
111 {
112    /*
113    zx = imageX + (x - imageX) * zoomX;
114    zx - imageX = (x - imageX) * zoomX;
115    (zx - imageX) / zoomX = x - imageX;
116    */
117    GLint x;
118    if (zoomX < 0.0)
119       zx++;
120    x = imageX + (GLint) ((zx - imageX) / zoomX);
121    return x;
122 }
123 
124 
125 
126 /**
127  * Helper function called from _swrast_write_zoomed_rgba/rgb/
128  * index/depth_span().
129  */
130 static void
zoom_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * src,GLenum format)131 zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
132            const GLvoid *src, GLenum format )
133 {
134    SWcontext *swrast = SWRAST_CONTEXT(ctx);
135    SWspan zoomed;
136    GLint x0, x1, y0, y1;
137    GLint zoomedWidth;
138 
139    if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
140                               &x0, &x1, &y0, &y1)) {
141       return;  /* totally clipped */
142    }
143 
144    if (!swrast->ZoomedArrays) {
145       /* allocate on demand */
146       swrast->ZoomedArrays = (SWspanarrays *) CALLOC(sizeof(SWspanarrays));
147       if (!swrast->ZoomedArrays)
148          return;
149    }
150 
151    zoomedWidth = x1 - x0;
152    ASSERT(zoomedWidth > 0);
153    ASSERT(zoomedWidth <= SWRAST_MAX_WIDTH);
154 
155    /* no pixel arrays! must be horizontal spans. */
156    ASSERT((span->arrayMask & SPAN_XY) == 0);
157    ASSERT(span->primitive == GL_BITMAP);
158 
159    INIT_SPAN(zoomed, GL_BITMAP);
160    zoomed.x = x0;
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;
168    else
169       zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[FRAG_ATTRIB_COL0];
170 
171    COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]);
172    COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]);
173    COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]);
174 
175    zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0];
176    zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0];
177    zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0];
178 
179    if (format == GL_RGBA || format == GL_RGB) {
180       /* copy Z info */
181       zoomed.z = span->z;
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 |= FRAG_BIT_COL0;  /* we'll produce these values */
187       ASSERT(span->arrayMask & SPAN_RGBA);
188    }
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);
203    }
204    else {
205       _mesa_problem(ctx, "Bad format in zoom_span");
206       return;
207    }
208 
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;
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_4UBV(zoomed.array->rgba8[i], rgba[j]);
219          }
220       }
221       else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
222          const GLushort (*rgba)[4] = (const GLushort (*)[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 < (GLint) span->end);
228             COPY_4V(zoomed.array->rgba16[i], rgba[j]);
229          }
230       }
231       else {
232          const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
233          GLint i;
234          for (i = 0; i < zoomedWidth; i++) {
235             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
236             ASSERT(j >= 0);
237             ASSERT(j < span->end);
238             COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL0][i], rgba[j]);
239          }
240       }
241    }
242    else if (format == GL_RGB) {
243       if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
244          const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
245          GLint i;
246          for (i = 0; i < zoomedWidth; i++) {
247             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
248             ASSERT(j >= 0);
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;
254          }
255       }
256       else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
257          const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
258          GLint i;
259          for (i = 0; i < zoomedWidth; i++) {
260             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
261             ASSERT(j >= 0);
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;
267          }
268       }
269       else {
270          const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
271          GLint i;
272          for (i = 0; i < zoomedWidth; i++) {
273             GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
274             ASSERT(j >= 0);
275             ASSERT(j < span->end);
276             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][0] = rgb[j][0];
277             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][1] = rgb[j][1];
278             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][2] = rgb[j][2];
279             zoomed.array->attribs[FRAG_ATTRIB_COL0][i][3] = 1.0F;
280          }
281       }
282    }
283    else if (format == GL_DEPTH_COMPONENT) {
284       const GLuint *zValues = (const GLuint *) src;
285       GLint i;
286       for (i = 0; i < zoomedWidth; i++) {
287          GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
288          ASSERT(j >= 0);
289          ASSERT(j < (GLint) span->end);
290          zoomed.array->z[i] = zValues[j];
291       }
292       /* Now, fall into the RGB path below */
293       format = GL_RGBA;
294    }
295 
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.
301        */
302       const GLint end = zoomed.end; /* save */
303       void *rgbaSave;
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));
308 
309       rgbaSave = malloc(zoomed.end * pixelSize);
310       if (!rgbaSave) {
311          return;
312       }
313 
314       if (y1 - y0 > 1) {
315          memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
316       }
317       for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
318          _swrast_write_rgba_span(ctx, &zoomed);
319          zoomed.end = end;  /* restore */
320          if (y1 - y0 > 1) {
321             /* restore the colors */
322             memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
323          }
324       }
325 
326       free(rgbaSave);
327    }
328 }
329 
330 
331 void
_swrast_write_zoomed_rgba_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * rgba)332 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
333                                const SWspan *span, const GLvoid *rgba)
334 {
335    zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
336 }
337 
338 
339 void
_swrast_write_zoomed_rgb_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * rgb)340 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
341                               const SWspan *span, const GLvoid *rgb)
342 {
343    zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
344 }
345 
346 
347 void
_swrast_write_zoomed_depth_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span)348 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
349                                 const SWspan *span)
350 {
351    zoom_span(ctx, imgX, imgY, span,
352              (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
353 }
354 
355 
356 /**
357  * Zoom/write stencil values.
358  * No per-fragment operations are applied.
359  */
360 void
_swrast_write_zoomed_stencil_span(struct gl_context * ctx,GLint imgX,GLint imgY,GLint width,GLint spanX,GLint spanY,const GLubyte stencil[])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[])
364 {
365    GLubyte *zoomedVals;
366    GLint x0, x1, y0, y1, y;
367    GLint i, zoomedWidth;
368 
369    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
370                               &x0, &x1, &y0, &y1)) {
371       return;  /* totally clipped */
372    }
373 
374    zoomedWidth = x1 - x0;
375    ASSERT(zoomedWidth > 0);
376    ASSERT(zoomedWidth <= SWRAST_MAX_WIDTH);
377 
378    zoomedVals = (GLubyte *) malloc(zoomedWidth * sizeof(GLubyte));
379    if (!zoomedVals)
380       return;
381 
382    /* zoom the span horizontally */
383    for (i = 0; i < zoomedWidth; i++) {
384       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
385       ASSERT(j >= 0);
386       ASSERT(j < width);
387       zoomedVals[i] = stencil[j];
388    }
389 
390    /* write the zoomed spans */
391    for (y = y0; y < y1; y++) {
392       _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
393    }
394 
395    free(zoomedVals);
396 }
397 
398 
399 /**
400  * Zoom/write 32-bit Z values.
401  * No per-fragment operations are applied.
402  */
403 void
_swrast_write_zoomed_z_span(struct gl_context * ctx,GLint imgX,GLint imgY,GLint width,GLint spanX,GLint spanY,const GLuint * zVals)404 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
405                             GLint width, GLint spanX, GLint spanY,
406                             const GLuint *zVals)
407 {
408    struct gl_renderbuffer *rb =
409       ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
410    GLuint *zoomedVals;
411    GLint x0, x1, y0, y1, y;
412    GLint i, zoomedWidth;
413 
414    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
415                               &x0, &x1, &y0, &y1)) {
416       return;  /* totally clipped */
417    }
418 
419    zoomedWidth = x1 - x0;
420    ASSERT(zoomedWidth > 0);
421    ASSERT(zoomedWidth <= SWRAST_MAX_WIDTH);
422 
423    zoomedVals = (GLuint *) malloc(zoomedWidth * sizeof(GLuint));
424    if (!zoomedVals)
425       return;
426 
427    /* zoom the span horizontally */
428    for (i = 0; i < zoomedWidth; i++) {
429       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
430       ASSERT(j >= 0);
431       ASSERT(j < width);
432       zoomedVals[i] = zVals[j];
433    }
434 
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);
439    }
440 
441    free(zoomedVals);
442 }
443