s_zoom.c revision c1cb5412336be0e1067899318403ea573be9bb4d
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 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 SWspan zoomed; 134 SWspanarrays zoomed_arrays; /* this is big! */ 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 zoomedWidth = x1 - x0; 144 ASSERT(zoomedWidth > 0); 145 ASSERT(zoomedWidth <= MAX_WIDTH); 146 147 /* no pixel arrays! must be horizontal spans. */ 148 ASSERT((span->arrayMask & SPAN_XY) == 0); 149 ASSERT(span->primitive == GL_BITMAP); 150 151 INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0); 152 zoomed.x = x0; 153 zoomed.end = zoomedWidth; 154 zoomed.array = &zoomed_arrays; 155 zoomed_arrays.ChanType = span->array->ChanType; 156 /* XXX temporary */ 157#if CHAN_TYPE == GL_UNSIGNED_BYTE 158 zoomed_arrays.rgba = zoomed_arrays.rgba8; 159#elif CHAN_TYPE == GL_UNSIGNED_SHORT 160 zoomed_arrays.rgba = zoomed_arrays.rgba16; 161#else 162 zoomed_arrays.rgba = zoomed_arrays.attribs[FRAG_ATTRIB_COL0]; 163#endif 164 165 /* copy attribute info (XXX copy all attribs?) */ 166 COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]); 167 COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]); 168 COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]); 169 170 zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0]; 171 zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0]; 172 zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_FOGC][0]; 173 174 if (format == GL_RGBA || format == GL_RGB) { 175 /* copy Z info */ 176 zoomed.z = span->z; 177 zoomed.zStep = span->zStep; 178 /* we'll generate an array of colorss */ 179 zoomed.interpMask = span->interpMask & ~SPAN_RGBA; 180 zoomed.arrayMask |= SPAN_RGBA; 181 ASSERT(span->arrayMask & SPAN_RGBA); 182 } 183 else if (format == GL_COLOR_INDEX) { 184 /* copy Z info */ 185 zoomed.z = span->z; 186 zoomed.zStep = span->zStep; 187 /* we'll generate an array of color indexes */ 188 zoomed.interpMask = span->interpMask & ~SPAN_INDEX; 189 zoomed.arrayMask |= SPAN_INDEX; 190 ASSERT(span->arrayMask & SPAN_INDEX); 191 } 192 else if (format == GL_DEPTH_COMPONENT) { 193 /* Copy color info */ 194 zoomed.red = span->red; 195 zoomed.green = span->green; 196 zoomed.blue = span->blue; 197 zoomed.alpha = span->alpha; 198 zoomed.redStep = span->redStep; 199 zoomed.greenStep = span->greenStep; 200 zoomed.blueStep = span->blueStep; 201 zoomed.alphaStep = span->alphaStep; 202 /* we'll generate an array of depth values */ 203 zoomed.interpMask = span->interpMask & ~SPAN_Z; 204 zoomed.arrayMask |= SPAN_Z; 205 ASSERT(span->arrayMask & SPAN_Z); 206 } 207 else { 208 _mesa_problem(ctx, "Bad format in zoom_span"); 209 return; 210 } 211 212 /* zoom the span horizontally */ 213 if (format == GL_RGBA) { 214 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) { 215 const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src; 216 GLint i; 217 for (i = 0; i < zoomedWidth; i++) { 218 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 219 ASSERT(j >= 0); 220 ASSERT(j < (GLint) span->end); 221 COPY_4UBV(zoomed.array->rgba8[i], rgba[j]); 222 } 223 } 224 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) { 225 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src; 226 GLint i; 227 for (i = 0; i < zoomedWidth; i++) { 228 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 229 ASSERT(j >= 0); 230 ASSERT(j < (GLint) span->end); 231 COPY_4V(zoomed.array->rgba16[i], rgba[j]); 232 } 233 } 234 else { 235 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src; 236 GLint i; 237 for (i = 0; i < zoomedWidth; i++) { 238 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 239 ASSERT(j >= 0); 240 ASSERT(j < span->end); 241 COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_COL0][i], rgba[j]); 242 } 243 } 244 } 245 else if (format == GL_RGB) { 246 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) { 247 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src; 248 GLint i; 249 for (i = 0; i < zoomedWidth; i++) { 250 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 251 ASSERT(j >= 0); 252 ASSERT(j < (GLint) span->end); 253 zoomed.array->rgba8[i][0] = rgb[j][0]; 254 zoomed.array->rgba8[i][1] = rgb[j][1]; 255 zoomed.array->rgba8[i][2] = rgb[j][2]; 256 zoomed.array->rgba8[i][3] = 0xff; 257 } 258 } 259 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) { 260 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src; 261 GLint i; 262 for (i = 0; i < zoomedWidth; i++) { 263 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 264 ASSERT(j >= 0); 265 ASSERT(j < (GLint) span->end); 266 zoomed.array->rgba16[i][0] = rgb[j][0]; 267 zoomed.array->rgba16[i][1] = rgb[j][1]; 268 zoomed.array->rgba16[i][2] = rgb[j][2]; 269 zoomed.array->rgba16[i][3] = 0xffff; 270 } 271 } 272 else { 273 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src; 274 GLint i; 275 for (i = 0; i < zoomedWidth; i++) { 276 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 277 ASSERT(j >= 0); 278 ASSERT(j < span->end); 279 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][0] = rgb[j][0]; 280 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][1] = rgb[j][1]; 281 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][2] = rgb[j][2]; 282 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][3] = 1.0F; 283 } 284 } 285 } 286 else if (format == GL_COLOR_INDEX) { 287 const GLuint *indexes = (const GLuint *) src; 288 GLint i; 289 for (i = 0; i < zoomedWidth; i++) { 290 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 291 ASSERT(j >= 0); 292 ASSERT(j < (GLint) span->end); 293 zoomed.array->index[i] = indexes[j]; 294 } 295 } 296 else if (format == GL_DEPTH_COMPONENT) { 297 const GLuint *zValues = (const GLuint *) src; 298 GLint i; 299 for (i = 0; i < zoomedWidth; i++) { 300 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 301 ASSERT(j >= 0); 302 ASSERT(j < (GLint) span->end); 303 zoomed.array->z[i] = zValues[j]; 304 } 305 /* Now, fall into either the RGB or COLOR_INDEX path below */ 306 format = ctx->Visual.rgbMode ? GL_RGBA : GL_COLOR_INDEX; 307 } 308 309 /* write the span in rows [r0, r1) */ 310 if (format == GL_RGBA || format == GL_RGB) { 311 /* Writing the span may modify the colors, so make a backup now if we're 312 * going to call _swrast_write_zoomed_span() more than once. 313 * Also, clipping may change the span end value, so store it as well. 314 */ 315 const GLint end = zoomed.end; /* save */ 316 GLuint rgbaSave[MAX_WIDTH][4]; 317 const GLint pixelSize = 318 (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) : 319 ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort) 320 : 4 * sizeof(GLfloat)); 321 if (y1 - y0 > 1) { 322 MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize); 323 } 324 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) { 325 _swrast_write_rgba_span(ctx, &zoomed); 326 zoomed.end = end; /* restore */ 327 if (y1 - y0 > 1) { 328 /* restore the colors */ 329 MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize); 330 } 331 } 332 } 333 else if (format == GL_COLOR_INDEX) { 334 /* use specular color array for temp storage */ 335 GLuint *indexSave = (GLuint *) zoomed.array->attribs[FRAG_ATTRIB_FOGC]; 336 const GLint end = zoomed.end; /* save */ 337 if (y1 - y0 > 1) { 338 MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint)); 339 } 340 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) { 341 _swrast_write_index_span(ctx, &zoomed); 342 zoomed.end = end; /* restore */ 343 if (y1 - y0 > 1) { 344 /* restore the colors */ 345 MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint)); 346 } 347 } 348 } 349} 350 351 352void 353_swrast_write_zoomed_rgba_span(GLcontext *ctx, GLint imgX, GLint imgY, 354 const SWspan *span, const GLvoid *rgba) 355{ 356 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA); 357} 358 359 360void 361_swrast_write_zoomed_rgb_span(GLcontext *ctx, GLint imgX, GLint imgY, 362 const SWspan *span, const GLvoid *rgb) 363{ 364 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB); 365} 366 367 368void 369_swrast_write_zoomed_index_span(GLcontext *ctx, GLint imgX, GLint imgY, 370 const SWspan *span) 371{ 372 zoom_span(ctx, imgX, imgY, span, 373 (const GLvoid *) span->array->index, GL_COLOR_INDEX); 374} 375 376 377void 378_swrast_write_zoomed_depth_span(GLcontext *ctx, GLint imgX, GLint imgY, 379 const SWspan *span) 380{ 381 zoom_span(ctx, imgX, imgY, span, 382 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT); 383} 384 385 386/** 387 * Zoom/write stencil values. 388 * No per-fragment operations are applied. 389 */ 390void 391_swrast_write_zoomed_stencil_span(GLcontext *ctx, GLint imgX, GLint imgY, 392 GLint width, GLint spanX, GLint spanY, 393 const GLstencil stencil[]) 394{ 395 GLstencil zoomedVals[MAX_WIDTH]; 396 GLint x0, x1, y0, y1, y; 397 GLint i, zoomedWidth; 398 399 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, 400 &x0, &x1, &y0, &y1)) { 401 return; /* totally clipped */ 402 } 403 404 zoomedWidth = x1 - x0; 405 ASSERT(zoomedWidth > 0); 406 ASSERT(zoomedWidth <= MAX_WIDTH); 407 408 /* zoom the span horizontally */ 409 for (i = 0; i < zoomedWidth; i++) { 410 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; 411 ASSERT(j >= 0); 412 ASSERT(j < width); 413 zoomedVals[i] = stencil[j]; 414 } 415 416 /* write the zoomed spans */ 417 for (y = y0; y < y1; y++) { 418 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals); 419 } 420} 421 422 423/** 424 * Zoom/write z values (16 or 32-bit). 425 * No per-fragment operations are applied. 426 */ 427void 428_swrast_write_zoomed_z_span(GLcontext *ctx, GLint imgX, GLint imgY, 429 GLint width, GLint spanX, GLint spanY, 430 const GLvoid *z) 431{ 432 struct gl_renderbuffer *rb = ctx->DrawBuffer->_DepthBuffer; 433 GLushort zoomedVals16[MAX_WIDTH]; 434 GLuint zoomedVals32[MAX_WIDTH]; 435 GLint x0, x1, y0, y1, y; 436 GLint i, zoomedWidth; 437 438 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, 439 &x0, &x1, &y0, &y1)) { 440 return; /* totally clipped */ 441 } 442 443 zoomedWidth = x1 - x0; 444 ASSERT(zoomedWidth > 0); 445 ASSERT(zoomedWidth <= MAX_WIDTH); 446 447 /* zoom the span horizontally */ 448 if (rb->DataType == GL_UNSIGNED_SHORT) { 449 for (i = 0; i < zoomedWidth; i++) { 450 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; 451 ASSERT(j >= 0); 452 ASSERT(j < width); 453 zoomedVals16[i] = ((GLushort *) z)[j]; 454 } 455 z = zoomedVals16; 456 } 457 else { 458 ASSERT(rb->DataType == GL_UNSIGNED_INT); 459 for (i = 0; i < zoomedWidth; i++) { 460 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; 461 ASSERT(j >= 0); 462 ASSERT(j < width); 463 zoomedVals32[i] = ((GLuint *) z)[j]; 464 } 465 z = zoomedVals32; 466 } 467 468 /* write the zoomed spans */ 469 for (y = y0; y < y1; y++) { 470 rb->PutRow(ctx, rb, zoomedWidth, x0, y, z, NULL); 471 } 472} 473