516a5bb5826f20e7e36e78c743ca2cc5356c8bcc
[mesa.git] / src / mesa / swrast / s_zoom.c
1 /* $Id: s_zoom.c,v 1.11 2002/01/28 03:42:28 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 */
78 void
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 const GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
87 struct sw_span zoomed;
88
89 INIT_SPAN(zoomed);
90 zoomed.arrayMask |= SPAN_RGBA;
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 /* n==m */
152 for (j=zoomed.start; j<zoomed.end; j++) {
153 i = n - j - 1;
154 COPY_CHAN4(zoomed.color.rgba[j], rgba[i]);
155 zoomed.zArray[j] = z[i];
156 }
157 if (fog && ctx->Fog.Enabled) {
158 for (j=zoomed.start; j<zoomed.end; j++) {
159 i = n - j - 1;
160 zoomed.fogArray[j] = fog[i];
161 }
162 }
163 }
164 else {
165 const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
166 for (j=zoomed.start; j<zoomed.end; j++) {
167 i = (GLint) (j * xscale);
168 if (i<0) i = n + i - 1;
169 COPY_CHAN4(zoomed.color.rgba[j], rgba[i]);
170 zoomed.zArray[j] = z[i];
171 }
172 if (fog && ctx->Fog.Enabled) {
173 for (j=zoomed.start; j<zoomed.end; j++) {
174 i = (GLint) (j * xscale);
175 if (i<0) i = n + i - 1;
176 zoomed.fogArray[j] = fog[i];
177 }
178 }
179 }
180
181 zoomed.arrayMask |= SPAN_Z;
182 if (fog)
183 zoomed.arrayMask |= SPAN_FOG;
184
185 /* write the span */
186 for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) {
187 SAVE_SPAN(zoomed);
188 ASSERT((zoomed.interpMask & SPAN_RGBA) == 0);
189 _mesa_write_rgba_span(ctx, &zoomed, GL_BITMAP);
190 RESTORE_SPAN(zoomed);
191 /* problem here: "zoomed" can change inside
192 "_mesa_write_rgba_span". Best solution: make copy "tmpspan"
193 and give to function, but too slow */
194 }
195 }
196
197
198
199 void
200 _mesa_write_zoomed_rgb_span( GLcontext *ctx,
201 GLuint n, GLint x, GLint y, const GLdepth z[],
202 const GLfloat *fog,
203 CONST GLchan rgb[][3], GLint y0 )
204 {
205 GLint m;
206 GLint r0, r1, row, r;
207 GLint i, j, skipcol;
208 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
209 struct sw_span zoomed;
210
211 INIT_SPAN(zoomed);
212 zoomed.arrayMask |= SPAN_RGBA;
213
214 if (fog && ctx->Fog.Enabled)
215 zoomed.arrayMask |= SPAN_FOG;
216
217
218 /* compute width of output row */
219 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
220 if (m==0) {
221 return;
222 }
223 if (ctx->Pixel.ZoomX<0.0) {
224 /* adjust x coordinate for left/right mirroring */
225 x = x - m;
226 }
227
228 /* compute which rows to draw */
229 row = y-y0;
230 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
231 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
232 if (r0==r1) {
233 return;
234 }
235 else if (r1<r0) {
236 GLint rtmp = r1;
237 r1 = r0;
238 r0 = rtmp;
239 }
240
241 /* return early if r0...r1 is above or below window */
242 if (r0<0 && r1<0) {
243 /* below window */
244 return;
245 }
246 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
247 /* above window */
248 return;
249 }
250
251 /* check if left edge is outside window */
252 skipcol = 0;
253 if (x<0) {
254 skipcol = -x;
255 m += x;
256 }
257 /* make sure span isn't too long or short */
258 if (m>maxwidth) {
259 m = maxwidth;
260 }
261 else if (m<=0) {
262 return;
263 }
264
265 ASSERT( m <= MAX_WIDTH );
266
267 /* zoom the span horizontally */
268 if (ctx->Pixel.ZoomX==-1.0F) {
269 /* n==m */
270 for (j=0;j<m;j++) {
271 i = n - (j+skipcol) - 1;
272 zoomed.color.rgba[j][0] = rgb[i][0];
273 zoomed.color.rgba[j][1] = rgb[i][1];
274 zoomed.color.rgba[j][2] = rgb[i][2];
275 zoomed.color.rgba[j][3] = CHAN_MAX;
276 zoomed.zArray[j] = z[i];
277 }
278 if (zoomed.arrayMask & SPAN_FOG) {
279 for (j=0;j<m;j++) {
280 i = n - (j+skipcol) - 1;
281 zoomed.fogArray[j] = fog[i];
282 }
283 }
284 }
285 else {
286 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
287 for (j=0;j<m;j++) {
288 i = (GLint) ((j+skipcol) * xscale);
289 if (i<0) i = n + i - 1;
290 zoomed.color.rgba[j][0] = rgb[i][0];
291 zoomed.color.rgba[j][1] = rgb[i][1];
292 zoomed.color.rgba[j][2] = rgb[i][2];
293 zoomed.color.rgba[j][3] = CHAN_MAX;
294 zoomed.zArray[j] = z[i];
295 }
296 if (zoomed.arrayMask & SPAN_FOG) {
297 for (j=0;j<m;j++) {
298 i = (GLint) ((j+skipcol) * xscale);
299 if (i<0) i = n + i - 1;
300 zoomed.fogArray[j] = fog[i];
301 }
302 }
303 }
304
305 /* write the span */
306 for (r=r0; r<r1; r++) {
307 zoomed.x = x + skipcol;
308 zoomed.y = r;
309 zoomed.end = m;
310 ASSERT((zoomed.interpMask & SPAN_RGBA) == 0);
311 _mesa_write_rgba_span( ctx, &zoomed, GL_BITMAP );
312 }
313 }
314
315
316
317 /*
318 * As above, but write CI pixels.
319 */
320 void
321 _mesa_write_zoomed_index_span( GLcontext *ctx,
322 GLuint n, GLint x, GLint y, const GLdepth z[],
323 const GLfloat *fog,
324 const GLuint indexes[], GLint y0 )
325 {
326 GLint m;
327 GLint r0, r1, row, r;
328 GLint i, j, skipcol;
329 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
330 struct sw_span zoomed;
331
332 INIT_SPAN(zoomed);
333 zoomed.arrayMask |= SPAN_INDEX;
334
335 /* compute width of output row */
336 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
337 if (m==0) {
338 return;
339 }
340 if (ctx->Pixel.ZoomX<0.0) {
341 /* adjust x coordinate for left/right mirroring */
342 x = x - m;
343 }
344
345 /* compute which rows to draw */
346 row = y-y0;
347 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
348 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
349 if (r0==r1) {
350 return;
351 }
352 else if (r1<r0) {
353 GLint rtmp = r1;
354 r1 = r0;
355 r0 = rtmp;
356 }
357
358 /* return early if r0...r1 is above or below window */
359 if (r0<0 && r1<0) {
360 /* below window */
361 return;
362 }
363 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
364 /* above window */
365 return;
366 }
367
368 /* check if left edge is outside window */
369 skipcol = 0;
370 if (x<0) {
371 skipcol = -x;
372 m += x;
373 }
374 /* make sure span isn't too long or short */
375 if (m>maxwidth) {
376 m = maxwidth;
377 }
378 else if (m<=0) {
379 return;
380 }
381
382 ASSERT( m <= MAX_WIDTH );
383
384 /* zoom the span horizontally */
385 if (ctx->Pixel.ZoomX==-1.0F) {
386 /* n==m */
387 for (j=0;j<m;j++) {
388 i = n - (j+skipcol) - 1;
389 zoomed.color.index[j] = indexes[i];
390 zoomed.zArray[j] = z[i];
391 }
392 if (fog && ctx->Fog.Enabled) {
393 for (j=0;j<m;j++) {
394 i = n - (j+skipcol) - 1;
395 zoomed.fogArray[j] = fog[i];
396 }
397 zoomed.arrayMask |= SPAN_FOG;
398 }
399 }
400 else {
401 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
402 for (j=0;j<m;j++) {
403 i = (GLint) ((j+skipcol) * xscale);
404 if (i<0) i = n + i - 1;
405 zoomed.color.index[j] = indexes[i];
406 zoomed.zArray[j] = z[i];
407 }
408 if (fog && ctx->Fog.Enabled) {
409 for (j=0;j<m;j++) {
410 i = (GLint) ((j+skipcol) * xscale);
411 if (i<0) i = n + i - 1;
412 zoomed.fogArray[j] = fog[i];
413 }
414 zoomed.arrayMask |= SPAN_FOG;
415 }
416 }
417
418 zoomed.arrayMask |= SPAN_Z;
419
420 /* write the span */
421 for (r=r0; r<r1; r++) {
422 SAVE_SPAN(zoomed);
423 ASSERT((zoomed.interpMask & SPAN_INDEX) == 0);
424 zoomed.x = x + skipcol;
425 zoomed.y = r;
426 zoomed.end = m;
427 _mesa_write_index_span(ctx, &zoomed, GL_BITMAP);
428 RESTORE_SPAN(zoomed);
429 }
430 }
431
432
433
434 /*
435 * As above, but write stencil values.
436 */
437 void
438 _mesa_write_zoomed_stencil_span( GLcontext *ctx,
439 GLuint n, GLint x, GLint y,
440 const GLstencil stencil[], GLint y0 )
441 {
442 GLint m;
443 GLint r0, r1, row, r;
444 GLint i, j, skipcol;
445 GLstencil zstencil[MAX_WIDTH]; /* zoomed stencil values */
446 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH );
447
448 /* compute width of output row */
449 m = (GLint) ABSF( n * ctx->Pixel.ZoomX );
450 if (m==0) {
451 return;
452 }
453 if (ctx->Pixel.ZoomX<0.0) {
454 /* adjust x coordinate for left/right mirroring */
455 x = x - m;
456 }
457
458 /* compute which rows to draw */
459 row = y-y0;
460 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY);
461 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY);
462 if (r0==r1) {
463 return;
464 }
465 else if (r1<r0) {
466 GLint rtmp = r1;
467 r1 = r0;
468 r0 = rtmp;
469 }
470
471 /* return early if r0...r1 is above or below window */
472 if (r0<0 && r1<0) {
473 /* below window */
474 return;
475 }
476 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) {
477 /* above window */
478 return;
479 }
480
481 /* check if left edge is outside window */
482 skipcol = 0;
483 if (x<0) {
484 skipcol = -x;
485 m += x;
486 }
487 /* make sure span isn't too long or short */
488 if (m>maxwidth) {
489 m = maxwidth;
490 }
491 else if (m<=0) {
492 return;
493 }
494
495 ASSERT( m <= MAX_WIDTH );
496
497 /* zoom the span horizontally */
498 if (ctx->Pixel.ZoomX==-1.0F) {
499 /* n==m */
500 for (j=0;j<m;j++) {
501 i = n - (j+skipcol) - 1;
502 zstencil[j] = stencil[i];
503 }
504 }
505 else {
506 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX;
507 for (j=0;j<m;j++) {
508 i = (GLint) ((j+skipcol) * xscale);
509 if (i<0) i = n + i - 1;
510 zstencil[j] = stencil[i];
511 }
512 }
513
514 /* write the span */
515 for (r=r0; r<r1; r++) {
516 _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil );
517 }
518 }