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