Merge branch 'master' of git+ssh://brianp@git.freedesktop.org/git/mesa/mesa into...
[mesa.git] / src / mesa / swrast / s_zoom.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 * Compute the bounds of the region resulting from zooming a pixel span.
38 * The resulting region will be entirely inside the window/scissor bounds
39 * so no additional clipping is needed.
40 * \param imageX, imageY position of the overall image being drawn
41 * \param spanX, spanY position of span being drawing
42 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
43 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
44 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
45 */
46 static GLboolean
47 compute_zoomed_bounds(GLcontext *ctx, GLint imageX, GLint imageY,
48 GLint spanX, GLint spanY, GLint width,
49 GLint *x0, GLint *x1, GLint *y0, GLint *y1)
50 {
51 const struct gl_framebuffer *fb = ctx->DrawBuffer;
52 GLint c0, c1, r0, r1;
53
54 ASSERT(spanX >= imageX);
55 ASSERT(spanY >= imageY);
56
57 /*
58 * Compute destination columns: [c0, c1)
59 */
60 c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
61 c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
62 if (c1 < c0) {
63 /* swap */
64 GLint tmp = c1;
65 c1 = c0;
66 c0 = tmp;
67 }
68 c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
69 c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
70 if (c0 == c1) {
71 return GL_FALSE; /* no width */
72 }
73
74 /*
75 * Compute destination rows: [r0, r1)
76 */
77 r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
78 r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
79 if (r1 < r0) {
80 /* swap */
81 GLint tmp = r1;
82 r1 = r0;
83 r0 = tmp;
84 }
85 r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
86 r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
87 if (r0 == r1) {
88 return GL_FALSE; /* no height */
89 }
90
91 *x0 = c0;
92 *x1 = c1;
93 *y0 = r0;
94 *y1 = r1;
95
96 return GL_TRUE;
97 }
98
99
100 /**
101 * Can use this for unzooming X or Y values.
102 */
103 static INLINE GLint
104 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
105 {
106 /*
107 zx = imageX + (x - imageX) * zoomX;
108 zx - imageX = (x - imageX) * zoomX;
109 (zx - imageX) / zoomX = x - imageX;
110 */
111 GLint x = imageX + (GLint) ((zx - imageX) / zoomX);
112 return x;
113 }
114
115
116
117 /**
118 * Helper function called from _swrast_write_zoomed_rgba/rgb/
119 * index/depth_span().
120 */
121 static void
122 zoom_span( GLcontext *ctx, GLint imgX, GLint imgY, const SWspan *span,
123 const GLvoid *src, GLenum format )
124 {
125 SWspan zoomed;
126 SWspanarrays zoomed_arrays; /* this is big! */
127 GLint x0, x1, y0, y1;
128 GLint zoomedWidth;
129
130 if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
131 &x0, &x1, &y0, &y1)) {
132 return; /* totally clipped */
133 }
134
135 zoomedWidth = x1 - x0;
136 ASSERT(zoomedWidth > 0);
137 ASSERT(zoomedWidth <= MAX_WIDTH);
138
139 /* no pixel arrays! must be horizontal spans. */
140 ASSERT((span->arrayMask & SPAN_XY) == 0);
141 ASSERT(span->primitive == GL_BITMAP);
142
143 INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0);
144 zoomed.x = x0;
145 zoomed.end = zoomedWidth;
146 zoomed.array = &zoomed_arrays;
147 zoomed_arrays.ChanType = span->array->ChanType;
148 /* XXX temporary */
149 #if CHAN_TYPE == GL_UNSIGNED_BYTE
150 zoomed_arrays.rgba = zoomed_arrays.color.sz1.rgba;
151 zoomed_arrays.spec = zoomed_arrays.color.sz1.spec;
152 #elif CHAN_TYPE == GL_UNSIGNED_SHORT
153 zoomed_arrays.rgba = zoomed_arrays.color.sz2.rgba;
154 zoomed_arrays.spec = zoomed_arrays.color.sz2.spec;
155 #else
156 zoomed_arrays.rgba = zoomed_arrays.color.sz4.rgba;
157 zoomed_arrays.spec = zoomed_arrays.color.sz4.spec;
158 #endif
159
160
161 /* copy fog interp info */
162 zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0];
163 zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0];
164 zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0];
165 /* XXX copy texcoord info? */
166
167 if (format == GL_RGBA || format == GL_RGB) {
168 /* copy Z info */
169 zoomed.z = span->z;
170 zoomed.zStep = span->zStep;
171 /* we'll generate an array of colorss */
172 zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
173 zoomed.arrayMask |= SPAN_RGBA;
174 ASSERT(span->arrayMask & SPAN_RGBA);
175 }
176 else if (format == GL_COLOR_INDEX) {
177 /* copy Z info */
178 zoomed.z = span->z;
179 zoomed.zStep = span->zStep;
180 /* we'll generate an array of color indexes */
181 zoomed.interpMask = span->interpMask & ~SPAN_INDEX;
182 zoomed.arrayMask |= SPAN_INDEX;
183 ASSERT(span->arrayMask & SPAN_INDEX);
184 }
185 else if (format == GL_DEPTH_COMPONENT) {
186 /* Copy color info */
187 zoomed.red = span->red;
188 zoomed.green = span->green;
189 zoomed.blue = span->blue;
190 zoomed.alpha = span->alpha;
191 zoomed.redStep = span->redStep;
192 zoomed.greenStep = span->greenStep;
193 zoomed.blueStep = span->blueStep;
194 zoomed.alphaStep = span->alphaStep;
195 /* we'll generate an array of depth values */
196 zoomed.interpMask = span->interpMask & ~SPAN_Z;
197 zoomed.arrayMask |= SPAN_Z;
198 ASSERT(span->arrayMask & SPAN_Z);
199 }
200 else {
201 _mesa_problem(ctx, "Bad format in zoom_span");
202 return;
203 }
204
205 /* zoom the span horizontally */
206 if (format == GL_RGBA) {
207 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
208 const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
209 GLint i;
210 for (i = 0; i < zoomedWidth; i++) {
211 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
212 ASSERT(j >= 0);
213 ASSERT(j < (GLint) span->end);
214 COPY_4UBV(zoomed.array->color.sz1.rgba[i], rgba[j]);
215 }
216 }
217 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
218 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
219 GLint i;
220 for (i = 0; i < zoomedWidth; i++) {
221 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
222 ASSERT(j >= 0);
223 ASSERT(j < (GLint) span->end);
224 COPY_4V(zoomed.array->color.sz2.rgba[i], rgba[j]);
225 }
226 }
227 else {
228 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
229 GLint i;
230 for (i = 0; i < zoomedWidth; i++) {
231 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
232 ASSERT(j >= 0);
233 ASSERT(j < span->end);
234 COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL0][i], rgba[j]);
235 }
236 }
237 }
238 else if (format == GL_RGB) {
239 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
240 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
241 GLint i;
242 for (i = 0; i < zoomedWidth; i++) {
243 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
244 ASSERT(j >= 0);
245 ASSERT(j < (GLint) span->end);
246 zoomed.array->color.sz1.rgba[i][0] = rgb[j][0];
247 zoomed.array->color.sz1.rgba[i][1] = rgb[j][1];
248 zoomed.array->color.sz1.rgba[i][2] = rgb[j][2];
249 zoomed.array->color.sz1.rgba[i][3] = 0xff;
250 }
251 }
252 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
253 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
254 GLint i;
255 for (i = 0; i < zoomedWidth; i++) {
256 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
257 ASSERT(j >= 0);
258 ASSERT(j < (GLint) span->end);
259 zoomed.array->color.sz2.rgba[i][0] = rgb[j][0];
260 zoomed.array->color.sz2.rgba[i][1] = rgb[j][1];
261 zoomed.array->color.sz2.rgba[i][2] = rgb[j][2];
262 zoomed.array->color.sz2.rgba[i][3] = 0xffff;
263 }
264 }
265 else {
266 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
267 GLint i;
268 for (i = 0; i < zoomedWidth; i++) {
269 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
270 ASSERT(j >= 0);
271 ASSERT(j < span->end);
272 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][0] = rgb[j][0];
273 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][1] = rgb[j][1];
274 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][2] = rgb[j][2];
275 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][3] = 1.0F;
276 }
277 }
278 }
279 else if (format == GL_COLOR_INDEX) {
280 const GLuint *indexes = (const GLuint *) src;
281 GLint i;
282 for (i = 0; i < zoomedWidth; i++) {
283 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
284 ASSERT(j >= 0);
285 ASSERT(j < (GLint) span->end);
286 zoomed.array->index[i] = indexes[j];
287 }
288 }
289 else if (format == GL_DEPTH_COMPONENT) {
290 const GLuint *zValues = (const GLuint *) src;
291 GLint i;
292 for (i = 0; i < zoomedWidth; i++) {
293 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
294 ASSERT(j >= 0);
295 ASSERT(j < (GLint) span->end);
296 zoomed.array->z[i] = zValues[j];
297 }
298 /* Now, fall into either the RGB or COLOR_INDEX path below */
299 format = ctx->Visual.rgbMode ? GL_RGBA : GL_COLOR_INDEX;
300 }
301
302 /* write the span in rows [r0, r1) */
303 if (format == GL_RGBA || format == GL_RGB) {
304 /* Writing the span may modify the colors, so make a backup now if we're
305 * going to call _swrast_write_zoomed_span() more than once.
306 * Also, clipping may change the span end value, so store it as well.
307 */
308 const GLint end = zoomed.end; /* save */
309 /* use specular color array for temp storage */
310 void *rgbaSave = zoomed.array->spec;
311 const GLint pixelSize =
312 (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
313 ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
314 : 4 * sizeof(GLfloat));
315 if (y1 - y0 > 1) {
316 MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
317 }
318 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
319 _swrast_write_rgba_span(ctx, &zoomed);
320 zoomed.end = end; /* restore */
321 if (y1 - y0 > 1) {
322 /* restore the colors */
323 MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
324 }
325 }
326 }
327 else if (format == GL_COLOR_INDEX) {
328 /* use specular color array for temp storage */
329 GLuint *indexSave = (GLuint *) zoomed.array->spec;
330 const GLint end = zoomed.end; /* save */
331 if (y1 - y0 > 1) {
332 MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint));
333 }
334 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
335 _swrast_write_index_span(ctx, &zoomed);
336 zoomed.end = end; /* restore */
337 if (y1 - y0 > 1) {
338 /* restore the colors */
339 MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint));
340 }
341 }
342 }
343 }
344
345
346 void
347 _swrast_write_zoomed_rgba_span(GLcontext *ctx, GLint imgX, GLint imgY,
348 const SWspan *span, const GLvoid *rgba)
349 {
350 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
351 }
352
353
354 void
355 _swrast_write_zoomed_rgb_span(GLcontext *ctx, GLint imgX, GLint imgY,
356 const SWspan *span, const GLvoid *rgb)
357 {
358 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
359 }
360
361
362 void
363 _swrast_write_zoomed_index_span(GLcontext *ctx, GLint imgX, GLint imgY,
364 const SWspan *span)
365 {
366 zoom_span(ctx, imgX, imgY, span,
367 (const GLvoid *) span->array->index, GL_COLOR_INDEX);
368 }
369
370
371 void
372 _swrast_write_zoomed_depth_span(GLcontext *ctx, GLint imgX, GLint imgY,
373 const SWspan *span)
374 {
375 zoom_span(ctx, imgX, imgY, span,
376 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
377 }
378
379
380 /**
381 * Zoom/write stencil values.
382 * No per-fragment operations are applied.
383 */
384 void
385 _swrast_write_zoomed_stencil_span(GLcontext *ctx, GLint imgX, GLint imgY,
386 GLint width, GLint spanX, GLint spanY,
387 const GLstencil stencil[])
388 {
389 GLstencil zoomedVals[MAX_WIDTH];
390 GLint x0, x1, y0, y1, y;
391 GLint i, zoomedWidth;
392
393 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
394 &x0, &x1, &y0, &y1)) {
395 return; /* totally clipped */
396 }
397
398 zoomedWidth = x1 - x0;
399 ASSERT(zoomedWidth > 0);
400 ASSERT(zoomedWidth <= MAX_WIDTH);
401
402 /* zoom the span horizontally */
403 for (i = 0; i < zoomedWidth; i++) {
404 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
405 ASSERT(j >= 0);
406 ASSERT(j < width);
407 zoomedVals[i] = stencil[j];
408 }
409
410 /* write the zoomed spans */
411 for (y = y0; y < y1; y++) {
412 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
413 }
414 }
415
416
417 /**
418 * Zoom/write z values (16 or 32-bit).
419 * No per-fragment operations are applied.
420 */
421 void
422 _swrast_write_zoomed_z_span(GLcontext *ctx, GLint imgX, GLint imgY,
423 GLint width, GLint spanX, GLint spanY,
424 const GLvoid *z)
425 {
426 struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer;
427 GLushort zoomedVals16[MAX_WIDTH];
428 GLuint zoomedVals32[MAX_WIDTH];
429 GLint x0, x1, y0, y1, y;
430 GLint i, zoomedWidth;
431
432 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
433 &x0, &x1, &y0, &y1)) {
434 return; /* totally clipped */
435 }
436
437 zoomedWidth = x1 - x0;
438 ASSERT(zoomedWidth > 0);
439 ASSERT(zoomedWidth <= MAX_WIDTH);
440
441 /* zoom the span horizontally */
442 if (rb->DataType == GL_UNSIGNED_SHORT) {
443 for (i = 0; i < zoomedWidth; i++) {
444 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
445 ASSERT(j >= 0);
446 ASSERT(j < width);
447 zoomedVals16[i] = ((GLushort *) z)[j];
448 }
449 z = zoomedVals16;
450 }
451 else {
452 ASSERT(rb->DataType == GL_UNSIGNED_INT);
453 for (i = 0; i < zoomedWidth; i++) {
454 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
455 ASSERT(j >= 0);
456 ASSERT(j < width);
457 zoomedVals32[i] = ((GLuint *) z)[j];
458 }
459 z = zoomedVals32;
460 }
461
462 /* write the zoomed spans */
463 for (y = y0; y < y1; y++) {
464 rb->PutRow(ctx, rb, zoomedWidth, x0, y, z, NULL);
465 }
466 }