1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "main/errors.h"
26 #include "main/glheader.h"
27 #include "main/macros.h"
28
29 #include "main/format_pack.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 * Compute the bounds of the region resulting from zooming a pixel span.
39 * The resulting region will be entirely inside the window/scissor bounds
40 * so no additional clipping is needed.
41 * \param imageX, imageY position of the mage being drawn (gl WindowPos)
42 * \param spanX, spanY position of span being drawing
43 * \param width number of pixels in span
44 * \param x0, x1 returned X bounds of zoomed region [x0, x1)
45 * \param y0, y1 returned Y bounds of zoomed region [y0, y1)
46 * \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
47 */
48 static GLboolean
compute_zoomed_bounds(struct gl_context * ctx,GLint imageX,GLint imageY,GLint spanX,GLint spanY,GLint width,GLint * x0,GLint * x1,GLint * y0,GLint * y1)49 compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
50 GLint spanX, GLint spanY, GLint width,
51 GLint *x0, GLint *x1, GLint *y0, GLint *y1)
52 {
53 const struct gl_framebuffer *fb = ctx->DrawBuffer;
54 GLint c0, c1, r0, r1;
55
56 assert(spanX >= imageX);
57 assert(spanY >= imageY);
58
59 /*
60 * Compute destination columns: [c0, c1)
61 */
62 c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
63 c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
64 if (c1 < c0) {
65 /* swap */
66 GLint tmp = c1;
67 c1 = c0;
68 c0 = tmp;
69 }
70 c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
71 c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
72 if (c0 == c1) {
73 return GL_FALSE; /* no width */
74 }
75
76 /*
77 * Compute destination rows: [r0, r1)
78 */
79 r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
80 r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
81 if (r1 < r0) {
82 /* swap */
83 GLint tmp = r1;
84 r1 = r0;
85 r0 = tmp;
86 }
87 r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
88 r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
89 if (r0 == r1) {
90 return GL_FALSE; /* no height */
91 }
92
93 *x0 = c0;
94 *x1 = c1;
95 *y0 = r0;
96 *y1 = r1;
97
98 return GL_TRUE;
99 }
100
101
102 /**
103 * Convert a zoomed x image coordinate back to an unzoomed x coord.
104 * 'zx' is screen position of a pixel in the zoomed image, who's left edge
105 * is at 'imageX'.
106 * return corresponding x coord in the original, unzoomed image.
107 * This can use this for unzooming X or Y values.
108 */
109 static inline GLint
unzoom_x(GLfloat zoomX,GLint imageX,GLint zx)110 unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
111 {
112 /*
113 zx = imageX + (x - imageX) * zoomX;
114 zx - imageX = (x - imageX) * zoomX;
115 (zx - imageX) / zoomX = x - imageX;
116 */
117 GLint x;
118 if (zoomX < 0.0F)
119 zx++;
120 x = imageX + (GLint) ((zx - imageX) / zoomX);
121 return x;
122 }
123
124
125
126 /**
127 * Helper function called from _swrast_write_zoomed_rgba/rgb/
128 * index/depth_span().
129 */
130 static void
zoom_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * src,GLenum format)131 zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
132 const GLvoid *src, GLenum format )
133 {
134 SWcontext *swrast = SWRAST_CONTEXT(ctx);
135 SWspan zoomed;
136 GLint x0, x1, y0, y1;
137 GLint zoomedWidth;
138
139 if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
140 &x0, &x1, &y0, &y1)) {
141 return; /* totally clipped */
142 }
143
144 if (!swrast->ZoomedArrays) {
145 /* allocate on demand */
146 swrast->ZoomedArrays = (SWspanarrays *) calloc(1, sizeof(SWspanarrays));
147 if (!swrast->ZoomedArrays)
148 return;
149 }
150
151 zoomedWidth = x1 - x0;
152 assert(zoomedWidth > 0);
153 assert(zoomedWidth <= SWRAST_MAX_WIDTH);
154
155 /* no pixel arrays! must be horizontal spans. */
156 assert((span->arrayMask & SPAN_XY) == 0);
157 assert(span->primitive == GL_BITMAP);
158
159 INIT_SPAN(zoomed, GL_BITMAP);
160 zoomed.x = x0;
161 zoomed.end = zoomedWidth;
162 zoomed.array = swrast->ZoomedArrays;
163 zoomed.array->ChanType = span->array->ChanType;
164 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
165 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
166 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
167 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
168 else
169 zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[VARYING_SLOT_COL0];
170
171 COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]);
172 COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]);
173 COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]);
174
175 zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0];
176 zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0];
177 zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_FOGC][0];
178
179 if (format == GL_RGBA || format == GL_RGB) {
180 /* copy Z info */
181 zoomed.z = span->z;
182 zoomed.zStep = span->zStep;
183 /* we'll generate an array of colorss */
184 zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
185 zoomed.arrayMask |= SPAN_RGBA;
186 zoomed.arrayAttribs |= VARYING_BIT_COL0; /* we'll produce these values */
187 assert(span->arrayMask & SPAN_RGBA);
188 }
189 else if (format == GL_DEPTH_COMPONENT) {
190 /* Copy color info */
191 zoomed.red = span->red;
192 zoomed.green = span->green;
193 zoomed.blue = span->blue;
194 zoomed.alpha = span->alpha;
195 zoomed.redStep = span->redStep;
196 zoomed.greenStep = span->greenStep;
197 zoomed.blueStep = span->blueStep;
198 zoomed.alphaStep = span->alphaStep;
199 /* we'll generate an array of depth values */
200 zoomed.interpMask = span->interpMask & ~SPAN_Z;
201 zoomed.arrayMask |= SPAN_Z;
202 assert(span->arrayMask & SPAN_Z);
203 }
204 else {
205 _mesa_problem(ctx, "Bad format in zoom_span");
206 return;
207 }
208
209 /* zoom the span horizontally */
210 if (format == GL_RGBA) {
211 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
212 const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
213 GLint i;
214 for (i = 0; i < zoomedWidth; i++) {
215 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
216 assert(j >= 0);
217 assert(j < (GLint) span->end);
218 COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
219 }
220 }
221 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
222 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
223 GLint i;
224 for (i = 0; i < zoomedWidth; i++) {
225 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
226 assert(j >= 0);
227 assert(j < (GLint) span->end);
228 COPY_4V(zoomed.array->rgba16[i], rgba[j]);
229 }
230 }
231 else {
232 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
233 GLint i;
234 for (i = 0; i < zoomedWidth; i++) {
235 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
236 assert(j >= 0);
237 assert(j < (GLint) span->end);
238 COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgba[j]);
239 }
240 }
241 }
242 else if (format == GL_RGB) {
243 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
244 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
245 GLint i;
246 for (i = 0; i < zoomedWidth; i++) {
247 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
248 assert(j >= 0);
249 assert(j < (GLint) span->end);
250 zoomed.array->rgba8[i][0] = rgb[j][0];
251 zoomed.array->rgba8[i][1] = rgb[j][1];
252 zoomed.array->rgba8[i][2] = rgb[j][2];
253 zoomed.array->rgba8[i][3] = 0xff;
254 }
255 }
256 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
257 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
258 GLint i;
259 for (i = 0; i < zoomedWidth; i++) {
260 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
261 assert(j >= 0);
262 assert(j < (GLint) span->end);
263 zoomed.array->rgba16[i][0] = rgb[j][0];
264 zoomed.array->rgba16[i][1] = rgb[j][1];
265 zoomed.array->rgba16[i][2] = rgb[j][2];
266 zoomed.array->rgba16[i][3] = 0xffff;
267 }
268 }
269 else {
270 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
271 GLint i;
272 for (i = 0; i < zoomedWidth; i++) {
273 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
274 assert(j >= 0);
275 assert(j < (GLint) span->end);
276 zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0];
277 zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1];
278 zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2];
279 zoomed.array->attribs[VARYING_SLOT_COL0][i][3] = 1.0F;
280 }
281 }
282 }
283 else if (format == GL_DEPTH_COMPONENT) {
284 const GLuint *zValues = (const GLuint *) src;
285 GLint i;
286 for (i = 0; i < zoomedWidth; i++) {
287 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
288 assert(j >= 0);
289 assert(j < (GLint) span->end);
290 zoomed.array->z[i] = zValues[j];
291 }
292 /* Now, fall into the RGB path below */
293 format = GL_RGBA;
294 }
295
296 /* write the span in rows [r0, r1) */
297 if (format == GL_RGBA || format == GL_RGB) {
298 /* Writing the span may modify the colors, so make a backup now if we're
299 * going to call _swrast_write_zoomed_span() more than once.
300 * Also, clipping may change the span end value, so store it as well.
301 */
302 const GLint end = zoomed.end; /* save */
303 void *rgbaSave;
304 const GLint pixelSize =
305 (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
306 ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
307 : 4 * sizeof(GLfloat));
308
309 rgbaSave = malloc(zoomed.end * pixelSize);
310 if (!rgbaSave) {
311 return;
312 }
313
314 if (y1 - y0 > 1) {
315 memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
316 }
317 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
318 _swrast_write_rgba_span(ctx, &zoomed);
319 zoomed.end = end; /* restore */
320 if (y1 - y0 > 1) {
321 /* restore the colors */
322 memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
323 }
324 }
325
326 free(rgbaSave);
327 }
328 }
329
330
331 void
_swrast_write_zoomed_rgba_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * rgba)332 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
333 const SWspan *span, const GLvoid *rgba)
334 {
335 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
336 }
337
338
339 void
_swrast_write_zoomed_rgb_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span,const GLvoid * rgb)340 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
341 const SWspan *span, const GLvoid *rgb)
342 {
343 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
344 }
345
346
347 void
_swrast_write_zoomed_depth_span(struct gl_context * ctx,GLint imgX,GLint imgY,const SWspan * span)348 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
349 const SWspan *span)
350 {
351 zoom_span(ctx, imgX, imgY, span,
352 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
353 }
354
355
356 /**
357 * Zoom/write stencil values.
358 * No per-fragment operations are applied.
359 */
360 void
_swrast_write_zoomed_stencil_span(struct gl_context * ctx,GLint imgX,GLint imgY,GLint width,GLint spanX,GLint spanY,const GLubyte stencil[])361 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
362 GLint width, GLint spanX, GLint spanY,
363 const GLubyte stencil[])
364 {
365 GLubyte *zoomedVals;
366 GLint x0, x1, y0, y1, y;
367 GLint i, zoomedWidth;
368
369 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
370 &x0, &x1, &y0, &y1)) {
371 return; /* totally clipped */
372 }
373
374 zoomedWidth = x1 - x0;
375 assert(zoomedWidth > 0);
376 assert(zoomedWidth <= SWRAST_MAX_WIDTH);
377
378 zoomedVals = malloc(zoomedWidth * sizeof(GLubyte));
379 if (!zoomedVals)
380 return;
381
382 /* zoom the span horizontally */
383 for (i = 0; i < zoomedWidth; i++) {
384 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
385 assert(j >= 0);
386 assert(j < width);
387 zoomedVals[i] = stencil[j];
388 }
389
390 /* write the zoomed spans */
391 for (y = y0; y < y1; y++) {
392 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
393 }
394
395 free(zoomedVals);
396 }
397
398
399 /**
400 * Zoom/write 32-bit Z values.
401 * No per-fragment operations are applied.
402 */
403 void
_swrast_write_zoomed_z_span(struct gl_context * ctx,GLint imgX,GLint imgY,GLint width,GLint spanX,GLint spanY,const GLuint * zVals)404 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
405 GLint width, GLint spanX, GLint spanY,
406 const GLuint *zVals)
407 {
408 struct gl_renderbuffer *rb =
409 ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
410 GLuint *zoomedVals;
411 GLint x0, x1, y0, y1, y;
412 GLint i, zoomedWidth;
413
414 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
415 &x0, &x1, &y0, &y1)) {
416 return; /* totally clipped */
417 }
418
419 zoomedWidth = x1 - x0;
420 assert(zoomedWidth > 0);
421 assert(zoomedWidth <= SWRAST_MAX_WIDTH);
422
423 zoomedVals = malloc(zoomedWidth * sizeof(GLuint));
424 if (!zoomedVals)
425 return;
426
427 /* zoom the span horizontally */
428 for (i = 0; i < zoomedWidth; i++) {
429 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
430 assert(j >= 0);
431 assert(j < width);
432 zoomedVals[i] = zVals[j];
433 }
434
435 /* write the zoomed spans */
436 for (y = y0; y < y1; y++) {
437 GLubyte *dst = _swrast_pixel_address(rb, x0, y);
438 _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
439 }
440
441 free(zoomedVals);
442 }
443