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