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