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/format_pack.h" 29 #include "main/colormac.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 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 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.0) 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 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(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[FRAG_ATTRIB_COL0]; 170 171 COPY_4V(zoomed.attrStart[FRAG_ATTRIB_WPOS], span->attrStart[FRAG_ATTRIB_WPOS]); 172 COPY_4V(zoomed.attrStepX[FRAG_ATTRIB_WPOS], span->attrStepX[FRAG_ATTRIB_WPOS]); 173 COPY_4V(zoomed.attrStepY[FRAG_ATTRIB_WPOS], span->attrStepY[FRAG_ATTRIB_WPOS]); 174 175 zoomed.attrStart[FRAG_ATTRIB_FOGC][0] = span->attrStart[FRAG_ATTRIB_FOGC][0]; 176 zoomed.attrStepX[FRAG_ATTRIB_FOGC][0] = span->attrStepX[FRAG_ATTRIB_FOGC][0]; 177 zoomed.attrStepY[FRAG_ATTRIB_FOGC][0] = span->attrStepY[FRAG_ATTRIB_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 |= FRAG_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 < span->end); 238 COPY_4V(zoomed.array->attribs[FRAG_ATTRIB_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 < span->end); 276 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][0] = rgb[j][0]; 277 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][1] = rgb[j][1]; 278 zoomed.array->attribs[FRAG_ATTRIB_COL0][i][2] = rgb[j][2]; 279 zoomed.array->attribs[FRAG_ATTRIB_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 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 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 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 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 = (GLubyte *) 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 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 = (GLuint *) 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