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/glheader.h" 26 #include "main/macros.h" 27 #include "main/imports.h" 28 #include "main/format_pack.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 */ 47 static GLboolean 48 compute_zoomed_bounds(struct gl_context *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 */ 108 static inline GLint 109 unzoom_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.0F) 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 */ 129 static void 130 zoom_span( struct gl_context *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(1, sizeof(SWspanarrays)); 146 if (!swrast->ZoomedArrays) 147 return; 148 } 149 150 zoomedWidth = x1 - x0; 151 assert(zoomedWidth > 0); 152 assert(zoomedWidth <= SWRAST_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[VARYING_SLOT_COL0]; 169 170 COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]); 171 COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]); 172 COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]); 173 174 zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0]; 175 zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0]; 176 zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_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 |= VARYING_BIT_COL0; /* we'll produce these values */ 186 assert(span->arrayMask & SPAN_RGBA); 187 } 188 else if (format == GL_DEPTH_COMPONENT) { 189 /* Copy color info */ 190 zoomed.red = span->red; 191 zoomed.green = span->green; 192 zoomed.blue = span->blue; 193 zoomed.alpha = span->alpha; 194 zoomed.redStep = span->redStep; 195 zoomed.greenStep = span->greenStep; 196 zoomed.blueStep = span->blueStep; 197 zoomed.alphaStep = span->alphaStep; 198 /* we'll generate an array of depth values */ 199 zoomed.interpMask = span->interpMask & ~SPAN_Z; 200 zoomed.arrayMask |= SPAN_Z; 201 assert(span->arrayMask & SPAN_Z); 202 } 203 else { 204 _mesa_problem(ctx, "Bad format in zoom_span"); 205 return; 206 } 207 208 /* zoom the span horizontally */ 209 if (format == GL_RGBA) { 210 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) { 211 const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src; 212 GLint i; 213 for (i = 0; i < zoomedWidth; i++) { 214 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 215 assert(j >= 0); 216 assert(j < (GLint) span->end); 217 COPY_4UBV(zoomed.array->rgba8[i], rgba[j]); 218 } 219 } 220 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) { 221 const GLushort (*rgba)[4] = (const GLushort (*)[4]) src; 222 GLint i; 223 for (i = 0; i < zoomedWidth; i++) { 224 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 225 assert(j >= 0); 226 assert(j < (GLint) span->end); 227 COPY_4V(zoomed.array->rgba16[i], rgba[j]); 228 } 229 } 230 else { 231 const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src; 232 GLint i; 233 for (i = 0; i < zoomedWidth; i++) { 234 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 235 assert(j >= 0); 236 assert(j < (GLint) span->end); 237 COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgba[j]); 238 } 239 } 240 } 241 else if (format == GL_RGB) { 242 if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) { 243 const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src; 244 GLint i; 245 for (i = 0; i < zoomedWidth; i++) { 246 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 247 assert(j >= 0); 248 assert(j < (GLint) span->end); 249 zoomed.array->rgba8[i][0] = rgb[j][0]; 250 zoomed.array->rgba8[i][1] = rgb[j][1]; 251 zoomed.array->rgba8[i][2] = rgb[j][2]; 252 zoomed.array->rgba8[i][3] = 0xff; 253 } 254 } 255 else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) { 256 const GLushort (*rgb)[3] = (const GLushort (*)[3]) src; 257 GLint i; 258 for (i = 0; i < zoomedWidth; i++) { 259 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 260 assert(j >= 0); 261 assert(j < (GLint) span->end); 262 zoomed.array->rgba16[i][0] = rgb[j][0]; 263 zoomed.array->rgba16[i][1] = rgb[j][1]; 264 zoomed.array->rgba16[i][2] = rgb[j][2]; 265 zoomed.array->rgba16[i][3] = 0xffff; 266 } 267 } 268 else { 269 const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src; 270 GLint i; 271 for (i = 0; i < zoomedWidth; i++) { 272 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 273 assert(j >= 0); 274 assert(j < (GLint) span->end); 275 zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0]; 276 zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1]; 277 zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2]; 278 zoomed.array->attribs[VARYING_SLOT_COL0][i][3] = 1.0F; 279 } 280 } 281 } 282 else if (format == GL_DEPTH_COMPONENT) { 283 const GLuint *zValues = (const GLuint *) src; 284 GLint i; 285 for (i = 0; i < zoomedWidth; i++) { 286 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x; 287 assert(j >= 0); 288 assert(j < (GLint) span->end); 289 zoomed.array->z[i] = zValues[j]; 290 } 291 /* Now, fall into the RGB path below */ 292 format = GL_RGBA; 293 } 294 295 /* write the span in rows [r0, r1) */ 296 if (format == GL_RGBA || format == GL_RGB) { 297 /* Writing the span may modify the colors, so make a backup now if we're 298 * going to call _swrast_write_zoomed_span() more than once. 299 * Also, clipping may change the span end value, so store it as well. 300 */ 301 const GLint end = zoomed.end; /* save */ 302 void *rgbaSave; 303 const GLint pixelSize = 304 (zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) : 305 ((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort) 306 : 4 * sizeof(GLfloat)); 307 308 rgbaSave = malloc(zoomed.end * pixelSize); 309 if (!rgbaSave) { 310 return; 311 } 312 313 if (y1 - y0 > 1) { 314 memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize); 315 } 316 for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) { 317 _swrast_write_rgba_span(ctx, &zoomed); 318 zoomed.end = end; /* restore */ 319 if (y1 - y0 > 1) { 320 /* restore the colors */ 321 memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize); 322 } 323 } 324 325 free(rgbaSave); 326 } 327 } 328 329 330 void 331 _swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY, 332 const SWspan *span, const GLvoid *rgba) 333 { 334 zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA); 335 } 336 337 338 void 339 _swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY, 340 const SWspan *span, const GLvoid *rgb) 341 { 342 zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB); 343 } 344 345 346 void 347 _swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY, 348 const SWspan *span) 349 { 350 zoom_span(ctx, imgX, imgY, span, 351 (const GLvoid *) span->array->z, GL_DEPTH_COMPONENT); 352 } 353 354 355 /** 356 * Zoom/write stencil values. 357 * No per-fragment operations are applied. 358 */ 359 void 360 _swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY, 361 GLint width, GLint spanX, GLint spanY, 362 const GLubyte stencil[]) 363 { 364 GLubyte *zoomedVals; 365 GLint x0, x1, y0, y1, y; 366 GLint i, zoomedWidth; 367 368 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, 369 &x0, &x1, &y0, &y1)) { 370 return; /* totally clipped */ 371 } 372 373 zoomedWidth = x1 - x0; 374 assert(zoomedWidth > 0); 375 assert(zoomedWidth <= SWRAST_MAX_WIDTH); 376 377 zoomedVals = malloc(zoomedWidth * sizeof(GLubyte)); 378 if (!zoomedVals) 379 return; 380 381 /* zoom the span horizontally */ 382 for (i = 0; i < zoomedWidth; i++) { 383 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; 384 assert(j >= 0); 385 assert(j < width); 386 zoomedVals[i] = stencil[j]; 387 } 388 389 /* write the zoomed spans */ 390 for (y = y0; y < y1; y++) { 391 _swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals); 392 } 393 394 free(zoomedVals); 395 } 396 397 398 /** 399 * Zoom/write 32-bit Z values. 400 * No per-fragment operations are applied. 401 */ 402 void 403 _swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY, 404 GLint width, GLint spanX, GLint spanY, 405 const GLuint *zVals) 406 { 407 struct gl_renderbuffer *rb = 408 ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; 409 GLuint *zoomedVals; 410 GLint x0, x1, y0, y1, y; 411 GLint i, zoomedWidth; 412 413 if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width, 414 &x0, &x1, &y0, &y1)) { 415 return; /* totally clipped */ 416 } 417 418 zoomedWidth = x1 - x0; 419 assert(zoomedWidth > 0); 420 assert(zoomedWidth <= SWRAST_MAX_WIDTH); 421 422 zoomedVals = malloc(zoomedWidth * sizeof(GLuint)); 423 if (!zoomedVals) 424 return; 425 426 /* zoom the span horizontally */ 427 for (i = 0; i < zoomedWidth; i++) { 428 GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX; 429 assert(j >= 0); 430 assert(j < width); 431 zoomedVals[i] = zVals[j]; 432 } 433 434 /* write the zoomed spans */ 435 for (y = y0; y < y1; y++) { 436 GLubyte *dst = _swrast_pixel_address(rb, x0, y); 437 _mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst); 438 } 439 440 free(zoomedVals); 441 } 442