fixed pointer arithmetic error in glCopyPixels
[mesa.git] / src / mesa / main / blend.c
1 /* $Id: blend.c,v 1.34 2001/09/14 21:36:43 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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
28 #ifdef PC_HEADER
29 #include "all.h"
30 #else
31 #include "glheader.h"
32 #include "blend.h"
33 #include "colormac.h"
34 #include "context.h"
35 #include "enums.h"
36 #include "macros.h"
37 #include "mtypes.h"
38 #endif
39
40
41 void
42 _mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
43 {
44
45 GET_CURRENT_CONTEXT(ctx);
46 ASSERT_OUTSIDE_BEGIN_END(ctx);
47
48 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
49 fprintf(stderr, "glBlendFunc %s %s\n",
50 _mesa_lookup_enum_by_nr(sfactor),
51 _mesa_lookup_enum_by_nr(dfactor));
52
53 switch (sfactor) {
54 case GL_SRC_COLOR:
55 case GL_ONE_MINUS_SRC_COLOR:
56 if (!ctx->Extensions.NV_blend_square) {
57 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
58 return;
59 }
60 /* fall-through */
61 case GL_ZERO:
62 case GL_ONE:
63 case GL_DST_COLOR:
64 case GL_ONE_MINUS_DST_COLOR:
65 case GL_SRC_ALPHA:
66 case GL_ONE_MINUS_SRC_ALPHA:
67 case GL_DST_ALPHA:
68 case GL_ONE_MINUS_DST_ALPHA:
69 case GL_SRC_ALPHA_SATURATE:
70 case GL_CONSTANT_COLOR:
71 case GL_ONE_MINUS_CONSTANT_COLOR:
72 case GL_CONSTANT_ALPHA:
73 case GL_ONE_MINUS_CONSTANT_ALPHA:
74 break;
75 default:
76 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
77 return;
78 }
79
80 switch (dfactor) {
81 case GL_DST_COLOR:
82 case GL_ONE_MINUS_DST_COLOR:
83 if (!ctx->Extensions.NV_blend_square) {
84 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
85 return;
86 }
87 /* fall-through */
88 case GL_ZERO:
89 case GL_ONE:
90 case GL_SRC_COLOR:
91 case GL_ONE_MINUS_SRC_COLOR:
92 case GL_SRC_ALPHA:
93 case GL_ONE_MINUS_SRC_ALPHA:
94 case GL_DST_ALPHA:
95 case GL_ONE_MINUS_DST_ALPHA:
96 case GL_CONSTANT_COLOR:
97 case GL_ONE_MINUS_CONSTANT_COLOR:
98 case GL_CONSTANT_ALPHA:
99 case GL_ONE_MINUS_CONSTANT_ALPHA:
100 break;
101 default:
102 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
103 return;
104 }
105
106 if (ctx->Color.BlendDstRGB == dfactor &&
107 ctx->Color.BlendSrcRGB == sfactor &&
108 ctx->Color.BlendDstA == dfactor &&
109 ctx->Color.BlendSrcA == sfactor)
110 return;
111
112 FLUSH_VERTICES(ctx, _NEW_COLOR);
113 ctx->Color.BlendDstRGB = ctx->Color.BlendDstA = dfactor;
114 ctx->Color.BlendSrcRGB = ctx->Color.BlendSrcA = sfactor;
115
116 if (ctx->Driver.BlendFunc)
117 ctx->Driver.BlendFunc( ctx, sfactor, dfactor );
118 }
119
120
121 /* GL_EXT_blend_func_separate */
122 void
123 _mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
124 GLenum sfactorA, GLenum dfactorA )
125 {
126 GET_CURRENT_CONTEXT(ctx);
127 ASSERT_OUTSIDE_BEGIN_END(ctx);
128
129 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
130 fprintf(stderr, "glBlendFuncSeparate %s %s %s %s\n",
131 _mesa_lookup_enum_by_nr(sfactorRGB),
132 _mesa_lookup_enum_by_nr(dfactorRGB),
133 _mesa_lookup_enum_by_nr(sfactorA),
134 _mesa_lookup_enum_by_nr(dfactorA));
135
136 switch (sfactorRGB) {
137 case GL_SRC_COLOR:
138 case GL_ONE_MINUS_SRC_COLOR:
139 if (!ctx->Extensions.NV_blend_square) {
140 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)");
141 return;
142 }
143 /* fall-through */
144 case GL_ZERO:
145 case GL_ONE:
146 case GL_DST_COLOR:
147 case GL_ONE_MINUS_DST_COLOR:
148 case GL_SRC_ALPHA:
149 case GL_ONE_MINUS_SRC_ALPHA:
150 case GL_DST_ALPHA:
151 case GL_ONE_MINUS_DST_ALPHA:
152 case GL_SRC_ALPHA_SATURATE:
153 case GL_CONSTANT_COLOR:
154 case GL_ONE_MINUS_CONSTANT_COLOR:
155 case GL_CONSTANT_ALPHA:
156 case GL_ONE_MINUS_CONSTANT_ALPHA:
157 break;
158 default:
159 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)");
160 return;
161 }
162
163 switch (dfactorRGB) {
164 case GL_DST_COLOR:
165 case GL_ONE_MINUS_DST_COLOR:
166 if (!ctx->Extensions.NV_blend_square) {
167 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)");
168 return;
169 }
170 /* fall-through */
171 case GL_ZERO:
172 case GL_ONE:
173 case GL_SRC_COLOR:
174 case GL_ONE_MINUS_SRC_COLOR:
175 case GL_SRC_ALPHA:
176 case GL_ONE_MINUS_SRC_ALPHA:
177 case GL_DST_ALPHA:
178 case GL_ONE_MINUS_DST_ALPHA:
179 case GL_CONSTANT_COLOR:
180 case GL_ONE_MINUS_CONSTANT_COLOR:
181 case GL_CONSTANT_ALPHA:
182 case GL_ONE_MINUS_CONSTANT_ALPHA:
183 break;
184 default:
185 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)");
186 return;
187 }
188
189 switch (sfactorA) {
190 case GL_SRC_COLOR:
191 case GL_ONE_MINUS_SRC_COLOR:
192 if (!ctx->Extensions.NV_blend_square) {
193 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)");
194 return;
195 }
196 /* fall-through */
197 case GL_ZERO:
198 case GL_ONE:
199 case GL_DST_COLOR:
200 case GL_ONE_MINUS_DST_COLOR:
201 case GL_SRC_ALPHA:
202 case GL_ONE_MINUS_SRC_ALPHA:
203 case GL_DST_ALPHA:
204 case GL_ONE_MINUS_DST_ALPHA:
205 case GL_SRC_ALPHA_SATURATE:
206 case GL_CONSTANT_COLOR:
207 case GL_ONE_MINUS_CONSTANT_COLOR:
208 case GL_CONSTANT_ALPHA:
209 case GL_ONE_MINUS_CONSTANT_ALPHA:
210 break;
211 default:
212 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)");
213 return;
214 }
215
216 switch (dfactorA) {
217 case GL_DST_COLOR:
218 case GL_ONE_MINUS_DST_COLOR:
219 if (!ctx->Extensions.NV_blend_square) {
220 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)");
221 return;
222 }
223 /* fall-through */
224 case GL_ZERO:
225 case GL_ONE:
226 case GL_SRC_COLOR:
227 case GL_ONE_MINUS_SRC_COLOR:
228 case GL_SRC_ALPHA:
229 case GL_ONE_MINUS_SRC_ALPHA:
230 case GL_DST_ALPHA:
231 case GL_ONE_MINUS_DST_ALPHA:
232 case GL_CONSTANT_COLOR:
233 case GL_ONE_MINUS_CONSTANT_COLOR:
234 case GL_CONSTANT_ALPHA:
235 case GL_ONE_MINUS_CONSTANT_ALPHA:
236 break;
237 default:
238 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)" );
239 return;
240 }
241
242 if (ctx->Color.BlendSrcRGB == sfactorRGB &&
243 ctx->Color.BlendDstRGB == dfactorRGB &&
244 ctx->Color.BlendSrcA == sfactorA &&
245 ctx->Color.BlendDstA == dfactorA)
246 return;
247
248 FLUSH_VERTICES(ctx, _NEW_COLOR);
249
250 ctx->Color.BlendSrcRGB = sfactorRGB;
251 ctx->Color.BlendDstRGB = dfactorRGB;
252 ctx->Color.BlendSrcA = sfactorA;
253 ctx->Color.BlendDstA = dfactorA;
254
255 if (ctx->Driver.BlendFuncSeparate) {
256 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB,
257 sfactorA, dfactorA );
258 }
259 }
260
261
262
263 /* This is really an extension function! */
264 void
265 _mesa_BlendEquation( GLenum mode )
266 {
267 GET_CURRENT_CONTEXT(ctx);
268 ASSERT_OUTSIDE_BEGIN_END(ctx);
269
270 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
271 fprintf(stderr, "glBlendEquation %s\n",
272 _mesa_lookup_enum_by_nr(mode));
273
274 switch (mode) {
275 case GL_FUNC_ADD_EXT:
276 break;
277 case GL_MIN_EXT:
278 case GL_MAX_EXT:
279 if (!ctx->Extensions.EXT_blend_minmax &&
280 !ctx->Extensions.ARB_imaging) {
281 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
282 return;
283 }
284 break;
285 case GL_LOGIC_OP:
286 if (!ctx->Extensions.EXT_blend_logic_op) {
287 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
288 return;
289 }
290 break;
291 case GL_FUNC_SUBTRACT_EXT:
292 case GL_FUNC_REVERSE_SUBTRACT_EXT:
293 if (!ctx->Extensions.EXT_blend_subtract &&
294 !ctx->Extensions.ARB_imaging) {
295 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
296 return;
297 }
298 break;
299 default:
300 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendEquation" );
301 return;
302 }
303
304 if (ctx->Color.BlendEquation == mode)
305 return;
306
307 FLUSH_VERTICES(ctx, _NEW_COLOR);
308 ctx->Color.BlendEquation = mode;
309
310 /* This is needed to support 1.1's RGB logic ops AND
311 * 1.0's blending logicops.
312 */
313 ctx->Color.ColorLogicOpEnabled = (mode==GL_LOGIC_OP &&
314 ctx->Color.BlendEnabled);
315
316 if (ctx->Driver.BlendEquation)
317 (*ctx->Driver.BlendEquation)( ctx, mode );
318 }
319
320
321
322 void
323 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
324 {
325 GLfloat tmp[4];
326 GET_CURRENT_CONTEXT(ctx);
327 ASSERT_OUTSIDE_BEGIN_END(ctx);
328
329 tmp[0] = CLAMP( red, 0.0F, 1.0F );
330 tmp[1] = CLAMP( green, 0.0F, 1.0F );
331 tmp[2] = CLAMP( blue, 0.0F, 1.0F );
332 tmp[3] = CLAMP( alpha, 0.0F, 1.0F );
333
334 if (TEST_EQ_4V(tmp, ctx->Color.BlendColor))
335 return;
336
337 FLUSH_VERTICES(ctx, _NEW_COLOR);
338 COPY_4FV( ctx->Color.BlendColor, tmp );
339
340 if (ctx->Driver.BlendColor)
341 (*ctx->Driver.BlendColor)(ctx, tmp);
342 }
343
344
345 void
346 _mesa_AlphaFunc( GLenum func, GLclampf ref )
347 {
348 GET_CURRENT_CONTEXT(ctx);
349 GLchan cref;
350 ASSERT_OUTSIDE_BEGIN_END(ctx);
351
352 switch (func) {
353 case GL_NEVER:
354 case GL_LESS:
355 case GL_EQUAL:
356 case GL_LEQUAL:
357 case GL_GREATER:
358 case GL_NOTEQUAL:
359 case GL_GEQUAL:
360 case GL_ALWAYS:
361 /* convert float alpha ref to GLchan type */
362 UNCLAMPED_FLOAT_TO_CHAN(cref, ref);
363
364 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == cref)
365 return;
366
367 FLUSH_VERTICES(ctx, _NEW_COLOR);
368 ctx->Color.AlphaFunc = func;
369 ctx->Color.AlphaRef = cref;
370
371 if (ctx->Driver.AlphaFunc)
372 ctx->Driver.AlphaFunc(ctx, func, cref);
373 return;
374
375 default:
376 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" );
377 return;
378 }
379 }
380
381
382 void
383 _mesa_LogicOp( GLenum opcode )
384 {
385 GET_CURRENT_CONTEXT(ctx);
386 ASSERT_OUTSIDE_BEGIN_END(ctx);
387
388 switch (opcode) {
389 case GL_CLEAR:
390 case GL_SET:
391 case GL_COPY:
392 case GL_COPY_INVERTED:
393 case GL_NOOP:
394 case GL_INVERT:
395 case GL_AND:
396 case GL_NAND:
397 case GL_OR:
398 case GL_NOR:
399 case GL_XOR:
400 case GL_EQUIV:
401 case GL_AND_REVERSE:
402 case GL_AND_INVERTED:
403 case GL_OR_REVERSE:
404 case GL_OR_INVERTED:
405 break;
406 default:
407 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" );
408 return;
409 }
410
411 if (ctx->Color.LogicOp == opcode)
412 return;
413
414 FLUSH_VERTICES(ctx, _NEW_COLOR);
415 ctx->Color.LogicOp = opcode;
416
417 if (ctx->Driver.LogicOpcode)
418 ctx->Driver.LogicOpcode( ctx, opcode );
419 }
420
421
422 void
423 _mesa_IndexMask( GLuint mask )
424 {
425 GET_CURRENT_CONTEXT(ctx);
426 ASSERT_OUTSIDE_BEGIN_END(ctx);
427
428 if (ctx->Color.IndexMask == mask)
429 return;
430
431 FLUSH_VERTICES(ctx, _NEW_COLOR);
432 ctx->Color.IndexMask = mask;
433
434 if (ctx->Driver.IndexMask)
435 ctx->Driver.IndexMask( ctx, mask );
436 }
437
438
439 void
440 _mesa_ColorMask( GLboolean red, GLboolean green,
441 GLboolean blue, GLboolean alpha )
442 {
443 GET_CURRENT_CONTEXT(ctx);
444 GLubyte tmp[4];
445 ASSERT_OUTSIDE_BEGIN_END(ctx);
446
447 if (MESA_VERBOSE & VERBOSE_API)
448 fprintf(stderr, "glColorMask %d %d %d %d\n", red, green, blue, alpha);
449
450 /* Shouldn't have any information about channel depth in core mesa
451 * -- should probably store these as the native booleans:
452 */
453 tmp[RCOMP] = red ? 0xff : 0x0;
454 tmp[GCOMP] = green ? 0xff : 0x0;
455 tmp[BCOMP] = blue ? 0xff : 0x0;
456 tmp[ACOMP] = alpha ? 0xff : 0x0;
457
458 if (TEST_EQ_4UBV(tmp, ctx->Color.ColorMask))
459 return;
460
461 FLUSH_VERTICES(ctx, _NEW_COLOR);
462 COPY_4UBV(ctx->Color.ColorMask, tmp);
463
464 if (ctx->Driver.ColorMask)
465 ctx->Driver.ColorMask( ctx, red, green, blue, alpha );
466 }