s_zoom.c revision b8e80941
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#include "main/imports.h" 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 */ 48static GLboolean 49compute_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 */ 109static inline GLint 110unzoom_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 */ 130static void 131zoom_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 331void 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 339void 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 347void 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 */ 360void 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 */ 403void 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