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