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
gl_alloc_accum_buffer(GLcontext * ctx)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
gl_ClearAccum(GLcontext * ctx,GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)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
gl_Accum(GLcontext * ctx,GLenum op,GLfloat value)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 */
gl_clear_accum_buffer(GLcontext * ctx)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