1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  * 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 
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
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)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
unzoom_x(GLfloat zoomX,GLint imageX,GLint zx)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.0F)
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
zoom_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * src,GLenum format)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(1, sizeof(SWspanarrays));
146       if (!swrast->ZoomedArrays)
147          return;
148    }
149 
150    zoomedWidth = x1 - x0;
151    assert(zoomedWidth > 0);
152    assert(zoomedWidth <= SWRAST_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[VARYING_SLOT_COL0];
169 
170    COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]);
171    COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]);
172    COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]);
173 
174    zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0];
175    zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0];
176    zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_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 |= VARYING_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 < (GLint) span->end);
237             COPY_4V(zoomed.array->attribs[VARYING_SLOT_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 < (GLint) span->end);
275             zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0];
276             zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1];
277             zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2];
278             zoomed.array->attribs[VARYING_SLOT_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       void *rgbaSave;
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 
308       rgbaSave = malloc(zoomed.end * pixelSize);
309       if (!rgbaSave) {
310          return;
311       }
312 
313       if (y1 - y0 > 1) {
314          memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
315       }
316       for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
317          _swrast_write_rgba_span(ctx, &zoomed);
318          zoomed.end = end;  /* restore */
319          if (y1 - y0 > 1) {
320             /* restore the colors */
321             memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
322          }
323       }
324 
325       free(rgbaSave);
326    }
327 }
328 
329 
330 void
_swrast_write_zoomed_rgba_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * rgba)331 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
332                                const SWspan *span, const GLvoid *rgba)
333 {
334    zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
335 }
336 
337 
338 void
_swrast_write_zoomed_rgb_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * rgb)339 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
340                               const SWspan *span, const GLvoid *rgb)
341 {
342    zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
343 }
344 
345 
346 void
_swrast_write_zoomed_depth_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span)347 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
348                                 const SWspan *span)
349 {
350    zoom_span(ctx, imgX, imgY, span,
351              (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
352 }
353 
354 
355 /**
356  * Zoom/write stencil values.
357  * No per-fragment operations are applied.
358  */
359 void
_swrast_write_zoomed_stencil_span(struct gl_context * ctx,GLint imgX,GLint imgY,GLint width,GLint spanX,GLint spanY,const GLubyte stencil[])360 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
361                                   GLint width, GLint spanX, GLint spanY,
362                                   const GLubyte stencil[])
363 {
364    GLubyte *zoomedVals;
365    GLint x0, x1, y0, y1, y;
366    GLint i, zoomedWidth;
367 
368    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
369                               &x0, &x1, &y0, &y1)) {
370       return;  /* totally clipped */
371    }
372 
373    zoomedWidth = x1 - x0;
374    assert(zoomedWidth > 0);
375    assert(zoomedWidth <= SWRAST_MAX_WIDTH);
376 
377    zoomedVals = malloc(zoomedWidth * sizeof(GLubyte));
378    if (!zoomedVals)
379       return;
380 
381    /* zoom the span horizontally */
382    for (i = 0; i < zoomedWidth; i++) {
383       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
384       assert(j >= 0);
385       assert(j < width);
386       zoomedVals[i] = stencil[j];
387    }
388 
389    /* write the zoomed spans */
390    for (y = y0; y < y1; y++) {
391       _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
392    }
393 
394    free(zoomedVals);
395 }
396 
397 
398 /**
399  * Zoom/write 32-bit Z values.
400  * No per-fragment operations are applied.
401  */
402 void
_swrast_write_zoomed_z_span(struct gl_context * ctx,GLint imgX,GLint imgY,GLint width,GLint spanX,GLint spanY,const GLuint * zVals)403 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
404                             GLint width, GLint spanX, GLint spanY,
405                             const GLuint *zVals)
406 {
407    struct gl_renderbuffer *rb =
408       ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
409    GLuint *zoomedVals;
410    GLint x0, x1, y0, y1, y;
411    GLint i, zoomedWidth;
412 
413    if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
414                               &x0, &x1, &y0, &y1)) {
415       return;  /* totally clipped */
416    }
417 
418    zoomedWidth = x1 - x0;
419    assert(zoomedWidth > 0);
420    assert(zoomedWidth <= SWRAST_MAX_WIDTH);
421 
422    zoomedVals = malloc(zoomedWidth * sizeof(GLuint));
423    if (!zoomedVals)
424       return;
425 
426    /* zoom the span horizontally */
427    for (i = 0; i < zoomedWidth; i++) {
428       GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
429       assert(j >= 0);
430       assert(j < width);
431       zoomedVals[i] = zVals[j];
432    }
433 
434    /* write the zoomed spans */
435    for (y = y0; y < y1; y++) {
436       GLubyte *dst = _swrast_pixel_address(rb, x0, y);
437       _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
438    }
439 
440    free(zoomedVals);
441 }
442