1 /* $Id: accum.c,v 1.5 1997/07/24 01:24:28 brianp Exp $ */ 2 3 /* 4 * Mesa 3-D graphics library 5 * Version: 2.4 6 * Copyright (C) 1995-1997 Brian Paul 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public 19 * License along with this library; if not, write to the Free 20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 24 /* 25 * $Log: accum.c,v $ 26 * Revision 1.5 1997/07/24 01:24:28 brianp 27 * changed precompiled header symbol from PCH to PC_HEADER 28 * 29 * Revision 1.4 1997/05/28 03:23:09 brianp 30 * added precompiled header (PCH) support 31 * 32 * Revision 1.3 1997/04/30 01:54:48 brianp 33 * call gl_warning() if calling gl_Accum w/out accum buffer 34 * 35 * Revision 1.2 1996/09/15 14:19:44 brianp 36 * now use GLframebuffer and GLvisual 37 * added gl_alloc_accum_buffer() 38 * 39 * Revision 1.1 1996/09/13 01:38:16 brianp 40 * Initial revision 41 * 42 */ 43 44 45 #ifdef PC_HEADER 46 #include "all.h" 47 #else 48 #include <limits.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include "accum.h" 52 #include "context.h" 53 #include "dlist.h" 54 #include "macros.h" 55 #include "types.h" 56 #endif 57 58 59 void gl_alloc_accum_buffer( GLcontext *ctx ) 60 { 61 GLint n; 62 63 if (ctx->Buffer->Accum) { 64 free( ctx->Buffer->Accum ); 65 ctx->Buffer->Accum = NULL; 66 } 67 68 /* allocate accumulation buffer if not already present */ 69 n = ctx->Buffer->Width * ctx->Buffer->Height * 4 * sizeof(GLaccum); 70 ctx->Buffer->Accum = (GLaccum *) malloc( n ); 71 if (!ctx->Buffer->Accum) { 72 /* unable to setup accumulation buffer */ 73 gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" ); 74 } 75 } 76 77 78 79 void gl_ClearAccum( GLcontext *ctx, 80 GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha ) 81 { 82 if (INSIDE_BEGIN_END(ctx)) { 83 gl_error( ctx, GL_INVALID_OPERATION, "glAccum" ); 84 return; 85 } 86 ctx->Accum.ClearColor[0] = CLAMP( red, -1.0, 1.0 ); 87 ctx->Accum.ClearColor[1] = CLAMP( green, -1.0, 1.0 ); 88 ctx->Accum.ClearColor[2] = CLAMP( blue, -1.0, 1.0 ); 89 ctx->Accum.ClearColor[3] = CLAMP( alpha, -1.0, 1.0 ); 90 } 91 92 93 94 95 void gl_Accum( GLcontext *ctx, GLenum op, GLfloat value ) 96 { 97 GLuint xpos, ypos, width, height; 98 GLfloat acc_scale; 99 100 if (INSIDE_BEGIN_END(ctx)) { 101 gl_error( ctx, GL_INVALID_OPERATION, "glAccum" ); 102 return; 103 } 104 105 if (ctx->Visual->AccumBits==0 || !ctx->Buffer->Accum) { 106 /* No accumulation buffer! */ 107 gl_warning(ctx, "Calling glAccum() without an accumulation buffer"); 108 return; 109 } 110 111 if (sizeof(GLaccum)==1) { 112 acc_scale = 127.0; 113 } 114 else if (sizeof(GLaccum)==2) { 115 acc_scale = 32767.0; 116 } 117 else { 118 /* sizeof(GLaccum) > 2 (Cray) */ 119 acc_scale = (float) SHRT_MAX; 120 } 121 122 /* Determine region to operate upon. */ 123 if (ctx->Scissor.Enabled) { 124 xpos = ctx->Scissor.X; 125 ypos = ctx->Scissor.Y; 126 width = ctx->Scissor.Width; 127 height = ctx->Scissor.Height; 128 } 129 else { 130 /* whole window */ 131 xpos = 0; 132 ypos = 0; 133 width = ctx->Buffer->Width; 134 height = ctx->Buffer->Height; 135 } 136 137 switch (op) { 138 case GL_ADD: 139 { 140 GLaccum ival, *acc; 141 GLuint i, j; 142 143 ival = (GLaccum) (value * acc_scale); 144 for (j=0;j<height;j++) { 145 acc = ctx->Buffer->Accum 146 + (ypos * ctx->Buffer->Width + xpos) * 4; 147 for (i=0;i<width;i++) { 148 *acc += ival; acc++; /* red */ 149 *acc += ival; acc++; /* green */ 150 *acc += ival; acc++; /* blue */ 151 *acc += ival; acc++; /* alpha */ 152 } 153 ypos++; 154 } 155 } 156 break; 157 case GL_MULT: 158 { 159 GLaccum *acc; 160 GLuint i, j; 161 162 for (j=0;j<height;j++) { 163 acc = ctx->Buffer->Accum 164 + (ypos * ctx->Buffer->Width + xpos) * 4; 165 for (i=0;i<width;i++) { 166 *acc = (GLaccum) ( (GLfloat) *acc * value ); acc++; /*r*/ 167 *acc = (GLaccum) ( (GLfloat) *acc * value ); acc++; /*g*/ 168 *acc = (GLaccum) ( (GLfloat) *acc * value ); acc++; /*g*/ 169 *acc = (GLaccum) ( (GLfloat) *acc * value ); acc++; /*a*/ 170 } 171 ypos++; 172 } 173 } 174 break; 175 case GL_ACCUM: 176 { 177 GLaccum *acc; 178 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; 179 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; 180 GLfloat rscale, gscale, bscale, ascale; 181 GLuint i, j; 182 183 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.ReadBuffer ); 184 185 /* Accumulate */ 186 rscale = value * acc_scale * ctx->Visual->InvRedScale; 187 gscale = value * acc_scale * ctx->Visual->InvGreenScale; 188 bscale = value * acc_scale * ctx->Visual->InvBlueScale; 189 ascale = value * acc_scale * ctx->Visual->InvAlphaScale; 190 for (j=0;j<height;j++) { 191 (*ctx->Driver.ReadColorSpan)( ctx, width, xpos, ypos, 192 red, green, blue, alpha); 193 acc = ctx->Buffer->Accum 194 + (ypos * ctx->Buffer->Width + xpos) * 4; 195 for (i=0;i<width;i++) { 196 *acc += (GLaccum) ( (GLfloat) red[i] * rscale ); acc++; 197 *acc += (GLaccum) ( (GLfloat) green[i] * gscale ); acc++; 198 *acc += (GLaccum) ( (GLfloat) blue[i] * bscale ); acc++; 199 *acc += (GLaccum) ( (GLfloat) alpha[i] * ascale ); acc++; 200 } 201 ypos++; 202 } 203 204 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DrawBuffer ); 205 } 206 break; 207 case GL_LOAD: 208 { 209 GLaccum *acc; 210 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; 211 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; 212 GLfloat rscale, gscale, bscale, ascale; 213 GLuint i, j; 214 215 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.ReadBuffer ); 216 217 /* Load accumulation buffer */ 218 rscale = value * acc_scale * ctx->Visual->InvRedScale; 219 gscale = value * acc_scale * ctx->Visual->InvGreenScale; 220 bscale = value * acc_scale * ctx->Visual->InvBlueScale; 221 ascale = value * acc_scale * ctx->Visual->InvAlphaScale; 222 for (j=0;j<height;j++) { 223 (*ctx->Driver.ReadColorSpan)( ctx, width, xpos, ypos, 224 red, green, blue, alpha); 225 acc = ctx->Buffer->Accum 226 + (ypos * ctx->Buffer->Width + xpos) * 4; 227 for (i=0;i<width;i++) { 228 *acc++ = (GLaccum) ( (GLfloat) red[i] * rscale ); 229 *acc++ = (GLaccum) ( (GLfloat) green[i] * gscale ); 230 *acc++ = (GLaccum) ( (GLfloat) blue[i] * bscale ); 231 *acc++ = (GLaccum) ( (GLfloat) alpha[i] * ascale ); 232 } 233 ypos++; 234 } 235 236 (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DrawBuffer ); 237 } 238 break; 239 case GL_RETURN: 240 { 241 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; 242 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; 243 GLaccum *acc; 244 GLfloat rscale, gscale, bscale, ascale; 245 GLint rmax, gmax, bmax, amax; 246 GLuint i, j; 247 248 rscale = value / acc_scale * ctx->Visual->RedScale; 249 gscale = value / acc_scale * ctx->Visual->GreenScale; 250 bscale = value / acc_scale * ctx->Visual->BlueScale; 251 ascale = value / acc_scale * ctx->Visual->AlphaScale; 252 rmax = (GLint) ctx->Visual->RedScale; 253 gmax = (GLint) ctx->Visual->GreenScale; 254 bmax = (GLint) ctx->Visual->BlueScale; 255 amax = (GLint) ctx->Visual->AlphaScale; 256 for (j=0;j<height;j++) { 257 acc = ctx->Buffer->Accum 258 + (ypos * ctx->Buffer->Width + xpos) * 4; 259 for (i=0;i<width;i++) { 260 GLint r, g, b, a; 261 r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F ); 262 g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F ); 263 b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F ); 264 a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F ); 265 red[i] = CLAMP( r, 0, rmax ); 266 green[i] = CLAMP( g, 0, gmax ); 267 blue[i] = CLAMP( b, 0, bmax ); 268 alpha[i] = CLAMP( a, 0, amax ); 269 } 270 (*ctx->Driver.WriteColorSpan)( ctx, width, xpos, ypos, 271 red, green, blue, alpha, NULL ); 272 ypos++; 273 } 274 } 275 break; 276 default: 277 gl_error( ctx, GL_INVALID_ENUM, "glAccum" ); 278 } 279 } 280 281 282 283 284 /* 285 * Clear the accumulation Buffer-> 286 */ 287 void gl_clear_accum_buffer( GLcontext *ctx ) 288 { 289 GLuint buffersize; 290 GLfloat acc_scale; 291 292 if (ctx->Visual->AccumBits==0) { 293 /* No accumulation buffer! */ 294 return; 295 } 296 297 if (sizeof(GLaccum)==1) { 298 acc_scale = 127.0; 299 } 300 else if (sizeof(GLaccum)==2) { 301 acc_scale = 32767.0; 302 } 303 else { 304 /* sizeof(GLaccum) > 2 (Cray) */ 305 acc_scale = (float) SHRT_MAX; 306 } 307 308 /* number of pixels */ 309 buffersize = ctx->Buffer->Width * ctx->Buffer->Height; 310 311 if (!ctx->Buffer->Accum) { 312 /* try to alloc accumulation buffer */ 313 ctx->Buffer->Accum = (GLaccum *) 314 malloc( buffersize * 4 * sizeof(GLaccum) ); 315 } 316 317 if (ctx->Buffer->Accum) { 318 if (ctx->Scissor.Enabled) { 319 /* Limit clear to scissor box */ 320 GLaccum r, g, b, a; 321 GLint i, j; 322 GLint width, height; 323 GLaccum *row; 324 r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale); 325 g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale); 326 b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale); 327 a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale); 328 /* size of region to clear */ 329 width = 4 * (ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1); 330 height = ctx->Buffer->Ymax - ctx->Buffer->Ymin + 1; 331 /* ptr to first element to clear */ 332 row = ctx->Buffer->Accum 333 + 4 * (ctx->Buffer->Ymin * ctx->Buffer->Width 334 + ctx->Buffer->Xmin); 335 for (j=0;j<height;j++) { 336 for (i=0;i<width;i+=4) { 337 row[i+0] = r; 338 row[i+1] = g; 339 row[i+2] = b; 340 row[i+3] = a; 341 } 342 row += 4 * ctx->Buffer->Width; 343 } 344 } 345 else { 346 /* clear whole buffer */ 347 if (ctx->Accum.ClearColor[0]==0.0 && 348 ctx->Accum.ClearColor[1]==0.0 && 349 ctx->Accum.ClearColor[2]==0.0 && 350 ctx->Accum.ClearColor[3]==0.0) { 351 /* Black */ 352 MEMSET( ctx->Buffer->Accum, 0, buffersize * 4 * sizeof(GLaccum) ); 353 } 354 else { 355 /* Not black */ 356 GLaccum *acc, r, g, b, a; 357 GLuint i; 358 359 acc = ctx->Buffer->Accum; 360 r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale); 361 g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale); 362 b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale); 363 a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale); 364 for (i=0;i<buffersize;i++) { 365 *acc++ = r; 366 *acc++ = g; 367 *acc++ = b; 368 *acc++ = a; 369 } 370 } 371 } 372 } 373 } 374