blend.c revision 1b258989462e907e45abbdf8743b0a75f22c02b3
1/* $Id: blend.c,v 1.33 2001/06/18 17:26:08 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
41void
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 */
122void
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! */
264void
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
322void
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.0, 1.0 );
330   tmp[1] = CLAMP( green, 0.0, 1.0 );
331   tmp[2] = CLAMP( blue,  0.0, 1.0 );
332   tmp[3] = CLAMP( alpha, 0.0, 1.0 );
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
345void
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
382void
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
422void
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
439void
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}
467