s_zoom.c revision 2a182a98973edc9ecf2936b1288485bb2b3fa722
1/* $Id: s_zoom.c,v 1.9 2002/01/27 18:32:03 brianp Exp $ */ 2 3/* 4 * Mesa 3-D graphics library 5 * Version: 4.1 6 * 7 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26 27#include "glheader.h" 28#include "macros.h" 29#include "mem.h" 30#include "colormac.h" 31 32#include "s_context.h" 33#include "s_span.h" 34#include "s_stencil.h" 35#include "s_zoom.h" 36 37 38#ifdef DEBUG 39 40#define SAVE_SPAN(span) struct sw_span tmp_span = (span); 41 42#define RESTORE_SPAN(span) \ 43{ \ 44 GLint i; \ 45 for (i=tmp_span.start; i<tmp_span.end; i++) { \ 46 if (tmp_span.color.rgba[i][RCOMP] != \ 47 (span).color.rgba[i][RCOMP] || \ 48 tmp_span.color.rgba[i][GCOMP] != \ 49 (span).color.rgba[i][GCOMP] || \ 50 tmp_span.color.rgba[i][BCOMP] != \ 51 (span).color.rgba[i][BCOMP]) { \ 52 fprintf(stderr, "glZoom: Color-span changed in subfunction."); \ 53 } \ 54 if (tmp_span.zArray[i] != (span).zArray[i]) { \ 55 fprintf(stderr, "glZoom: Depth-span changed in subfunction."); \ 56 } \ 57 } \ 58 (span) = tmp_span; \ 59} 60 61#else /* DEBUG not defined */ 62 63#define SAVE_SPAN(span) GLint start = (span).start, end = (span).end; 64#define RESTORE_SPAN(span) (span).start = start, (span).end = end; \ 65 (span).writeAll = GL_TRUE; 66 67#endif /* DEBUG */ 68 69/* 70 * Write a span of pixels to the frame buffer while applying a pixel zoom. 71 * This is only used by glDrawPixels and glCopyPixels. 72 * Input: n - number of pixels in input row 73 * x, y - destination of the span 74 * z - depth values for the span 75 * red, green, blue, alpha - array of colors 76 * y0 - location of first row in the image we're drawing. 77 */ 78void 79_mesa_write_zoomed_rgba_span( GLcontext *ctx, 80 GLuint n, GLint x, GLint y, const GLdepth z[], 81 const GLfloat *fog, 82 CONST GLchan rgba[][4], GLint y0 ) 83{ 84 GLint r0, r1, row; 85 GLint i, j; 86 struct sw_span zoomed; 87 const GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); 88 89 SW_SPAN_RESET (zoomed); 90 INIT_SPAN(zoomed); 91 92 /* compute width of output row */ 93 zoomed.end = (GLint) ABSF( n * ctx->Pixel.ZoomX ); 94 if (zoomed.end == 0) { 95 return; 96 } 97 /*here ok or better latter? like it was before */ 98 else if (zoomed.end > maxwidth) { 99 zoomed.end = maxwidth; 100 } 101 102 if (ctx->Pixel.ZoomX<0.0) { 103 /* adjust x coordinate for left/right mirroring */ 104 zoomed.x = x - zoomed.end; 105 } 106 else 107 zoomed.x = x; 108 109 110 /* compute which rows to draw */ 111 row = y-y0; 112 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); 113 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); 114 if (r0==r1) { 115 return; 116 } 117 else if (r1<r0) { 118 GLint rtmp = r1; 119 r1 = r0; 120 r0 = rtmp; 121 } 122 123 /* return early if r0...r1 is above or below window */ 124 if (r0<0 && r1<0) { 125 /* below window */ 126 return; 127 } 128 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) { 129 /* above window */ 130 return; 131 } 132 133 /* check if left edge is outside window */ 134 if (zoomed.x < 0) { 135 zoomed.start = -x; 136 } 137 138 /* make sure span isn't too long or short */ 139 /* if (m>maxwidth) { 140 m = maxwidth; 141 }*/ 142 143 if (zoomed.end <= zoomed.start) { 144 return; 145 } 146 147 ASSERT( zoomed.end <= MAX_WIDTH ); 148 149 /* zoom the span horizontally */ 150 if (ctx->Pixel.ZoomX==-1.0F) { 151 SW_SPAN_SET_FLAG(zoomed.filledColor); 152 SW_SPAN_SET_FLAG(zoomed.filledAlpha); 153 SW_SPAN_SET_FLAG(zoomed.filledDepth); 154 /* n==m */ 155 for (j=zoomed.start; j<zoomed.end; j++) { 156 i = n - j - 1; 157 COPY_CHAN4(zoomed.color.rgba[j], rgba[i]); 158 zoomed.zArray[j] = z[i]; 159 } 160 if (fog && ctx->Fog.Enabled) { 161 for (j=zoomed.start; j<zoomed.end; j++) { 162 i = n - j - 1; 163 zoomed.fogArray[j] = fog[i]; 164 } 165 } 166 } 167 else { 168 const GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 169 SW_SPAN_SET_FLAG(zoomed.filledColor); 170 SW_SPAN_SET_FLAG(zoomed.filledAlpha); 171 SW_SPAN_SET_FLAG(zoomed.filledDepth); 172 for (j=zoomed.start; j<zoomed.end; j++) { 173 i = (GLint) (j * xscale); 174 if (i<0) i = n + i - 1; 175 COPY_CHAN4(zoomed.color.rgba[j], rgba[i]); 176 zoomed.zArray[j] = z[i]; 177 } 178 if (fog && ctx->Fog.Enabled) { 179 for (j=zoomed.start; j<zoomed.end; j++) { 180 i = (GLint) (j * xscale); 181 if (i<0) i = n + i - 1; 182 zoomed.fogArray[j] = fog[i]; 183 } 184 } 185 } 186 187 zoomed.arrayMask |= SPAN_Z; 188 if (fog) 189 zoomed.arrayMask |= SPAN_FOG; 190 191 /* write the span */ 192 for (zoomed.y = r0; zoomed.y < r1; zoomed.y++) { 193 SAVE_SPAN(zoomed); 194 ASSERT((zoomed.interpMask & SPAN_RGBA) == 0); 195 _mesa_write_rgba_span(ctx, &zoomed, GL_BITMAP); 196 RESTORE_SPAN(zoomed); 197 /* problem here: "zoomed" can change inside 198 "_mesa_write_rgba_span". Best solution: make copy "tmpspan" 199 and give to function, but too slow */ 200 } 201} 202 203 204 205void 206_mesa_write_zoomed_rgb_span( GLcontext *ctx, 207 GLuint n, GLint x, GLint y, const GLdepth z[], 208 const GLfloat *fog, 209 CONST GLchan rgb[][3], GLint y0 ) 210{ 211 GLint m; 212 GLint r0, r1, row, r; 213 GLint i, j, skipcol; 214 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); 215 struct sw_span zoomed; 216 217 INIT_SPAN(zoomed); 218 zoomed.arrayMask |= SPAN_RGBA; 219 220 if (fog && ctx->Fog.Enabled) 221 zoomed.arrayMask |= SPAN_FOG; 222 223 224 /* compute width of output row */ 225 m = (GLint) ABSF( n * ctx->Pixel.ZoomX ); 226 if (m==0) { 227 return; 228 } 229 if (ctx->Pixel.ZoomX<0.0) { 230 /* adjust x coordinate for left/right mirroring */ 231 x = x - m; 232 } 233 234 /* compute which rows to draw */ 235 row = y-y0; 236 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); 237 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); 238 if (r0==r1) { 239 return; 240 } 241 else if (r1<r0) { 242 GLint rtmp = r1; 243 r1 = r0; 244 r0 = rtmp; 245 } 246 247 /* return early if r0...r1 is above or below window */ 248 if (r0<0 && r1<0) { 249 /* below window */ 250 return; 251 } 252 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) { 253 /* above window */ 254 return; 255 } 256 257 /* check if left edge is outside window */ 258 skipcol = 0; 259 if (x<0) { 260 skipcol = -x; 261 m += x; 262 } 263 /* make sure span isn't too long or short */ 264 if (m>maxwidth) { 265 m = maxwidth; 266 } 267 else if (m<=0) { 268 return; 269 } 270 271 ASSERT( m <= MAX_WIDTH ); 272 273 /* zoom the span horizontally */ 274 if (ctx->Pixel.ZoomX==-1.0F) { 275 /* n==m */ 276 for (j=0;j<m;j++) { 277 i = n - (j+skipcol) - 1; 278 zoomed.color.rgba[j][0] = rgb[i][0]; 279 zoomed.color.rgba[j][1] = rgb[i][1]; 280 zoomed.color.rgba[j][2] = rgb[i][2]; 281 zoomed.color.rgba[j][3] = CHAN_MAX; 282 zoomed.zArray[j] = z[i]; 283 } 284 if (zoomed.arrayMask & SPAN_FOG) { 285 for (j=0;j<m;j++) { 286 i = n - (j+skipcol) - 1; 287 zoomed.fogArray[j] = fog[i]; 288 } 289 } 290 } 291 else { 292 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 293 for (j=0;j<m;j++) { 294 i = (GLint) ((j+skipcol) * xscale); 295 if (i<0) i = n + i - 1; 296 zoomed.color.rgba[j][0] = rgb[i][0]; 297 zoomed.color.rgba[j][1] = rgb[i][1]; 298 zoomed.color.rgba[j][2] = rgb[i][2]; 299 zoomed.color.rgba[j][3] = CHAN_MAX; 300 zoomed.zArray[j] = z[i]; 301 } 302 if (zoomed.arrayMask & SPAN_FOG) { 303 for (j=0;j<m;j++) { 304 i = (GLint) ((j+skipcol) * xscale); 305 if (i<0) i = n + i - 1; 306 zoomed.fogArray[j] = fog[i]; 307 } 308 } 309 } 310 311 /* write the span */ 312 for (r=r0; r<r1; r++) { 313 zoomed.x = x + skipcol; 314 zoomed.y = r; 315 zoomed.end = m; 316 ASSERT((zoomed.interpMask & SPAN_RGBA) == 0); 317 _mesa_write_rgba_span( ctx, &zoomed, GL_BITMAP ); 318 } 319} 320 321 322 323/* 324 * As above, but write CI pixels. 325 */ 326void 327_mesa_write_zoomed_index_span( GLcontext *ctx, 328 GLuint n, GLint x, GLint y, const GLdepth z[], 329 const GLfloat *fog, 330 const GLuint indexes[], GLint y0 ) 331{ 332 GLint m; 333 GLint r0, r1, row, r; 334 GLint i, j, skipcol; 335 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); 336 struct sw_span zoomed; 337 338 SW_SPAN_RESET(zoomed); 339 INIT_SPAN(zoomed); 340 zoomed.arrayMask |= SPAN_INDEX; 341 342 /* compute width of output row */ 343 m = (GLint) ABSF( n * ctx->Pixel.ZoomX ); 344 if (m==0) { 345 return; 346 } 347 if (ctx->Pixel.ZoomX<0.0) { 348 /* adjust x coordinate for left/right mirroring */ 349 x = x - m; 350 } 351 352 /* compute which rows to draw */ 353 row = y-y0; 354 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); 355 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); 356 if (r0==r1) { 357 return; 358 } 359 else if (r1<r0) { 360 GLint rtmp = r1; 361 r1 = r0; 362 r0 = rtmp; 363 } 364 365 /* return early if r0...r1 is above or below window */ 366 if (r0<0 && r1<0) { 367 /* below window */ 368 return; 369 } 370 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) { 371 /* above window */ 372 return; 373 } 374 375 /* check if left edge is outside window */ 376 skipcol = 0; 377 if (x<0) { 378 skipcol = -x; 379 m += x; 380 } 381 /* make sure span isn't too long or short */ 382 if (m>maxwidth) { 383 m = maxwidth; 384 } 385 else if (m<=0) { 386 return; 387 } 388 389 ASSERT( m <= MAX_WIDTH ); 390 391 /* zoom the span horizontally */ 392 if (ctx->Pixel.ZoomX==-1.0F) { 393 /* n==m */ 394 for (j=0;j<m;j++) { 395 i = n - (j+skipcol) - 1; 396 zoomed.color.index[j] = indexes[i]; 397 zoomed.zArray[j] = z[i]; 398 } 399 if (fog && ctx->Fog.Enabled) { 400 for (j=0;j<m;j++) { 401 i = n - (j+skipcol) - 1; 402 zoomed.fogArray[j] = fog[i]; 403 } 404 zoomed.arrayMask |= SPAN_FOG; 405 } 406 } 407 else { 408 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 409 for (j=0;j<m;j++) { 410 i = (GLint) ((j+skipcol) * xscale); 411 if (i<0) i = n + i - 1; 412 zoomed.color.index[j] = indexes[i]; 413 zoomed.zArray[j] = z[i]; 414 } 415 if (fog && ctx->Fog.Enabled) { 416 for (j=0;j<m;j++) { 417 i = (GLint) ((j+skipcol) * xscale); 418 if (i<0) i = n + i - 1; 419 zoomed.fogArray[j] = fog[i]; 420 } 421 zoomed.arrayMask |= SPAN_FOG; 422 } 423 } 424 425 zoomed.arrayMask |= SPAN_Z; 426 427 /* write the span */ 428 for (r=r0; r<r1; r++) { 429 SAVE_SPAN(zoomed); 430 ASSERT((zoomed.interpMask & SPAN_INDEX) == 0); 431 zoomed.x = x + skipcol; 432 zoomed.y = r; 433 zoomed.end = m; 434 _mesa_write_index_span(ctx, &zoomed, GL_BITMAP); 435 RESTORE_SPAN(zoomed); 436 } 437} 438 439 440 441/* 442 * As above, but write stencil values. 443 */ 444void 445_mesa_write_zoomed_stencil_span( GLcontext *ctx, 446 GLuint n, GLint x, GLint y, 447 const GLstencil stencil[], GLint y0 ) 448{ 449 GLint m; 450 GLint r0, r1, row, r; 451 GLint i, j, skipcol; 452 GLstencil zstencil[MAX_WIDTH]; /* zoomed stencil values */ 453 GLint maxwidth = MIN2( ctx->DrawBuffer->Width, MAX_WIDTH ); 454 455 /* compute width of output row */ 456 m = (GLint) ABSF( n * ctx->Pixel.ZoomX ); 457 if (m==0) { 458 return; 459 } 460 if (ctx->Pixel.ZoomX<0.0) { 461 /* adjust x coordinate for left/right mirroring */ 462 x = x - m; 463 } 464 465 /* compute which rows to draw */ 466 row = y-y0; 467 r0 = y0 + (GLint) (row * ctx->Pixel.ZoomY); 468 r1 = y0 + (GLint) ((row+1) * ctx->Pixel.ZoomY); 469 if (r0==r1) { 470 return; 471 } 472 else if (r1<r0) { 473 GLint rtmp = r1; 474 r1 = r0; 475 r0 = rtmp; 476 } 477 478 /* return early if r0...r1 is above or below window */ 479 if (r0<0 && r1<0) { 480 /* below window */ 481 return; 482 } 483 if (r0>=ctx->DrawBuffer->Height && r1>=ctx->DrawBuffer->Height) { 484 /* above window */ 485 return; 486 } 487 488 /* check if left edge is outside window */ 489 skipcol = 0; 490 if (x<0) { 491 skipcol = -x; 492 m += x; 493 } 494 /* make sure span isn't too long or short */ 495 if (m>maxwidth) { 496 m = maxwidth; 497 } 498 else if (m<=0) { 499 return; 500 } 501 502 ASSERT( m <= MAX_WIDTH ); 503 504 /* zoom the span horizontally */ 505 if (ctx->Pixel.ZoomX==-1.0F) { 506 /* n==m */ 507 for (j=0;j<m;j++) { 508 i = n - (j+skipcol) - 1; 509 zstencil[j] = stencil[i]; 510 } 511 } 512 else { 513 GLfloat xscale = 1.0F / ctx->Pixel.ZoomX; 514 for (j=0;j<m;j++) { 515 i = (GLint) ((j+skipcol) * xscale); 516 if (i<0) i = n + i - 1; 517 zstencil[j] = stencil[i]; 518 } 519 } 520 521 /* write the span */ 522 for (r=r0; r<r1; r++) { 523 _mesa_write_stencil_span( ctx, m, x+skipcol, r, zstencil ); 524 } 525} 526