s_zoom.c revision 3e37bafab0a339021354b9c78f983d05d433d735
1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 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 * Helper function called from _swrast_write_zoomed_rgba/rgb/index_span(). 38 */ 39static void 40zoom_span( GLcontext *ctx, const struct sw_span *span, 41 const GLvoid *src, GLint y0, GLenum format, GLint skipPixels ) 42{ 43 GLint r0, r1, row; 44 GLint c0, c1, skipCol; 45 GLint i, j; 46 const GLuint maxWidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); 47 struct sw_span zoomed; 48 struct span_arrays zoomed_arrays; /* this is big! */ 49 50 /* no pixel arrays! must be horizontal spans. */ 51 ASSERT((span->arrayMask & SPAN_XY) == 0); 52 ASSERT(span->primitive == GL_BITMAP); 53 54 INIT_SPAN(zoomed, GL_BITMAP, 0, 0, 0); 55 zoomed.array = &zoomed_arrays; 56 57 /* copy fog interp info */ 58 zoomed.fog = span->fog; 59 zoomed.fogStep = span->fogStep; 60 /* XXX copy texcoord info? */ 61 62 if (format == GL_RGBA || format == GL_RGB) { 63 /* copy Z info */ 64 zoomed.z = span->z; 65 zoomed.zStep = span->zStep; 66 /* we'll generate an array of colorss */ 67 zoomed.interpMask = span->interpMask & ~SPAN_RGBA; 68 zoomed.arrayMask |= SPAN_RGBA; 69 } 70 else if (format == GL_COLOR_INDEX) { 71 /* copy Z info */ 72 zoomed.z = span->z; 73 zoomed.zStep = span->zStep; 74 /* we'll generate an array of color indexes */ 75 zoomed.interpMask = span->interpMask & ~SPAN_INDEX; 76 zoomed.arrayMask |= SPAN_INDEX; 77 } 78 else { 79 assert(format == GL_DEPTH_COMPONENT); 80 /* Copy color info */ 81 zoomed.red = span->red; 82 zoomed.green = span->green; 83 zoomed.blue = span->blue; 84 zoomed.alpha = span->alpha; 85 zoomed.redStep = span->redStep; 86 zoomed.greenStep = span->greenStep; 87 zoomed.blueStep = span->blueStep; 88 zoomed.alphaStep = span->alphaStep; 89 /* we'll generate an array of depth values */ 90 zoomed.interpMask = span->interpMask & ~SPAN_Z; 91 zoomed.arrayMask |= SPAN_Z; 92 } 93 94 /* 95 * Compute which columns to draw: [c0, c1) 96 */ 97 c0 = (GLint) (span->x + skipPixels * ctx->Pixel.ZoomX); 98 c1 = (GLint) (span->x + (skipPixels + span->end) * ctx->Pixel.ZoomX); 99 if (c0 == c1) { 100 return; 101 } 102 else if (c1 < c0) { 103 /* swap */ 104 GLint ctmp = c1; 105 c1 = c0; 106 c0 = ctmp; 107 } 108 if (c0 < 0) { 109 zoomed.x = 0; 110 zoomed.start = 0; 111 zoomed.end = c1; 112 skipCol = -c0; 113 } 114 else { 115 zoomed.x = c0; 116 zoomed.start = 0; 117 zoomed.end = c1 - c0; 118 skipCol = 0; 119 } 120 if (zoomed.end > maxWidth) 121 zoomed.end = maxWidth; 122 123 /* 124 * Compute which rows to draw: [r0, r1) 125 */ 126 row = span->y - y0; 127 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); 128 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); 129 if (r0 == r1) { 130 return; 131 } 132 else if (r1 < r0) { 133 /* swap */ 134 GLint rtmp = r1; 135 r1 = r0; 136 r0 = rtmp; 137 } 138 139 ASSERT(r0 < r1); 140 ASSERT(c0 < c1); 141 142 /* 143 * Trivial clip rejection testing. 144 */ 145 if (r1 < 0) /* below window */ 146 return; 147 if (r0 >= (GLint) ctx->DrawBuffer->Height) /* above window */ 148 return; 149 if (c1 < 0) /* left of window */ 150 return; 151 if (c0 >= (GLint) ctx->DrawBuffer->Width) /* right of window */ 152 return; 153 154 /* zoom the span horizontally */ 155 if (format == GL_RGBA) { 156 const GLchan (*rgba)[4] = (const GLchan (*)[4]) src; 157 if (ctx->Pixel.ZoomX == -1.0F) { 158 /* common case */ 159 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 160 i = span->end - (j + skipCol) - 1; 161 COPY_CHAN4(zoomed.array->rgba[j], rgba[i]); 162 } 163 } 164 else { 165 /* general solution */ 166 const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 167 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 168 i = (GLint) ((j + skipCol) * xscale); 169 if (ctx->Pixel.ZoomX < 0.0) { 170 ASSERT(i <= 0); 171 i = span->end + i - 1; 172 } 173 ASSERT(i >= 0); 174 ASSERT(i < (GLint) span->end); 175 COPY_CHAN4(zoomed.array->rgba[j], rgba[i]); 176 } 177 } 178 } 179 else if (format == GL_RGB) { 180 const GLchan (*rgb)[3] = (const GLchan (*)[3]) src; 181 if (ctx->Pixel.ZoomX == -1.0F) { 182 /* common case */ 183 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 184 i = span->end - (j + skipCol) - 1; 185 zoomed.array->rgba[j][0] = rgb[i][0]; 186 zoomed.array->rgba[j][1] = rgb[i][1]; 187 zoomed.array->rgba[j][2] = rgb[i][2]; 188 zoomed.array->rgba[j][3] = CHAN_MAX; 189 } 190 } 191 else { 192 /* general solution */ 193 const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 194 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 195 i = (GLint) ((j + skipCol) * xscale); 196 if (ctx->Pixel.ZoomX < 0.0) { 197 ASSERT(i <= 0); 198 i = span->end + i - 1; 199 } 200 ASSERT(i >= 0); 201 ASSERT(i < (GLint) span->end); 202 zoomed.array->rgba[j][0] = rgb[i][0]; 203 zoomed.array->rgba[j][1] = rgb[i][1]; 204 zoomed.array->rgba[j][2] = rgb[i][2]; 205 zoomed.array->rgba[j][3] = CHAN_MAX; 206 } 207 } 208 } 209 else if (format == GL_COLOR_INDEX) { 210 const GLuint *indexes = (const GLuint *) src; 211 if (ctx->Pixel.ZoomX == -1.0F) { 212 /* common case */ 213 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 214 i = span->end - (j + skipCol) - 1; 215 zoomed.array->index[j] = indexes[i]; 216 } 217 } 218 else { 219 /* general solution */ 220 const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 221 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 222 i = (GLint) ((j + skipCol) * xscale); 223 if (ctx->Pixel.ZoomX < 0.0) { 224 ASSERT(i <= 0); 225 i = span->end + i - 1; 226 } 227 ASSERT(i >= 0); 228 ASSERT(i < (GLint) span->end); 229 zoomed.array->index[j] = indexes[i]; 230 } 231 } 232 } 233 else { 234 const GLuint *zValues = (const GLuint *) src; 235 assert(format == GL_DEPTH_COMPONENT); 236 if (ctx->Pixel.ZoomX == -1.0F) { 237 /* common case */ 238 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 239 i = span->end - (j + skipCol) - 1; 240 zoomed.array->z[j] = zValues[i]; 241 } 242 } 243 else { 244 /* general solution */ 245 const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 246 for (j = (GLint) zoomed.start; j < (GLint) zoomed.end; j++) { 247 i = (GLint) ((j + skipCol) * xscale); 248 if (ctx->Pixel.ZoomX < 0.0) { 249 ASSERT(i <= 0); 250 i = span->end + i - 1; 251 } 252 ASSERT(i >= 0); 253 ASSERT(i < (GLint) span->end); 254 zoomed.array->z[j] = zValues[i]; 255 } 256 } 257 /* Now, fall into either the RGB or COLOR_INDEX path below */ 258 if (ctx->Visual.rgbMode) 259 format = GL_RGBA; 260 else 261 format = GL_COLOR_INDEX; 262 } 263 264 265 /* write the span in rows [r0, r1) */ 266 if (format == GL_RGBA || format == GL_RGB) { 267 /* Writing the span may modify the colors, so make a backup now if we're 268 * going to call _swrast_write_zoomed_span() more than once. 269 * Also, clipping may change the span end value, so store it as well. 270 */ 271 GLchan rgbaSave[MAX_WIDTH][4]; 272 const GLint end = zoomed.end; /* save */ 273 if (r1 - r0 > 1) { 274 MEMCPY(rgbaSave, zoomed.array->rgba, zoomed.end * 4 * sizeof(GLchan)); 275 } 276 for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) { 277 _swrast_write_rgba_span(ctx, &zoomed); 278 zoomed.end = end; /* restore */ 279 if (r1 - r0 > 1) { 280 /* restore the colors */ 281 MEMCPY(zoomed.array->rgba, rgbaSave, zoomed.end*4 * sizeof(GLchan)); 282 } 283 } 284 } 285 else if (format == GL_COLOR_INDEX) { 286 GLuint indexSave[MAX_WIDTH]; 287 const GLint end = zoomed.end; /* save */ 288 if (r1 - r0 > 1) { 289 MEMCPY(indexSave, zoomed.array->index, zoomed.end * sizeof(GLuint)); 290 } 291 for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) { 292 _swrast_write_index_span(ctx, &zoomed); 293 zoomed.end = end; /* restore */ 294 if (r1 - r0 > 1) { 295 /* restore the colors */ 296 MEMCPY(zoomed.array->index, indexSave, zoomed.end * sizeof(GLuint)); 297 } 298 } 299 } 300} 301 302 303void 304_swrast_write_zoomed_rgba_span( GLcontext *ctx, const struct sw_span *span, 305 CONST GLchan rgba[][4], GLint y0, 306 GLint skipPixels ) 307{ 308 zoom_span(ctx, span, (const GLvoid *) rgba, y0, GL_RGBA, skipPixels); 309} 310 311 312void 313_swrast_write_zoomed_rgb_span( GLcontext *ctx, const struct sw_span *span, 314 CONST GLchan rgb[][3], GLint y0, 315 GLint skipPixels ) 316{ 317 zoom_span(ctx, span, (const GLvoid *) rgb, y0, GL_RGB, skipPixels); 318} 319 320 321void 322_swrast_write_zoomed_index_span( GLcontext *ctx, const struct sw_span *span, 323 GLint y0, GLint skipPixels ) 324{ 325 zoom_span(ctx, span, (const GLvoid *) span->array->index, y0, 326 GL_COLOR_INDEX, skipPixels); 327} 328 329 330void 331_swrast_write_zoomed_depth_span( GLcontext *ctx, const struct sw_span *span, 332 GLint y0, GLint skipPixels ) 333{ 334 zoom_span(ctx, span, (const GLvoid *) span->array->z, y0, 335 GL_DEPTH_COMPONENT, skipPixels); 336} 337 338 339/* 340 * As above, but write stencil values. 341 */ 342void 343_swrast_write_zoomed_stencil_span( GLcontext *ctx, 344 GLuint n, GLint x, GLint y, 345 const GLstencil stencil[], GLint y0, 346 GLint skipPixels ) 347{ 348 GLint m; 349 GLint r0, r1, row, r; 350 GLint i, j, skipcol; 351 GLstencil zstencil[MAX_WIDTH]; /* zoomed stencil values */ 352 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); 353 354 (void) skipPixels; /* XXX this shouldn't be ignored */ 355 356 /* compute width of output row */ 357 m = (GLint) FABSF( n * ctx->Pixel.ZoomX ); 358 if (m==0) { 359 return; 360 } 361 if (ctx->Pixel.ZoomX<0.0) { 362 /* adjust x coordinate for left/right mirroring */ 363 x = x - m; 364 } 365 366 /* compute which rows to draw */ 367 row = y - y0; 368 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); 369 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); 370 if (r0==r1) { 371 return; 372 } 373 else if (r1<r0) { 374 GLint rtmp = r1; 375 r1 = r0; 376 r0 = rtmp; 377 } 378 379 /* return early if r0...r1 is above or below window */ 380 if (r0<0 && r1<0) { 381 /* below window */ 382 return; 383 } 384 if (r0 >= (GLint) ctx->DrawBuffer->Height && 385 r1 >= (GLint) ctx->DrawBuffer->Height) { 386 /* above window */ 387 return; 388 } 389 390 /* check if left edge is outside window */ 391 skipcol = 0; 392 if (x<0) { 393 skipcol = -x; 394 m += x; 395 } 396 /* make sure span isn't too long or short */ 397 if (m>maxwidth) { 398 m = maxwidth; 399 } 400 else if (m<=0) { 401 return; 402 } 403 404 ASSERT( m <= MAX_WIDTH ); 405 406 /* zoom the span horizontally */ 407 if (ctx->Pixel.ZoomX==-1.0F) { 408 /* n==m */ 409 for (j=0;j<m;j++) { 410 i = n - (j+skipcol) - 1; 411 zstencil[j] = stencil[i]; 412 } 413 } 414 else { 415 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 416 for (j=0;j<m;j++) { 417 i = (GLint) ((j+skipcol) * xscale); 418 if (i<0) i = n + i - 1; 419 zstencil[j] = stencil[i]; 420 } 421 } 422 423 /* write the span */ 424 for (r=r0; r<r1; r++) { 425 _swrast_write_stencil_span( ctx, m, x+skipcol, r, zstencil ); 426 } 427} 428