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