s_zoom.c revision e197de56cdb86835f1437688a9161cd909792d80
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 */
47static GLboolean
48compute_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 */
108static INLINE GLint
109unzoom_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 */
129static void
130zoom_span( GLcontext *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_COLOR_INDEX) {
189      /* copy Z info */
190      zoomed.z = span->z;
191      zoomed.zStep = span->zStep;
192      /* we'll generate an array of color indexes */
193      zoomed.interpMask = span->interpMask & ~SPAN_INDEX;
194      zoomed.arrayMask |= SPAN_INDEX;
195      ASSERT(span->arrayMask & SPAN_INDEX);
196   }
197   else if (format == GL_DEPTH_COMPONENT) {
198      /* Copy color info */
199      zoomed.red = span->red;
200      zoomed.green = span->green;
201      zoomed.blue = span->blue;
202      zoomed.alpha = span->alpha;
203      zoomed.redStep = span->redStep;
204      zoomed.greenStep = span->greenStep;
205      zoomed.blueStep = span->blueStep;
206      zoomed.alphaStep = span->alphaStep;
207      /* we'll generate an array of depth values */
208      zoomed.interpMask = span->interpMask & ~SPAN_Z;
209      zoomed.arrayMask |= SPAN_Z;
210      ASSERT(span->arrayMask & SPAN_Z);
211   }
212   else {
213      _mesa_problem(ctx, "Bad format in zoom_span");
214      return;
215   }
216
217   /* zoom the span horizontally */
218   if (format == GL_RGBA) {
219      if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
220         const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
221         GLint i;
222         for (i = 0; i < zoomedWidth; i++) {
223            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
224            ASSERT(j >= 0);
225            ASSERT(j < (GLint) span->end);
226            COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
227         }
228      }
229      else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
230         const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
231         GLint i;
232         for (i = 0; i < zoomedWidth; i++) {
233            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
234            ASSERT(j >= 0);
235            ASSERT(j < (GLint) span->end);
236            COPY_4V(zoomed.array->rgba16[i], rgba[j]);
237         }
238      }
239      else {
240         const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
241         GLint i;
242         for (i = 0; i < zoomedWidth; i++) {
243            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
244            ASSERT(j >= 0);
245            ASSERT(j < span->end);
246            COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL0][i], rgba[j]);
247         }
248      }
249   }
250   else if (format == GL_RGB) {
251      if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
252         const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
253         GLint i;
254         for (i = 0; i < zoomedWidth; i++) {
255            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
256            ASSERT(j >= 0);
257            ASSERT(j < (GLint) span->end);
258            zoomed.array->rgba8[i][0] = rgb[j][0];
259            zoomed.array->rgba8[i][1] = rgb[j][1];
260            zoomed.array->rgba8[i][2] = rgb[j][2];
261            zoomed.array->rgba8[i][3] = 0xff;
262         }
263      }
264      else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
265         const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
266         GLint i;
267         for (i = 0; i < zoomedWidth; i++) {
268            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
269            ASSERT(j >= 0);
270            ASSERT(j < (GLint) span->end);
271            zoomed.array->rgba16[i][0] = rgb[j][0];
272            zoomed.array->rgba16[i][1] = rgb[j][1];
273            zoomed.array->rgba16[i][2] = rgb[j][2];
274            zoomed.array->rgba16[i][3] = 0xffff;
275         }
276      }
277      else {
278         const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
279         GLint i;
280         for (i = 0; i < zoomedWidth; i++) {
281            GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
282            ASSERT(j >= 0);
283            ASSERT(j < span->end);
284            zoomed.array->attribs[FRAG_ATTRIB_COL0][i][0] = rgb[j][0];
285            zoomed.array->attribs[FRAG_ATTRIB_COL0][i][1] = rgb[j][1];
286            zoomed.array->attribs[FRAG_ATTRIB_COL0][i][2] = rgb[j][2];
287            zoomed.array->attribs[FRAG_ATTRIB_COL0][i][3] = 1.0F;
288         }
289      }
290   }
291   else if (format == GL_COLOR_INDEX) {
292      const GLuint *indexes = (const GLuint *) src;
293      GLint i;
294      for (i = 0; i < zoomedWidth; i++) {
295         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
296         ASSERT(j >= 0);
297         ASSERT(j < (GLint) span->end);
298         zoomed.array->index[i] = indexes[j];
299      }
300   }
301   else if (format == GL_DEPTH_COMPONENT) {
302      const GLuint *zValues = (const GLuint *) src;
303      GLint i;
304      for (i = 0; i < zoomedWidth; i++) {
305         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
306         ASSERT(j >= 0);
307         ASSERT(j < (GLint) span->end);
308         zoomed.array->z[i] = zValues[j];
309      }
310      /* Now, fall into either the RGB or COLOR_INDEX path below */
311      format = ctx->Visual.rgbMode ? GL_RGBA : GL_COLOR_INDEX;
312   }
313
314   /* write the span in rows [r0, r1) */
315   if (format == GL_RGBA || format == GL_RGB) {
316      /* Writing the span may modify the colors, so make a backup now if we're
317       * going to call _swrast_write_zoomed_span() more than once.
318       * Also, clipping may change the span end value, so store it as well.
319       */
320      const GLint end = zoomed.end; /* save */
321      GLuint rgbaSave[MAX_WIDTH][4];
322      const GLint pixelSize =
323         (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
324         ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
325          : 4 * sizeof(GLfloat));
326      if (y1 - y0 > 1) {
327         memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
328      }
329      for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
330         _swrast_write_rgba_span(ctx, &zoomed);
331         zoomed.end = end;  /* restore */
332         if (y1 - y0 > 1) {
333            /* restore the colors */
334            memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
335         }
336      }
337   }
338   else if (format == GL_COLOR_INDEX) {
339      /* use specular color array for temp storage */
340      GLuint *indexSave = (GLuint *) zoomed.array->attribs[FRAG_ATTRIB_FOGC];
341      const GLint end = zoomed.end; /* save */
342      if (y1 - y0 > 1) {
343         memcpy(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
344      }
345      for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
346         _swrast_write_index_span(ctx, &zoomed);
347         zoomed.end = end;  /* restore */
348         if (y1 - y0 > 1) {
349            /* restore the colors */
350            memcpy(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
351         }
352      }
353   }
354}
355
356
357void
358_swrast_write_zoomed_rgba_span(GLcontext *ctx, GLint imgX, GLint imgY,
359                               const SWspan *span, const GLvoid *rgba)
360{
361   zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
362}
363
364
365void
366_swrast_write_zoomed_rgb_span(GLcontext *ctx, GLint imgX, GLint imgY,
367                              const SWspan *span, const GLvoid *rgb)
368{
369   zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
370}
371
372
373void
374_swrast_write_zoomed_index_span(GLcontext *ctx, GLint imgX, GLint imgY,
375                                const SWspan *span)
376{
377   zoom_span(ctx, imgX, imgY, span,
378             (const GLvoid *) span->array->index, GL_COLOR_INDEX);
379}
380
381
382void
383_swrast_write_zoomed_depth_span(GLcontext *ctx, GLint imgX, GLint imgY,
384                                const SWspan *span)
385{
386   zoom_span(ctx, imgX, imgY, span,
387             (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
388}
389
390
391/**
392 * Zoom/write stencil values.
393 * No per-fragment operations are applied.
394 */
395void
396_swrast_write_zoomed_stencil_span(GLcontext *ctx, GLint imgX, GLint imgY,
397                                  GLint width, GLint spanX, GLint spanY,
398                                  const GLstencil stencil[])
399{
400   GLstencil zoomedVals[MAX_WIDTH];
401   GLint x0, x1, y0, y1, y;
402   GLint i, zoomedWidth;
403
404   if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
405                              &x0, &x1, &y0, &y1)) {
406      return;  /* totally clipped */
407   }
408
409   zoomedWidth = x1 - x0;
410   ASSERT(zoomedWidth > 0);
411   ASSERT(zoomedWidth <= MAX_WIDTH);
412
413   /* zoom the span horizontally */
414   for (i = 0; i < zoomedWidth; i++) {
415      GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
416      ASSERT(j >= 0);
417      ASSERT(j < width);
418      zoomedVals[i] = stencil[j];
419   }
420
421   /* write the zoomed spans */
422   for (y = y0; y < y1; y++) {
423      _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
424   }
425}
426
427
428/**
429 * Zoom/write z values (16 or 32-bit).
430 * No per-fragment operations are applied.
431 */
432void
433_swrast_write_zoomed_z_span(GLcontext *ctx, GLint imgX, GLint imgY,
434                            GLint width, GLint spanX, GLint spanY,
435                            const GLvoid *z)
436{
437   struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer;
438   GLushort zoomedVals16[MAX_WIDTH];
439   GLuint zoomedVals32[MAX_WIDTH];
440   GLint x0, x1, y0, y1, y;
441   GLint i, zoomedWidth;
442
443   if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
444                              &x0, &x1, &y0, &y1)) {
445      return;  /* totally clipped */
446   }
447
448   zoomedWidth = x1 - x0;
449   ASSERT(zoomedWidth > 0);
450   ASSERT(zoomedWidth <= MAX_WIDTH);
451
452   /* zoom the span horizontally */
453   if (rb->DataType == GL_UNSIGNED_SHORT) {
454      for (i = 0; i < zoomedWidth; i++) {
455         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
456         ASSERT(j >= 0);
457         ASSERT(j < width);
458         zoomedVals16[i] = ((GLushort *) z)[j];
459      }
460      z = zoomedVals16;
461   }
462   else {
463      ASSERT(rb->DataType == GL_UNSIGNED_INT);
464      for (i = 0; i < zoomedWidth; i++) {
465         GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
466         ASSERT(j >= 0);
467         ASSERT(j < width);
468         zoomedVals32[i] = ((GLuint *) z)[j];
469      }
470      z = zoomedVals32;
471   }
472
473   /* write the zoomed spans */
474   for (y = y0; y < y1; y++) {
475      rb->PutRow(ctx, rb, zoomedWidth, x0, y, z, NULL);
476   }
477}
478