blend.c revision ead285a9266bb5f80e68de122490a6afb88df6f3
1/* $Id: blend.c,v 1.13 2000/02/24 22:04:03 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.3
6 *
7 * Copyright (C) 1999  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
29#ifdef PC_HEADER
30#include "all.h"
31#else
32#include "glheader.h"
33#include "alphabuf.h"
34#include "blend.h"
35#include "context.h"
36#include "enums.h"
37#include "macros.h"
38#include "pb.h"
39#include "span.h"
40#include "types.h"
41#endif
42
43
44void
45_mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
46{
47   GET_CURRENT_CONTEXT(ctx);
48   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFunc");
49
50   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
51      fprintf(stderr, "glBlendFunc %s %s\n",
52	      gl_lookup_enum_by_nr(sfactor),
53	      gl_lookup_enum_by_nr(dfactor));
54
55   switch (sfactor) {
56      case GL_ZERO:
57      case GL_ONE:
58      case GL_DST_COLOR:
59      case GL_ONE_MINUS_DST_COLOR:
60      case GL_SRC_ALPHA:
61      case GL_ONE_MINUS_SRC_ALPHA:
62      case GL_DST_ALPHA:
63      case GL_ONE_MINUS_DST_ALPHA:
64      case GL_SRC_ALPHA_SATURATE:
65      case GL_CONSTANT_COLOR:
66      case GL_ONE_MINUS_CONSTANT_COLOR:
67      case GL_CONSTANT_ALPHA:
68      case GL_ONE_MINUS_CONSTANT_ALPHA:
69         ctx->Color.BlendSrcRGB = ctx->Color.BlendSrcA = sfactor;
70         break;
71      default:
72         gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
73         return;
74   }
75
76   switch (dfactor) {
77      case GL_ZERO:
78      case GL_ONE:
79      case GL_SRC_COLOR:
80      case GL_ONE_MINUS_SRC_COLOR:
81      case GL_SRC_ALPHA:
82      case GL_ONE_MINUS_SRC_ALPHA:
83      case GL_DST_ALPHA:
84      case GL_ONE_MINUS_DST_ALPHA:
85      case GL_CONSTANT_COLOR:
86      case GL_ONE_MINUS_CONSTANT_COLOR:
87      case GL_CONSTANT_ALPHA:
88      case GL_ONE_MINUS_CONSTANT_ALPHA:
89         ctx->Color.BlendDstRGB = ctx->Color.BlendDstA = dfactor;
90         break;
91      default:
92         gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
93         return;
94   }
95
96   if (ctx->Driver.BlendFunc) {
97      (*ctx->Driver.BlendFunc)( ctx, sfactor, dfactor );
98   }
99
100   ctx->Color.BlendFunc = NULL;
101   ctx->NewState |= NEW_RASTER_OPS;
102}
103
104
105/* GL_EXT_blend_func_separate */
106void
107_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
108                            GLenum sfactorA, GLenum dfactorA )
109{
110   GET_CURRENT_CONTEXT(ctx);
111   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFuncSeparate");
112
113   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
114      fprintf(stderr, "glBlendFuncSeperate %s %s %s %s\n",
115	      gl_lookup_enum_by_nr(sfactorRGB),
116	      gl_lookup_enum_by_nr(dfactorRGB),
117	      gl_lookup_enum_by_nr(sfactorA),
118	      gl_lookup_enum_by_nr(dfactorA));
119
120   switch (sfactorRGB) {
121      case GL_ZERO:
122      case GL_ONE:
123      case GL_DST_COLOR:
124      case GL_ONE_MINUS_DST_COLOR:
125      case GL_SRC_ALPHA:
126      case GL_ONE_MINUS_SRC_ALPHA:
127      case GL_DST_ALPHA:
128      case GL_ONE_MINUS_DST_ALPHA:
129      case GL_SRC_ALPHA_SATURATE:
130      case GL_CONSTANT_COLOR:
131      case GL_ONE_MINUS_CONSTANT_COLOR:
132      case GL_CONSTANT_ALPHA:
133      case GL_ONE_MINUS_CONSTANT_ALPHA:
134         ctx->Color.BlendSrcRGB = sfactorRGB;
135         break;
136      default:
137         gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)" );
138         return;
139   }
140
141   switch (dfactorRGB) {
142      case GL_ZERO:
143      case GL_ONE:
144      case GL_SRC_COLOR:
145      case GL_ONE_MINUS_SRC_COLOR:
146      case GL_SRC_ALPHA:
147      case GL_ONE_MINUS_SRC_ALPHA:
148      case GL_DST_ALPHA:
149      case GL_ONE_MINUS_DST_ALPHA:
150      case GL_CONSTANT_COLOR:
151      case GL_ONE_MINUS_CONSTANT_COLOR:
152      case GL_CONSTANT_ALPHA:
153      case GL_ONE_MINUS_CONSTANT_ALPHA:
154         ctx->Color.BlendDstRGB = dfactorRGB;
155         break;
156      default:
157         gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)" );
158         return;
159   }
160
161   switch (sfactorA) {
162      case GL_ZERO:
163      case GL_ONE:
164      case GL_DST_COLOR:
165      case GL_ONE_MINUS_DST_COLOR:
166      case GL_SRC_ALPHA:
167      case GL_ONE_MINUS_SRC_ALPHA:
168      case GL_DST_ALPHA:
169      case GL_ONE_MINUS_DST_ALPHA:
170      case GL_SRC_ALPHA_SATURATE:
171      case GL_CONSTANT_COLOR:
172      case GL_ONE_MINUS_CONSTANT_COLOR:
173      case GL_CONSTANT_ALPHA:
174      case GL_ONE_MINUS_CONSTANT_ALPHA:
175         ctx->Color.BlendSrcA = sfactorA;
176         break;
177      default:
178         gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)" );
179         return;
180   }
181
182   switch (dfactorA) {
183      case GL_ZERO:
184      case GL_ONE:
185      case GL_SRC_COLOR:
186      case GL_ONE_MINUS_SRC_COLOR:
187      case GL_SRC_ALPHA:
188      case GL_ONE_MINUS_SRC_ALPHA:
189      case GL_DST_ALPHA:
190      case GL_ONE_MINUS_DST_ALPHA:
191      case GL_CONSTANT_COLOR:
192      case GL_ONE_MINUS_CONSTANT_COLOR:
193      case GL_CONSTANT_ALPHA:
194      case GL_ONE_MINUS_CONSTANT_ALPHA:
195         ctx->Color.BlendDstA = dfactorA;
196         break;
197      default:
198         gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)" );
199         return;
200   }
201
202   ctx->Color.BlendFunc = NULL;
203   ctx->NewState |= NEW_RASTER_OPS;
204
205   if (ctx->Driver.BlendFuncSeparate) {
206      (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB,
207					sfactorA, dfactorA );
208   }
209}
210
211
212
213/* This is really an extension function! */
214void
215_mesa_BlendEquation( GLenum mode )
216{
217   GET_CURRENT_CONTEXT(ctx);
218   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendEquation");
219
220   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
221      fprintf(stderr, "glBlendEquation %s\n",
222	      gl_lookup_enum_by_nr(mode));
223
224
225   switch (mode) {
226      case GL_MIN_EXT:
227      case GL_MAX_EXT:
228      case GL_LOGIC_OP:
229      case GL_FUNC_ADD_EXT:
230      case GL_FUNC_SUBTRACT_EXT:
231      case GL_FUNC_REVERSE_SUBTRACT_EXT:
232         ctx->Color.BlendEquation = mode;
233         break;
234      default:
235         gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" );
236         return;
237   }
238
239   /* This is needed to support 1.1's RGB logic ops AND
240    * 1.0's blending logicops.
241    */
242   if (mode==GL_LOGIC_OP && ctx->Color.BlendEnabled) {
243      ctx->Color.ColorLogicOpEnabled = GL_TRUE;
244   }
245   else {
246      ctx->Color.ColorLogicOpEnabled = GL_FALSE;
247   }
248
249   ctx->Color.BlendFunc = NULL;
250   ctx->NewState |= NEW_RASTER_OPS;
251
252   if (ctx->Driver.BlendEquation)
253      ctx->Driver.BlendEquation( ctx, mode );
254}
255
256
257
258void
259_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
260{
261   GET_CURRENT_CONTEXT(ctx);
262   ctx->Color.BlendColor[0] = CLAMP( red,   0.0F, 1.0F );
263   ctx->Color.BlendColor[1] = CLAMP( green, 0.0F, 1.0F );
264   ctx->Color.BlendColor[2] = CLAMP( blue,  0.0F, 1.0F );
265   ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0F, 1.0F );
266}
267
268#ifdef USE_MMX_ASM
269#define _BLENDAPI _ASMAPI
270#else
271#define _BLENDAPI
272#endif
273
274/*
275 * Common transparency blending mode.
276 */
277static void _BLENDAPI
278blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
279                    GLubyte rgba[][4], CONST GLubyte dest[][4] )
280{
281   GLuint i;
282   ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
283   ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
284   ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
285   (void) ctx;
286
287   for (i=0;i<n;i++) {
288      if (mask[i]) {
289         const GLint t = rgba[i][ACOMP];  /* t in [0,255] */
290         if (t == 0) {
291            /* 0% alpha */
292            rgba[i][RCOMP] = dest[i][RCOMP];
293            rgba[i][GCOMP] = dest[i][GCOMP];
294            rgba[i][BCOMP] = dest[i][BCOMP];
295            rgba[i][ACOMP] = dest[i][ACOMP];
296         }
297         else if (t == CHAN_MAX) {
298            /* 100% alpha, no-op */
299         }
300         else {
301            const GLint s = CHAN_MAX - t;
302            const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) >> 8;
303            const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) >> 8;
304            const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) >> 8;
305            const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) >> 8;
306            ASSERT(r <= CHAN_MAX);
307            ASSERT(g <= CHAN_MAX);
308            ASSERT(b <= CHAN_MAX);
309            ASSERT(a <= CHAN_MAX);
310            rgba[i][RCOMP] = (GLubyte) r;
311            rgba[i][GCOMP] = (GLubyte) g;
312            rgba[i][BCOMP] = (GLubyte) b;
313            rgba[i][ACOMP] = (GLubyte) a;
314         }
315      }
316   }
317}
318
319
320
321/*
322 * Add src and dest.
323 */
324static void _BLENDAPI
325blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
326           GLubyte rgba[][4], CONST GLubyte dest[][4] )
327{
328   GLuint i;
329   ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
330   ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
331   ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
332   (void) ctx;
333
334   for (i=0;i<n;i++) {
335      if (mask[i]) {
336         GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
337         GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
338         GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
339         GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
340         rgba[i][RCOMP] = (GLubyte) MIN2( r, CHAN_MAX );
341         rgba[i][GCOMP] = (GLubyte) MIN2( g, CHAN_MAX );
342         rgba[i][BCOMP] = (GLubyte) MIN2( b, CHAN_MAX );
343         rgba[i][ACOMP] = (GLubyte) MIN2( a, CHAN_MAX );
344      }
345   }
346}
347
348
349
350/*
351 * Blend min function  (for GL_EXT_blend_minmax)
352 */
353static void _BLENDAPI
354blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
355           GLubyte rgba[][4], CONST GLubyte dest[][4] )
356{
357   GLuint i;
358   ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
359   (void) ctx;
360
361   for (i=0;i<n;i++) {
362      if (mask[i]) {
363         rgba[i][RCOMP] = (GLubyte) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
364         rgba[i][GCOMP] = (GLubyte) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
365         rgba[i][BCOMP] = (GLubyte) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
366         rgba[i][ACOMP] = (GLubyte) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
367      }
368   }
369}
370
371
372
373/*
374 * Blend max function  (for GL_EXT_blend_minmax)
375 */
376static void _BLENDAPI
377blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
378           GLubyte rgba[][4], CONST GLubyte dest[][4] )
379{
380   GLuint i;
381   ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
382   (void) ctx;
383
384   for (i=0;i<n;i++) {
385      if (mask[i]) {
386         rgba[i][RCOMP] = (GLubyte) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
387         rgba[i][GCOMP] = (GLubyte) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
388         rgba[i][BCOMP] = (GLubyte) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
389         rgba[i][ACOMP] = (GLubyte) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
390      }
391   }
392}
393
394
395
396/*
397 * Modulate:  result = src * dest
398 */
399static void _BLENDAPI
400blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
401                GLubyte rgba[][4], CONST GLubyte dest[][4] )
402{
403   GLuint i;
404   (void) ctx;
405
406   for (i=0;i<n;i++) {
407      if (mask[i]) {
408         GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8;
409         GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8;
410         GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8;
411         GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8;
412         rgba[i][RCOMP] = (GLubyte) r;
413         rgba[i][GCOMP] = (GLubyte) g;
414         rgba[i][BCOMP] = (GLubyte) b;
415         rgba[i][ACOMP] = (GLubyte) a;
416      }
417   }
418}
419
420
421
422/*
423 * General case blend pixels.
424 * Input:  n - number of pixels
425 *         mask - the usual write mask
426 * In/Out:  rgba - the incoming and modified pixels
427 * Input:  dest - the pixels from the dest color buffer
428 */
429static void _BLENDAPI
430blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
431               GLubyte rgba[][4], CONST GLubyte dest[][4] )
432{
433   GLfloat rscale = 1.0F / CHAN_MAXF;
434   GLfloat gscale = 1.0F / CHAN_MAXF;
435   GLfloat bscale = 1.0F / CHAN_MAXF;
436   GLfloat ascale = 1.0F / CHAN_MAXF;
437   GLuint i;
438
439   for (i=0;i<n;i++) {
440      if (mask[i]) {
441         GLint Rs, Gs, Bs, As;  /* Source colors */
442         GLint Rd, Gd, Bd, Ad;  /* Dest colors */
443         GLfloat sR, sG, sB, sA;  /* Source scaling */
444         GLfloat dR, dG, dB, dA;  /* Dest scaling */
445         GLfloat r, g, b, a;
446
447         /* Source Color */
448         Rs = rgba[i][RCOMP];
449         Gs = rgba[i][GCOMP];
450         Bs = rgba[i][BCOMP];
451         As = rgba[i][ACOMP];
452
453         /* Frame buffer color */
454         Rd = dest[i][RCOMP];
455         Gd = dest[i][GCOMP];
456         Bd = dest[i][BCOMP];
457         Ad = dest[i][ACOMP];
458
459         /* Source RGB factor */
460         switch (ctx->Color.BlendSrcRGB) {
461            case GL_ZERO:
462               sR = sG = sB = 0.0F;
463               break;
464            case GL_ONE:
465               sR = sG = sB = 1.0F;
466               break;
467            case GL_DST_COLOR:
468               sR = (GLfloat) Rd * rscale;
469               sG = (GLfloat) Gd * gscale;
470               sB = (GLfloat) Bd * bscale;
471               break;
472            case GL_ONE_MINUS_DST_COLOR:
473               sR = 1.0F - (GLfloat) Rd * rscale;
474               sG = 1.0F - (GLfloat) Gd * gscale;
475               sB = 1.0F - (GLfloat) Bd * bscale;
476               break;
477            case GL_SRC_ALPHA:
478               sR = sG = sB = (GLfloat) As * ascale;
479               break;
480            case GL_ONE_MINUS_SRC_ALPHA:
481               sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
482               break;
483            case GL_DST_ALPHA:
484               sR = sG = sB = (GLfloat) Ad * ascale;
485               break;
486            case GL_ONE_MINUS_DST_ALPHA:
487               sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
488               break;
489            case GL_SRC_ALPHA_SATURATE:
490               if (As < CHAN_MAX - Ad) {
491                  sR = sG = sB = (GLfloat) As * ascale;
492               }
493               else {
494                  sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
495               }
496               break;
497            case GL_CONSTANT_COLOR:
498               sR = ctx->Color.BlendColor[0];
499               sG = ctx->Color.BlendColor[1];
500               sB = ctx->Color.BlendColor[2];
501               break;
502            case GL_ONE_MINUS_CONSTANT_COLOR:
503               sR = 1.0F - ctx->Color.BlendColor[0];
504               sG = 1.0F - ctx->Color.BlendColor[1];
505               sB = 1.0F - ctx->Color.BlendColor[2];
506               break;
507            case GL_CONSTANT_ALPHA:
508               sR = sG = sB = ctx->Color.BlendColor[3];
509               break;
510            case GL_ONE_MINUS_CONSTANT_ALPHA:
511               sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
512               break;
513            default:
514               /* this should never happen */
515               gl_problem(ctx, "Bad blend source RGB factor in do_blend");
516	       return;
517         }
518
519         /* Source Alpha factor */
520         switch (ctx->Color.BlendSrcA) {
521            case GL_ZERO:
522               sA = 0.0F;
523               break;
524            case GL_ONE:
525               sA = 1.0F;
526               break;
527            case GL_DST_COLOR:
528               sA = (GLfloat) Ad * ascale;
529               break;
530            case GL_ONE_MINUS_DST_COLOR:
531               sA = 1.0F - (GLfloat) Ad * ascale;
532               break;
533            case GL_SRC_ALPHA:
534               sA = (GLfloat) As * ascale;
535               break;
536            case GL_ONE_MINUS_SRC_ALPHA:
537               sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
538               break;
539            case GL_DST_ALPHA:
540               sA =(GLfloat) Ad * ascale;
541               break;
542            case GL_ONE_MINUS_DST_ALPHA:
543               sA = 1.0F - (GLfloat) Ad * ascale;
544               break;
545            case GL_SRC_ALPHA_SATURATE:
546               sA = 1.0;
547               break;
548            case GL_CONSTANT_COLOR:
549               sA = ctx->Color.BlendColor[3];
550               break;
551            case GL_ONE_MINUS_CONSTANT_COLOR:
552               sA = 1.0F - ctx->Color.BlendColor[3];
553               break;
554            case GL_CONSTANT_ALPHA:
555               sA = ctx->Color.BlendColor[3];
556               break;
557            case GL_ONE_MINUS_CONSTANT_ALPHA:
558               sA = 1.0F - ctx->Color.BlendColor[3];
559               break;
560            default:
561               /* this should never happen */
562               sA = 0.0F;
563               gl_problem(ctx, "Bad blend source A factor in do_blend");
564         }
565
566         /* Dest RGB factor */
567         switch (ctx->Color.BlendDstRGB) {
568            case GL_ZERO:
569               dR = dG = dB = 0.0F;
570               break;
571            case GL_ONE:
572               dR = dG = dB = 1.0F;
573               break;
574            case GL_SRC_COLOR:
575               dR = (GLfloat) Rs * rscale;
576               dG = (GLfloat) Gs * gscale;
577               dB = (GLfloat) Bs * bscale;
578               break;
579            case GL_ONE_MINUS_SRC_COLOR:
580               dR = 1.0F - (GLfloat) Rs * rscale;
581               dG = 1.0F - (GLfloat) Gs * gscale;
582               dB = 1.0F - (GLfloat) Bs * bscale;
583               break;
584            case GL_SRC_ALPHA:
585               dR = dG = dB = (GLfloat) As * ascale;
586               break;
587            case GL_ONE_MINUS_SRC_ALPHA:
588               dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
589               break;
590            case GL_DST_ALPHA:
591               dR = dG = dB = (GLfloat) Ad * ascale;
592               break;
593            case GL_ONE_MINUS_DST_ALPHA:
594               dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
595               break;
596            case GL_CONSTANT_COLOR:
597               dR = ctx->Color.BlendColor[0];
598               dG = ctx->Color.BlendColor[1];
599               dB = ctx->Color.BlendColor[2];
600               break;
601            case GL_ONE_MINUS_CONSTANT_COLOR:
602               dR = 1.0F - ctx->Color.BlendColor[0];
603               dG = 1.0F - ctx->Color.BlendColor[1];
604               dB = 1.0F - ctx->Color.BlendColor[2];
605               break;
606            case GL_CONSTANT_ALPHA:
607               dR = dG = dB = ctx->Color.BlendColor[3];
608               break;
609            case GL_ONE_MINUS_CONSTANT_ALPHA:
610               dR = dG = dB = 1.0F - ctx->Color.BlendColor[3] * ascale;
611               break;
612            default:
613               /* this should never happen */
614               dR = dG = dB = 0.0F;
615               gl_problem(ctx, "Bad blend dest RGB factor in do_blend");
616         }
617
618         /* Dest Alpha factor */
619         switch (ctx->Color.BlendDstA) {
620            case GL_ZERO:
621               dA = 0.0F;
622               break;
623            case GL_ONE:
624               dA = 1.0F;
625               break;
626            case GL_SRC_COLOR:
627               dA = (GLfloat) As * ascale;
628               break;
629            case GL_ONE_MINUS_SRC_COLOR:
630               dA = 1.0F - (GLfloat) As * ascale;
631               break;
632            case GL_SRC_ALPHA:
633               dA = (GLfloat) As * ascale;
634               break;
635            case GL_ONE_MINUS_SRC_ALPHA:
636               dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
637               break;
638            case GL_DST_ALPHA:
639               dA = (GLfloat) Ad * ascale;
640               break;
641            case GL_ONE_MINUS_DST_ALPHA:
642               dA = 1.0F - (GLfloat) Ad * ascale;
643               break;
644            case GL_CONSTANT_COLOR:
645               dA = ctx->Color.BlendColor[3];
646               break;
647            case GL_ONE_MINUS_CONSTANT_COLOR:
648               dA = 1.0F - ctx->Color.BlendColor[3];
649               break;
650            case GL_CONSTANT_ALPHA:
651               dA = ctx->Color.BlendColor[3];
652               break;
653            case GL_ONE_MINUS_CONSTANT_ALPHA:
654               dA = 1.0F - ctx->Color.BlendColor[3] * ascale;
655               break;
656            default:
657               /* this should never happen */
658               dA = 0.0F;
659               gl_problem(ctx, "Bad blend dest A factor in do_blend");
660	       return;
661         }
662
663         /* Due to round-off problems we have to clamp against zero. */
664         /* Optimization: we don't have to do this for all src & dst factors */
665         if (dA < 0.0F)  dA = 0.0F;
666         if (dR < 0.0F)  dR = 0.0F;
667         if (dG < 0.0F)  dG = 0.0F;
668         if (dB < 0.0F)  dB = 0.0F;
669         if (sA < 0.0F)  sA = 0.0F;
670         if (sR < 0.0F)  sR = 0.0F;
671         if (sG < 0.0F)  sG = 0.0F;
672         if (sB < 0.0F)  sB = 0.0F;
673
674         ASSERT( sR <= 1.0 );
675         ASSERT( sG <= 1.0 );
676         ASSERT( sB <= 1.0 );
677         ASSERT( sA <= 1.0 );
678         ASSERT( dR <= 1.0 );
679         ASSERT( dG <= 1.0 );
680         ASSERT( dB <= 1.0 );
681         ASSERT( dA <= 1.0 );
682
683         /* compute blended color */
684         if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
685            r = Rs * sR + Rd * dR;
686            g = Gs * sG + Gd * dG;
687            b = Bs * sB + Bd * dB;
688            a = As * sA + Ad * dA;
689         }
690         else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
691            r = Rs * sR - Rd * dR;
692            g = Gs * sG - Gd * dG;
693            b = Bs * sB - Bd * dB;
694            a = As * sA - Ad * dA;
695         }
696         else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
697            r = Rd * dR - Rs * sR;
698            g = Gd * dG - Gs * sG;
699            b = Bd * dB - Bs * sB;
700            a = Ad * dA - As * sA;
701         }
702         else {
703            /* should never get here */
704            r = g = b = a = 0.0F;  /* silence uninitialized var warning */
705            gl_problem(ctx, "unexpected BlendEquation in blend_general()");
706         }
707
708         /* final clamping */
709         rgba[i][RCOMP] = (GLubyte) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
710         rgba[i][GCOMP] = (GLubyte) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
711         rgba[i][BCOMP] = (GLubyte) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
712         rgba[i][ACOMP] = (GLubyte) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
713      }
714   }
715}
716
717
718
719#if defined(USE_MMX_ASM)
720#include "X86/mmx.h"
721#include "X86/common_x86asm.h"
722#endif
723
724
725/*
726 * Analyze current blending parameters to pick fastest blending function.
727 * Result: the ctx->Color.BlendFunc pointer is updated.
728 */
729static void set_blend_function( GLcontext *ctx )
730{
731   const GLenum eq = ctx->Color.BlendEquation;
732   const GLenum srcRGB = ctx->Color.BlendSrcRGB;
733   const GLenum dstRGB = ctx->Color.BlendDstRGB;
734   const GLenum srcA = ctx->Color.BlendSrcA;
735   const GLenum dstA = ctx->Color.BlendDstA;
736
737#if defined(USE_MMX_ASM)
738   /* Hmm.  A table here would have 12^4 == way too many entries.
739    * Provide a hook for MMX instead.
740    */
741   if (gl_x86_cpu_features & GL_CPU_MMX) {
742      gl_mmx_set_blend_function (ctx);
743   }
744   else
745#endif
746   if (srcRGB != srcA || dstRGB != dstA) {
747      ctx->Color.BlendFunc = blend_general;
748   }
749   else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
750       && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
751      ctx->Color.BlendFunc = blend_transparency;
752   }
753   else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
754      ctx->Color.BlendFunc = blend_add;
755   }
756   else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
757             && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
758            ||
759            ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
760             && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
761      ctx->Color.BlendFunc = blend_modulate;
762   }
763   else if (eq==GL_MIN_EXT) {
764      ctx->Color.BlendFunc = blend_min;
765   }
766   else if (eq==GL_MAX_EXT) {
767      ctx->Color.BlendFunc = blend_max;
768   }
769   else {
770      ctx->Color.BlendFunc = blend_general;
771   }
772}
773
774
775
776/*
777 * Apply the blending operator to a span of pixels.
778 * Input:  n - number of pixels in span
779 *         x, y - location of leftmost pixel in span in window coords.
780 *         mask - boolean mask indicating which pixels to blend.
781 * In/Out:  rgba - pixel values
782 */
783void
784_mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
785                  GLubyte rgba[][4], const GLubyte mask[] )
786{
787   GLubyte dest[MAX_WIDTH][4];
788
789   /* Check if device driver can do the work */
790   if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) {
791      return;
792   }
793
794   /* Read span of current frame buffer pixels */
795   gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
796
797   if (!ctx->Color.BlendFunc)
798      set_blend_function(ctx);
799
800   (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLubyte (*)[4])dest );
801}
802
803
804
805
806
807/*
808 * Apply the blending operator to an array of pixels.
809 * Input:  n - number of pixels in span
810 *         x, y - array of pixel locations
811 *         mask - boolean mask indicating which pixels to blend.
812 * In/Out:  rgba - pixel values
813 */
814void
815_mesa_blend_pixels( GLcontext *ctx,
816                    GLuint n, const GLint x[], const GLint y[],
817                    GLubyte rgba[][4], const GLubyte mask[] )
818{
819   GLubyte dest[PB_SIZE][4];
820
821   /* Check if device driver can do the work */
822   if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) {
823      return;
824   }
825
826   /* Read pixels from current color buffer */
827   (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
828   if (ctx->RasterMask & ALPHABUF_BIT) {
829      gl_read_alpha_pixels( ctx, n, x, y, dest, mask );
830   }
831
832   if (!ctx->Color.BlendFunc)
833      set_blend_function(ctx);
834
835   (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLubyte (*)[4])dest );
836}
837