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