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