s_zoom.c revision 2a182a98973edc9ecf2936b1288485bb2b3fa722
1/* $Id: s_zoom.c,v 1.9 2002/01/27 18:32:03 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  4.1
6 *
7 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27#include "glheader.h"
28#include "macros.h"
29#include "mem.h"
30#include "colormac.h"
31
32#include "s_context.h"
33#include "s_span.h"
34#include "s_stencil.h"
35#include "s_zoom.h"
36
37
38#ifdef DEBUG
39
40#define SAVE_SPAN(span)    struct sw_span tmp_span = (span);
41
42#define RESTORE_SPAN(span)						\
43{									\
44   GLint i;								\
45   for (i=tmp_span.start; i<tmp_span.end; i++) {			\
46      if (tmp_span.color.rgba[i][RCOMP] !=				\
47          (span).color.rgba[i][RCOMP] ||	 			\
48          tmp_span.color.rgba[i][GCOMP] != 				\
49	  (span).color.rgba[i][GCOMP] || 				\
50	  tmp_span.color.rgba[i][BCOMP] != 				\
51	  (span).color.rgba[i][BCOMP]) {				\
52         fprintf(stderr, "glZoom: Color-span changed in subfunction.");	\
53      }									\
54      if (tmp_span.zArray[i] != (span).zArray[i]) {			\
55         fprintf(stderr, "glZoom: Depth-span changed in subfunction.");	\
56      }									\
57   }									\
58   (span) = tmp_span;							\
59}
60
61#else /* DEBUG not defined */
62
63#define SAVE_SPAN(span)    GLint start = (span).start, end = (span).end;
64#define RESTORE_SPAN(span) (span).start = start, (span).end = end;      \
65			   (span).writeAll = GL_TRUE;
66
67#endif /* DEBUG */
68
69/*
70 * Write a span of pixels to the frame buffer while applying a pixel zoom.
71 * This is only used by glDrawPixels and glCopyPixels.
72 * Input:  n - number of pixels in input row
73 *         x, y - destination of the span
74 *         z - depth values for the span
75 *         red, green, blue, alpha - array of colors
76 *         y0 - location of first row in the image we're drawing.
77 */
78void
79_mesa_write_zoomed_rgba_span( GLcontext *ctx,
80                              GLuint n, GLint x, GLint y, const GLdepth z[],
81                              const GLfloat *fog,
82                              CONST GLchan rgba[][4], GLint y0 )
83{
84   GLint r0, r1, row;
85   GLint i, j;
86   struct sw_span zoomed;
87   const GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
88
89   SW_SPAN_RESET (zoomed);
90   INIT_SPAN(zoomed);
91
92   /* compute width of output row */
93   zoomed.end = (GLint) ABSF( n * ctx->Pixel.ZoomX );
94   if (zoomed.end == 0) {
95      return;
96   }
97   /*here ok or better latter? like it was before */
98   else if (zoomed.end > maxwidth) {
99     zoomed.end = maxwidth;
100   }
101
102   if (ctx->Pixel.ZoomX<0.0) {
103      /* adjust x coordinate for left/right mirroring */
104      zoomed.x = x - zoomed.end;
105   }
106   else
107     zoomed.x = x;
108
109
110   /* compute which rows to draw */
111   row = y-y0;
112   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
113   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
114   if (r0==r1) {
115      return;
116   }
117   else if (r1<r0) {
118      GLint rtmp = r1;
119      r1 = r0;
120      r0 = rtmp;
121   }
122
123   /* return early if r0...r1 is above or below window */
124   if (r0<0 && r1<0) {
125      /* below window */
126      return;
127   }
128   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
129      /* above window */
130      return;
131   }
132
133   /* check if left edge is outside window */
134   if (zoomed.x < 0) {
135      zoomed.start = -x;
136   }
137
138   /* make sure span isn't too long or short */
139   /*   if (m>maxwidth) {
140      m = maxwidth;
141      }*/
142
143   if (zoomed.end <= zoomed.start) {
144      return;
145   }
146
147   ASSERT( zoomed.end <= MAX_WIDTH );
148
149   /* zoom the span horizontally */
150   if (ctx->Pixel.ZoomX==-1.0F) {
151      SW_SPAN_SET_FLAG(zoomed.filledColor);
152      SW_SPAN_SET_FLAG(zoomed.filledAlpha);
153      SW_SPAN_SET_FLAG(zoomed.filledDepth);
154      /* n==m */
155      for (j=zoomed.start; j<zoomed.end; j++) {
156         i = n - j - 1;
157	 COPY_CHAN4(zoomed.color.rgba[j], rgba[i]);
158         zoomed.zArray[j] = z[i];
159      }
160      if (fog && ctx->Fog.Enabled) {
161	 for (j=zoomed.start; j<zoomed.end; j++) {
162	    i = n - j - 1;
163	    zoomed.fogArray[j] = fog[i];
164	 }
165      }
166   }
167   else {
168      const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
169      SW_SPAN_SET_FLAG(zoomed.filledColor);
170      SW_SPAN_SET_FLAG(zoomed.filledAlpha);
171      SW_SPAN_SET_FLAG(zoomed.filledDepth);
172      for (j=zoomed.start; j<zoomed.end; j++) {
173         i = (GLint) (j * xscale);
174         if (i<0)  i = n + i - 1;
175	 COPY_CHAN4(zoomed.color.rgba[j], rgba[i]);
176         zoomed.zArray[j] = z[i];
177      }
178      if (fog && ctx->Fog.Enabled) {
179	 for (j=zoomed.start; j<zoomed.end; j++) {
180	    i = (GLint) (j * xscale);
181	    if (i<0)  i = n + i - 1;
182	    zoomed.fogArray[j] = fog[i];
183	 }
184      }
185   }
186
187   zoomed.arrayMask |= SPAN_Z;
188   if (fog)
189      zoomed.arrayMask |= SPAN_FOG;
190
191   /* write the span */
192   for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
193      SAVE_SPAN(zoomed);
194      ASSERT((zoomed.interpMask & SPAN_RGBA) == 0);
195      _mesa_write_rgba_span(ctx, &zoomed, GL_BITMAP);
196      RESTORE_SPAN(zoomed);
197      /* problem here: "zoomed" can change inside
198	 "_mesa_write_rgba_span". Best solution: make copy "tmpspan"
199	 and give to function, but too slow */
200   }
201}
202
203
204
205void
206_mesa_write_zoomed_rgb_span( GLcontext *ctx,
207                             GLuint n, GLint x, GLint y, const GLdepth z[],
208                             const GLfloat *fog,
209                             CONST GLchan rgb[][3], GLint y0 )
210{
211   GLint m;
212   GLint r0, r1, row, r;
213   GLint i, j, skipcol;
214   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
215   struct sw_span zoomed;
216
217   INIT_SPAN(zoomed);
218   zoomed.arrayMask |= SPAN_RGBA;
219
220   if (fog && ctx->Fog.Enabled)
221      zoomed.arrayMask |= SPAN_FOG;
222
223
224   /* compute width of output row */
225   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
226   if (m==0) {
227      return;
228   }
229   if (ctx->Pixel.ZoomX<0.0) {
230      /* adjust x coordinate for left/right mirroring */
231      x = x - m;
232   }
233
234   /* compute which rows to draw */
235   row = y-y0;
236   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
237   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
238   if (r0==r1) {
239      return;
240   }
241   else if (r1<r0) {
242      GLint rtmp = r1;
243      r1 = r0;
244      r0 = rtmp;
245   }
246
247   /* return early if r0...r1 is above or below window */
248   if (r0<0 && r1<0) {
249      /* below window */
250      return;
251   }
252   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
253      /* above window */
254      return;
255   }
256
257   /* check if left edge is outside window */
258   skipcol = 0;
259   if (x<0) {
260      skipcol = -x;
261      m += x;
262   }
263   /* make sure span isn't too long or short */
264   if (m>maxwidth) {
265      m = maxwidth;
266   }
267   else if (m<=0) {
268      return;
269   }
270
271   ASSERT( m <= MAX_WIDTH );
272
273   /* zoom the span horizontally */
274   if (ctx->Pixel.ZoomX==-1.0F) {
275      /* n==m */
276      for (j=0;j<m;j++) {
277         i = n - (j+skipcol) - 1;
278         zoomed.color.rgba[j][0] = rgb[i][0];
279         zoomed.color.rgba[j][1] = rgb[i][1];
280         zoomed.color.rgba[j][2] = rgb[i][2];
281         zoomed.color.rgba[j][3] = CHAN_MAX;
282         zoomed.zArray[j] = z[i];
283      }
284      if (zoomed.arrayMask & SPAN_FOG) {
285	 for (j=0;j<m;j++) {
286	    i = n - (j+skipcol) - 1;
287	    zoomed.fogArray[j] = fog[i];
288	 }
289      }
290   }
291   else {
292      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
293      for (j=0;j<m;j++) {
294         i = (GLint) ((j+skipcol) * xscale);
295         if (i<0)  i = n + i - 1;
296         zoomed.color.rgba[j][0] = rgb[i][0];
297         zoomed.color.rgba[j][1] = rgb[i][1];
298         zoomed.color.rgba[j][2] = rgb[i][2];
299         zoomed.color.rgba[j][3] = CHAN_MAX;
300         zoomed.zArray[j] = z[i];
301      }
302      if (zoomed.arrayMask & SPAN_FOG) {
303	 for (j=0;j<m;j++) {
304	    i = (GLint) ((j+skipcol) * xscale);
305	    if (i<0)  i = n + i - 1;
306	    zoomed.fogArray[j] = fog[i];
307	 }
308      }
309   }
310
311   /* write the span */
312   for (r=r0; r<r1; r++) {
313      zoomed.x = x + skipcol;
314      zoomed.y = r;
315      zoomed.end = m;
316      ASSERT((zoomed.interpMask & SPAN_RGBA) == 0);
317      _mesa_write_rgba_span( ctx, &zoomed, GL_BITMAP );
318   }
319}
320
321
322
323/*
324 * As above, but write CI pixels.
325 */
326void
327_mesa_write_zoomed_index_span( GLcontext *ctx,
328                               GLuint n, GLint x, GLint y, const GLdepth z[],
329                               const GLfloat *fog,
330                               const GLuint indexes[], GLint y0 )
331{
332   GLint m;
333   GLint r0, r1, row, r;
334   GLint i, j, skipcol;
335   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
336   struct sw_span zoomed;
337
338   SW_SPAN_RESET(zoomed);
339   INIT_SPAN(zoomed);
340   zoomed.arrayMask |= SPAN_INDEX;
341
342   /* compute width of output row */
343   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
344   if (m==0) {
345      return;
346   }
347   if (ctx->Pixel.ZoomX<0.0) {
348      /* adjust x coordinate for left/right mirroring */
349      x = x - m;
350   }
351
352   /* compute which rows to draw */
353   row = y-y0;
354   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
355   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
356   if (r0==r1) {
357      return;
358   }
359   else if (r1<r0) {
360      GLint rtmp = r1;
361      r1 = r0;
362      r0 = rtmp;
363   }
364
365   /* return early if r0...r1 is above or below window */
366   if (r0<0 && r1<0) {
367      /* below window */
368      return;
369   }
370   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
371      /* above window */
372      return;
373   }
374
375   /* check if left edge is outside window */
376   skipcol = 0;
377   if (x<0) {
378      skipcol = -x;
379      m += x;
380   }
381   /* make sure span isn't too long or short */
382   if (m>maxwidth) {
383      m = maxwidth;
384   }
385   else if (m<=0) {
386      return;
387   }
388
389   ASSERT( m <= MAX_WIDTH );
390
391   /* zoom the span horizontally */
392   if (ctx->Pixel.ZoomX==-1.0F) {
393      /* n==m */
394      for (j=0;j<m;j++) {
395         i = n - (j+skipcol) - 1;
396         zoomed.color.index[j] = indexes[i];
397         zoomed.zArray[j]   = z[i];
398      }
399      if (fog && ctx->Fog.Enabled) {
400	 for (j=0;j<m;j++) {
401	    i = n - (j+skipcol) - 1;
402	    zoomed.fogArray[j] = fog[i];
403	 }
404         zoomed.arrayMask |= SPAN_FOG;
405      }
406   }
407   else {
408      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
409      for (j=0;j<m;j++) {
410         i = (GLint) ((j+skipcol) * xscale);
411         if (i<0)  i = n + i - 1;
412         zoomed.color.index[j] = indexes[i];
413         zoomed.zArray[j] = z[i];
414      }
415      if (fog && ctx->Fog.Enabled) {
416	 for (j=0;j<m;j++) {
417	    i = (GLint) ((j+skipcol) * xscale);
418	    if (i<0)  i = n + i - 1;
419	    zoomed.fogArray[j] = fog[i];
420	 }
421         zoomed.arrayMask |= SPAN_FOG;
422      }
423   }
424
425   zoomed.arrayMask |= SPAN_Z;
426
427   /* write the span */
428   for (r=r0; r<r1; r++) {
429      SAVE_SPAN(zoomed);
430      ASSERT((zoomed.interpMask & SPAN_INDEX) == 0);
431      zoomed.x = x + skipcol;
432      zoomed.y = r;
433      zoomed.end = m;
434      _mesa_write_index_span(ctx, &zoomed, GL_BITMAP);
435      RESTORE_SPAN(zoomed);
436   }
437}
438
439
440
441/*
442 * As above, but write stencil values.
443 */
444void
445_mesa_write_zoomed_stencil_span( GLcontext *ctx,
446                                 GLuint n, GLint x, GLint y,
447                                 const GLstencil stencil[], GLint y0 )
448{
449   GLint m;
450   GLint r0, r1, row, r;
451   GLint i, j, skipcol;
452   GLstencil zstencil[MAX_WIDTH];  /* zoomed stencil values */
453   GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
454
455   /* compute width of output row */
456   m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
457   if (m==0) {
458      return;
459   }
460   if (ctx->Pixel.ZoomX<0.0) {
461      /* adjust x coordinate for left/right mirroring */
462      x = x - m;
463   }
464
465   /* compute which rows to draw */
466   row = y-y0;
467   r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
468   r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
469   if (r0==r1) {
470      return;
471   }
472   else if (r1<r0) {
473      GLint rtmp = r1;
474      r1 = r0;
475      r0 = rtmp;
476   }
477
478   /* return early if r0...r1 is above or below window */
479   if (r0<0 && r1<0) {
480      /* below window */
481      return;
482   }
483   if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
484      /* above window */
485      return;
486   }
487
488   /* check if left edge is outside window */
489   skipcol = 0;
490   if (x<0) {
491      skipcol = -x;
492      m += x;
493   }
494   /* make sure span isn't too long or short */
495   if (m>maxwidth) {
496      m = maxwidth;
497   }
498   else if (m<=0) {
499      return;
500   }
501
502   ASSERT( m <= MAX_WIDTH );
503
504   /* zoom the span horizontally */
505   if (ctx->Pixel.ZoomX==-1.0F) {
506      /* n==m */
507      for (j=0;j<m;j++) {
508         i = n - (j+skipcol) - 1;
509         zstencil[j] = stencil[i];
510      }
511   }
512   else {
513      GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
514      for (j=0;j<m;j++) {
515         i = (GLint) ((j+skipcol) * xscale);
516         if (i<0)  i = n + i - 1;
517         zstencil[j] = stencil[i];
518      }
519   }
520
521   /* write the span */
522   for (r=r0; r<r1; r++) {
523      _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
524   }
525}
526