s_zoom.c revision 3e37bafab0a339021354b9c78f983d05d433d735
1/*
2 * Mesa 3-D graphics library
3 * Version:  6.5
4 *
5 * Copyright (C) 1999-2005  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 "glheader.h"
26#include "macros.h"
27#include "imports.h"
28#include "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 * Helper function called from _swrast_write_zoomed_rgba/rgb/index_span().
38 */
39static void
40zoom_span( GLcontext *ctx, const struct sw_span *span,
41           const GLvoid *src, GLint y0, GLenum format, GLint skipPixels )
42{
43   GLint r0, r1, row;
44   GLint c0, c1, skipCol;
45   GLint i, j;
46   const GLuint maxWidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
47   struct sw_span zoomed;
48   struct span_arrays zoomed_arrays;  /* this is big! */
49
50   /* no pixel arrays! must be horizontal spans. */
51   ASSERT((span->arrayMask & SPAN_XY) == 0);
52   ASSERT(span->primitive == GL_BITMAP);
53
54   INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0);
55   zoomed.array = &zoomed_arrays;
56
57   /* copy fog interp info */
58   zoomed.fog = span->fog;
59   zoomed.fogStep = span->fogStep;
60   /* XXX copy texcoord info? */
61
62   if (format == GL_RGBA || format == GL_RGB) {
63      /* copy Z info */
64      zoomed.z = span->z;
65      zoomed.zStep = span->zStep;
66      /* we'll generate an array of colorss */
67      zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
68      zoomed.arrayMask |= SPAN_RGBA;
69   }
70   else if (format == GL_COLOR_INDEX) {
71      /* copy Z info */
72      zoomed.z = span->z;
73      zoomed.zStep = span->zStep;
74      /* we'll generate an array of color indexes */
75      zoomed.interpMask = span->interpMask & ~SPAN_INDEX;
76      zoomed.arrayMask |= SPAN_INDEX;
77   }
78   else {
79      assert(format == GL_DEPTH_COMPONENT);
80      /* Copy color info */
81      zoomed.red = span->red;
82      zoomed.green = span->green;
83      zoomed.blue = span->blue;
84      zoomed.alpha = span->alpha;
85      zoomed.redStep = span->redStep;
86      zoomed.greenStep = span->greenStep;
87      zoomed.blueStep = span->blueStep;
88      zoomed.alphaStep = span->alphaStep;
89      /* we'll generate an array of depth values */
90      zoomed.interpMask = span->interpMask & ~SPAN_Z;
91      zoomed.arrayMask |= SPAN_Z;
92   }
93
94   /*
95    * Compute which columns to draw: [c0, c1)
96    */
97   c0 = (GLint) (span->x + skipPixels * ctx->Pixel.ZoomX);
98   c1 = (GLint) (span->x + (skipPixels + span->end) * ctx->Pixel.ZoomX);
99   if (c0 == c1) {
100      return;
101   }
102   else if (c1 < c0) {
103      /* swap */
104      GLint ctmp = c1;
105      c1 = c0;
106      c0 = ctmp;
107   }
108   if (c0 < 0) {
109      zoomed.x = 0;
110      zoomed.start = 0;
111      zoomed.end = c1;
112      skipCol = -c0;
113   }
114   else {
115      zoomed.x = c0;
116      zoomed.start = 0;
117      zoomed.end = c1 - c0;
118      skipCol = 0;
119   }
120   if (zoomed.end > maxWidth)
121      zoomed.end = maxWidth;
122
123   /*
124    * Compute which rows to draw: [r0, r1)
125    */
126   row = span->y - y0;
127   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
128   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
129   if (r0 == r1) {
130      return;
131   }
132   else if (r1 < r0) {
133      /* swap */
134      GLint rtmp = r1;
135      r1 = r0;
136      r0 = rtmp;
137   }
138
139   ASSERT(r0 < r1);
140   ASSERT(c0 < c1);
141
142   /*
143    * Trivial clip rejection testing.
144    */
145   if (r1 < 0) /* below window */
146      return;
147   if (r0 >= (GLint) ctx->DrawBuffer->Height) /* above window */
148      return;
149   if (c1 < 0) /* left of window */
150      return;
151   if (c0 >= (GLint) ctx->DrawBuffer->Width) /* right of window */
152      return;
153
154   /* zoom the span horizontally */
155   if (format == GL_RGBA) {
156      const GLchan (*rgba)[4] = (const GLchan (*)[4]) src;
157      if (ctx->Pixel.ZoomX == -1.0F) {
158         /* common case */
159         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
160            i = span->end - (j + skipCol) - 1;
161            COPY_CHAN4(zoomed.array->rgba[j], rgba[i]);
162         }
163      }
164      else {
165         /* general solution */
166         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
167         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
168            i = (GLint) ((j + skipCol) * xscale);
169            if (ctx->Pixel.ZoomX < 0.0) {
170               ASSERT(i <= 0);
171               i = span->end + i - 1;
172            }
173            ASSERT(i >= 0);
174            ASSERT(i < (GLint)  span->end);
175            COPY_CHAN4(zoomed.array->rgba[j], rgba[i]);
176         }
177      }
178   }
179   else if (format == GL_RGB) {
180      const GLchan (*rgb)[3] = (const GLchan (*)[3]) src;
181      if (ctx->Pixel.ZoomX == -1.0F) {
182         /* common case */
183         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
184            i = span->end - (j + skipCol) - 1;
185            zoomed.array->rgba[j][0] = rgb[i][0];
186            zoomed.array->rgba[j][1] = rgb[i][1];
187            zoomed.array->rgba[j][2] = rgb[i][2];
188            zoomed.array->rgba[j][3] = CHAN_MAX;
189         }
190      }
191      else {
192         /* general solution */
193         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
194         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
195            i = (GLint) ((j + skipCol) * xscale);
196            if (ctx->Pixel.ZoomX < 0.0) {
197               ASSERT(i <= 0);
198               i = span->end + i - 1;
199            }
200            ASSERT(i >= 0);
201            ASSERT(i < (GLint) span->end);
202            zoomed.array->rgba[j][0] = rgb[i][0];
203            zoomed.array->rgba[j][1] = rgb[i][1];
204            zoomed.array->rgba[j][2] = rgb[i][2];
205            zoomed.array->rgba[j][3] = CHAN_MAX;
206         }
207      }
208   }
209   else if (format == GL_COLOR_INDEX) {
210      const GLuint *indexes = (const GLuint *) src;
211      if (ctx->Pixel.ZoomX == -1.0F) {
212         /* common case */
213         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
214            i = span->end - (j + skipCol) - 1;
215            zoomed.array->index[j] = indexes[i];
216         }
217      }
218      else {
219         /* general solution */
220         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
221         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
222            i = (GLint) ((j + skipCol) * xscale);
223            if (ctx->Pixel.ZoomX < 0.0) {
224               ASSERT(i <= 0);
225               i = span->end + i - 1;
226            }
227            ASSERT(i >= 0);
228            ASSERT(i < (GLint) span->end);
229            zoomed.array->index[j] = indexes[i];
230         }
231      }
232   }
233   else {
234      const GLuint *zValues = (const GLuint *) src;
235      assert(format == GL_DEPTH_COMPONENT);
236      if (ctx->Pixel.ZoomX == -1.0F) {
237         /* common case */
238         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
239            i = span->end - (j + skipCol) - 1;
240            zoomed.array->z[j] = zValues[i];
241         }
242      }
243      else {
244         /* general solution */
245         const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
246         for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) {
247            i = (GLint) ((j + skipCol) * xscale);
248            if (ctx->Pixel.ZoomX < 0.0) {
249               ASSERT(i <= 0);
250               i = span->end + i - 1;
251            }
252            ASSERT(i >= 0);
253            ASSERT(i < (GLint) span->end);
254            zoomed.array->z[j] = zValues[i];
255         }
256      }
257      /* Now, fall into either the RGB or COLOR_INDEX path below */
258      if (ctx->Visual.rgbMode)
259         format = GL_RGBA;
260      else
261         format = GL_COLOR_INDEX;
262   }
263
264
265   /* write the span in rows [r0, r1) */
266   if (format == GL_RGBA || format == GL_RGB) {
267      /* Writing the span may modify the colors, so make a backup now if we're
268       * going to call _swrast_write_zoomed_span() more than once.
269       * Also, clipping may change the span end value, so store it as well.
270       */
271      GLchan rgbaSave[MAX_WIDTH][4];
272      const GLint end = zoomed.end; /* save */
273      if (r1 - r0 > 1) {
274         MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * 4 * sizeof(GLchan));
275      }
276      for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
277         _swrast_write_rgba_span(ctx, &zoomed);
278         zoomed.end = end;  /* restore */
279         if (r1 - r0 > 1) {
280            /* restore the colors */
281            MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end*4 * sizeof(GLchan));
282         }
283      }
284   }
285   else if (format == GL_COLOR_INDEX) {
286      GLuint indexSave[MAX_WIDTH];
287      const GLint end = zoomed.end; /* save */
288      if (r1 - r0 > 1) {
289         MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
290      }
291      for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
292         _swrast_write_index_span(ctx, &zoomed);
293         zoomed.end = end;  /* restore */
294         if (r1 - r0 > 1) {
295            /* restore the colors */
296            MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
297         }
298      }
299   }
300}
301
302
303void
304_swrast_write_zoomed_rgba_span( GLcontext *ctx, const struct sw_span *span,
305                              CONST GLchan rgba[][4], GLint y0,
306                              GLint skipPixels )
307{
308   zoom_span(ctx, span, (const GLvoid *) rgba, y0, GL_RGBA, skipPixels);
309}
310
311
312void
313_swrast_write_zoomed_rgb_span( GLcontext *ctx, const struct sw_span *span,
314                             CONST GLchan rgb[][3], GLint y0,
315                             GLint skipPixels )
316{
317   zoom_span(ctx, span, (const GLvoid *) rgb, y0, GL_RGB, skipPixels);
318}
319
320
321void
322_swrast_write_zoomed_index_span( GLcontext *ctx, const struct sw_span *span,
323                               GLint y0, GLint skipPixels )
324{
325   zoom_span(ctx, span, (const GLvoid *) span->array->index, y0,
326             GL_COLOR_INDEX, skipPixels);
327}
328
329
330void
331_swrast_write_zoomed_depth_span( GLcontext *ctx, const struct sw_span *span,
332                                 GLint y0, GLint skipPixels )
333{
334   zoom_span(ctx, span, (const GLvoid *) span->array->z, y0,
335             GL_DEPTH_COMPONENT, skipPixels);
336}
337
338
339/*
340 * As above, but write stencil values.
341 */
342void
343_swrast_write_zoomed_stencil_span( GLcontext *ctx,
344                                 GLuint n, GLint x, GLint y,
345                                 const GLstencil stencil[], GLint y0,
346                                 GLint skipPixels )
347{
348   GLint m;
349   GLint r0, r1, row, r;
350   GLint i, j, skipcol;
351   GLstencil zstencil[MAX_WIDTH];  /* zoomed stencil values */
352   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
353
354   (void) skipPixels;  /* XXX this shouldn't be ignored */
355
356   /* compute width of output row */
357   m = (GLint) FABSF( n * ctx->Pixel.ZoomX );
358   if (m==0) {
359      return;
360   }
361   if (ctx->Pixel.ZoomX<0.0) {
362      /* adjust x coordinate for left/right mirroring */
363      x = x - m;
364   }
365
366   /* compute which rows to draw */
367   row = y - y0;
368   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
369   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
370   if (r0==r1) {
371      return;
372   }
373   else if (r1<r0) {
374      GLint rtmp = r1;
375      r1 = r0;
376      r0 = rtmp;
377   }
378
379   /* return early if r0...r1 is above or below window */
380   if (r0<0 && r1<0) {
381      /* below window */
382      return;
383   }
384   if (r0 >= (GLint) ctx->DrawBuffer->Height &&
385       r1 >= (GLint) ctx->DrawBuffer->Height) {
386      /* above window */
387      return;
388   }
389
390   /* check if left edge is outside window */
391   skipcol = 0;
392   if (x<0) {
393      skipcol = -x;
394      m += x;
395   }
396   /* make sure span isn't too long or short */
397   if (m>maxwidth) {
398      m = maxwidth;
399   }
400   else if (m<=0) {
401      return;
402   }
403
404   ASSERT( m <= MAX_WIDTH );
405
406   /* zoom the span horizontally */
407   if (ctx->Pixel.ZoomX==-1.0F) {
408      /* n==m */
409      for (j=0;j<m;j++) {
410         i = n - (j+skipcol) - 1;
411         zstencil[j] = stencil[i];
412      }
413   }
414   else {
415      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
416      for (j=0;j<m;j++) {
417         i = (GLint) ((j+skipcol) * xscale);
418         if (i<0)  i = n + i - 1;
419         zstencil[j] = stencil[i];
420      }
421   }
422
423   /* write the span */
424   for (r=r0; r<r1; r++) {
425      _swrast_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
426   }
427}
428