home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / mesa / src / blend.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-31  |  13.9 KB  |  497 lines

  1. /* $Id: blend.c,v 1.9 1997/07/24 01:24:45 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: blend.c,v $
  26.  * Revision 1.9  1997/07/24 01:24:45  brianp
  27.  * changed precompiled header symbol from PCH to PC_HEADER
  28.  *
  29.  * Revision 1.8  1997/05/28 03:23:48  brianp
  30.  * added precompiled header (PCH) support
  31.  *
  32.  * Revision 1.7  1997/04/20 19:51:57  brianp
  33.  * replaced abort() with gl_problem()
  34.  *
  35.  * Revision 1.6  1997/02/15 18:27:56  brianp
  36.  * fixed a few error messages
  37.  *
  38.  * Revision 1.5  1997/01/28 22:17:19  brianp
  39.  * moved logic op blending into logic.c
  40.  *
  41.  * Revision 1.4  1997/01/04 00:13:11  brianp
  42.  * was using ! instead of ~ to invert pixel bits (ugh!)
  43.  *
  44.  * Revision 1.3  1996/09/19 00:53:31  brianp
  45.  * added missing returns after some gl_error() calls
  46.  *
  47.  * Revision 1.2  1996/09/15 14:18:10  brianp
  48.  * now use GLframebuffer and GLvisual
  49.  *
  50.  * Revision 1.1  1996/09/13 01:38:16  brianp
  51.  * Initial revision
  52.  *
  53.  */
  54.  
  55.  
  56. #ifdef PC_HEADER
  57. #include "all.h"
  58. #else
  59. #include <assert.h>
  60. #include <stdlib.h>
  61. #include "alphabuf.h"
  62. #include "blend.h"
  63. #include "context.h"
  64. #include "dlist.h"
  65. #include "macros.h"
  66. #include "pb.h"
  67. #include "span.h"
  68. #include "types.h"
  69. #endif
  70.  
  71.  
  72.  
  73. void gl_BlendFunc( GLcontext* ctx, GLenum sfactor, GLenum dfactor )
  74. {
  75.    if (INSIDE_BEGIN_END(ctx)) {
  76.       gl_error( ctx, GL_INVALID_OPERATION, "glBlendFunc" );
  77.       return;
  78.    }
  79.  
  80.    switch (sfactor) {
  81.       case GL_ZERO:
  82.       case GL_ONE:
  83.       case GL_DST_COLOR:
  84.       case GL_ONE_MINUS_DST_COLOR:
  85.       case GL_SRC_ALPHA:
  86.       case GL_ONE_MINUS_SRC_ALPHA:
  87.       case GL_DST_ALPHA:
  88.       case GL_ONE_MINUS_DST_ALPHA:
  89.       case GL_SRC_ALPHA_SATURATE:
  90.       case GL_CONSTANT_COLOR:
  91.       case GL_ONE_MINUS_CONSTANT_COLOR:
  92.       case GL_CONSTANT_ALPHA:
  93.       case GL_ONE_MINUS_CONSTANT_ALPHA:
  94.      ctx->Color.BlendSrc = sfactor;
  95.      break;
  96.       default:
  97.      gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
  98.      return;
  99.    }
  100.  
  101.    switch (dfactor) {
  102.       case GL_ZERO:
  103.       case GL_ONE:
  104.       case GL_SRC_COLOR:
  105.       case GL_ONE_MINUS_SRC_COLOR:
  106.       case GL_SRC_ALPHA:
  107.       case GL_ONE_MINUS_SRC_ALPHA:
  108.       case GL_DST_ALPHA:
  109.       case GL_ONE_MINUS_DST_ALPHA:
  110.       case GL_CONSTANT_COLOR:
  111.       case GL_ONE_MINUS_CONSTANT_COLOR:
  112.       case GL_CONSTANT_ALPHA:
  113.       case GL_ONE_MINUS_CONSTANT_ALPHA:
  114.      ctx->Color.BlendDst = dfactor;
  115.      break;
  116.       default:
  117.      gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
  118.    }
  119.    {
  120.     int a = ctx->NewState | NEW_RASTER_OPS;
  121.     ctx->NewState = a;
  122.    }
  123. }
  124.  
  125.  
  126.  
  127. /* This is really an extension function! */
  128. void gl_BlendEquation( GLcontext* ctx, GLenum mode )
  129. {
  130.    if (INSIDE_BEGIN_END(ctx)) {
  131.       gl_error( ctx, GL_INVALID_OPERATION, "glBlendEquation" );
  132.       return;
  133.    }
  134.  
  135.    switch (mode) {
  136.       case GL_MIN_EXT:
  137.       case GL_MAX_EXT:
  138.       case GL_LOGIC_OP:
  139.       case GL_FUNC_ADD_EXT:
  140.       case GL_FUNC_SUBTRACT_EXT:
  141.       case GL_FUNC_REVERSE_SUBTRACT_EXT:
  142.      ctx->Color.BlendEquation = mode;
  143.      break;
  144.       default:
  145.      gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" );
  146.      return;
  147.    }
  148.  
  149.    /* This is needed to support 1.1's RGB logic ops AND
  150.     * 1.0's blending logicops.
  151.     */
  152.    if (mode==GL_LOGIC_OP && ctx->Color.BlendEnabled) {
  153.       ctx->Color.ColorLogicOpEnabled = GL_TRUE;
  154.    }
  155.    else {
  156.       ctx->Color.ColorLogicOpEnabled = GL_FALSE;
  157.    }
  158.    {
  159.     int a = ctx->NewState | NEW_RASTER_OPS;
  160.     ctx->NewState = a;
  161.    }
  162. }
  163.  
  164.  
  165.  
  166. void gl_BlendColor( GLcontext* ctx, GLclampf red, GLclampf green,
  167.             GLclampf blue, GLclampf alpha )
  168. {
  169.    ctx->Color.BlendColor[0] = CLAMP( red,   0.0, 1.0 );
  170.    ctx->Color.BlendColor[1] = CLAMP( green, 0.0, 1.0 );
  171.    ctx->Color.BlendColor[2] = CLAMP( blue,  0.0, 1.0 );
  172.    ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0, 1.0 );
  173. }
  174.  
  175.  
  176.  
  177. /*
  178.  * Do the real work of gl_blend_span() and gl_blend_pixels().
  179.  * Input:  n - number of pixels
  180.  *         mask - the usual write mask
  181.  * In/Out:  red, green, blue, alpha - the incoming and modified pixels
  182.  * Input:  rdest, gdest, bdest, adest - the pixels from the dest color buffer
  183.  */
  184. static void do_blend( GLcontext* ctx, GLuint n, const GLubyte mask[],
  185.               GLubyte red[], GLubyte green[],
  186.               GLubyte blue[], GLubyte alpha[],
  187.               const GLubyte rdest[], const GLubyte gdest[],
  188.               const GLubyte bdest[], const GLubyte adest[] )
  189. {
  190.    GLuint i;
  191.  
  192.    /* Common cases: */
  193.  
  194.    if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT
  195.        && ctx->Color.BlendSrc==GL_SRC_ALPHA
  196.        && ctx->Color.BlendDst==GL_ONE_MINUS_SRC_ALPHA) {
  197.       /* Alpha blending */
  198.       GLfloat ascale = 256.0f * ctx->Visual->InvAlphaScale;
  199.       GLint rmax = (GLint) ctx->Visual->RedScale;
  200.       GLint gmax = (GLint) ctx->Visual->GreenScale;
  201.       GLint bmax = (GLint) ctx->Visual->BlueScale;
  202.       GLint amax = (GLint) ctx->Visual->AlphaScale;
  203.       for (i=0;i<n;i++) {
  204.      if (mask[i]) {
  205.         GLint r, g, b, a;
  206.         GLint t = (GLint) ( alpha[i] * ascale );  /* t in [0,256] */
  207.         GLint s = 256 - t;
  208.         r = (red[i]   * t + rdest[i] * s) >> 8;
  209.         g = (green[i] * t + gdest[i] * s) >> 8;
  210.         b = (blue[i]  * t + bdest[i] * s) >> 8;
  211.         a = (alpha[i] * t + adest[i] * s) >> 8;
  212.         red[i]   = MIN2( r, rmax );
  213.         green[i] = MIN2( g, gmax );
  214.         blue[i]  = MIN2( b, bmax );
  215.         alpha[i] = MIN2( a, amax );
  216.      }
  217.       }
  218.    }
  219.  
  220.    /* General cases: */
  221.  
  222.    else if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT
  223.      || ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT
  224.      || ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
  225.       GLfloat rmax = ctx->Visual->RedScale;
  226.       GLfloat gmax = ctx->Visual->GreenScale;
  227.       GLfloat bmax = ctx->Visual->BlueScale;
  228.       GLfloat amax = ctx->Visual->AlphaScale;
  229.       GLfloat rscale = 1.0f / rmax;
  230.       GLfloat gscale = 1.0f / gmax;
  231.       GLfloat bscale = 1.0f / bmax;
  232.       GLfloat ascale = 1.0f / amax;
  233.  
  234.       for (i=0;i<n;i++) {
  235.      if (mask[i]) {
  236.         GLint Rs, Gs, Bs, As;  /* Source colors */
  237.         GLint Rd, Gd, Bd, Ad;  /* Dest colors */
  238.         GLfloat sR, sG, sB, sA;  /* Source scaling */
  239.         GLfloat dR, dG, dB, dA;  /* Dest scaling */
  240.         GLfloat r, g, b, a;
  241.  
  242.         /* Source Color */
  243.         Rs = red[i];
  244.         Gs = green[i];
  245.         Bs = blue[i];
  246.         As = alpha[i];
  247.  
  248.         /* Frame buffer color */
  249.         Rd = rdest[i];
  250.         Gd = gdest[i];
  251.         Bd = bdest[i];
  252.         Ad = adest[i];
  253.  
  254.         /* Source scaling */
  255.         switch (ctx->Color.BlendSrc) {
  256.            case GL_ZERO:
  257.           sR = sG = sB = sA = 0.0F;
  258.           break;
  259.            case GL_ONE:
  260.           sR = sG = sB = sA = 1.0F;
  261.           break;
  262.            case GL_DST_COLOR:
  263.           sR = (GLfloat) Rd * rscale;
  264.           sG = (GLfloat) Gd * gscale;
  265.           sB = (GLfloat) Bd * bscale;
  266.           sA = (GLfloat) Ad * ascale;
  267.           break;
  268.            case GL_ONE_MINUS_DST_COLOR:
  269.           sR = 1.0F - (GLfloat) Rd * rscale;
  270.           sG = 1.0F - (GLfloat) Gd * gscale;
  271.           sB = 1.0F - (GLfloat) Bd * bscale;
  272.           sA = 1.0F - (GLfloat) Ad * ascale;
  273.           break;
  274.            case GL_SRC_ALPHA:
  275.           sR = sG = sB = sA = (GLfloat) As * ascale;
  276.           break;
  277.            case GL_ONE_MINUS_SRC_ALPHA:
  278.           sR = sG = sB = sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
  279.           break;
  280.            case GL_DST_ALPHA:
  281.           sR = sG = sB = sA =(GLfloat) Ad * ascale;
  282.           break;
  283.            case GL_ONE_MINUS_DST_ALPHA:
  284.           sR = sG = sB = sA = 1.0F - (GLfloat) Ad * ascale;
  285.           break;
  286.            case GL_SRC_ALPHA_SATURATE:
  287.           if (As < 1.0F - (GLfloat) Ad * ascale) {
  288.              sR = sG = sB = (GLfloat) As * ascale;
  289.           }
  290.           else {
  291.              sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
  292.           }
  293.           sA = 1.0;
  294.           break;
  295.            case GL_CONSTANT_COLOR:
  296.           sR = ctx->Color.BlendColor[0];
  297.           sG = ctx->Color.BlendColor[1];
  298.           sB = ctx->Color.BlendColor[2];
  299.           sA = ctx->Color.BlendColor[3];
  300.           break;
  301.            case GL_ONE_MINUS_CONSTANT_COLOR:
  302.           sR = 1.0F - ctx->Color.BlendColor[0];
  303.           sG = 1.0F - ctx->Color.BlendColor[1];
  304.           sB = 1.0F - ctx->Color.BlendColor[2];
  305.           sA = 1.0F - ctx->Color.BlendColor[3];
  306.           break;
  307.            case GL_CONSTANT_ALPHA:
  308.           sR = sG = sB = sA = ctx->Color.BlendColor[3];
  309.           break;
  310.            case GL_ONE_MINUS_CONSTANT_ALPHA:
  311.           sR = sG = sB = sA = 1.0F - ctx->Color.BlendColor[3];
  312.           break;
  313.            default:
  314.           /* this should never happen */
  315.           gl_problem(ctx, "Bad blend source factor in do_blend");
  316.         }
  317.  
  318.         /* Dest scaling */
  319.         switch (ctx->Color.BlendDst) {
  320.            case GL_ZERO:
  321.           dR = dG = dB = dA = 0.0F;
  322.           break;
  323.            case GL_ONE:
  324.           dR = dG = dB = dA = 1.0F;
  325.           break;
  326.            case GL_SRC_COLOR:
  327.           dR = (GLfloat) Rs * rscale;
  328.           dG = (GLfloat) Gs * gscale;
  329.           dB = (GLfloat) Bs * bscale;
  330.           dA = (GLfloat) As * ascale;
  331.           break;
  332.            case GL_ONE_MINUS_SRC_COLOR:
  333.           dR = 1.0F - (GLfloat) Rs * rscale;
  334.           dG = 1.0F - (GLfloat) Gs * gscale;
  335.           dB = 1.0F - (GLfloat) Bs * bscale;
  336.           dA = 1.0F - (GLfloat) As * ascale;
  337.           break;
  338.            case GL_SRC_ALPHA:
  339.           dR = dG = dB = dA = (GLfloat) As * ascale;
  340.           break;
  341.            case GL_ONE_MINUS_SRC_ALPHA:
  342.           dR = dG = dB = dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
  343.           break;
  344.            case GL_DST_ALPHA:
  345.           dR = dG = dB = dA = (GLfloat) Ad * ascale;
  346.           break;
  347.            case GL_ONE_MINUS_DST_ALPHA:
  348.           dR = dG = dB = dA = 1.0F - (GLfloat) Ad * ascale;
  349.           break;
  350.            case GL_CONSTANT_COLOR:
  351.           dR = ctx->Color.BlendColor[0];
  352.           dG = ctx->Color.BlendColor[1];
  353.           dB = ctx->Color.BlendColor[2];
  354.           dA = ctx->Color.BlendColor[3];
  355.           break;
  356.            case GL_ONE_MINUS_CONSTANT_COLOR:
  357.           dR = 1.0F - ctx->Color.BlendColor[0];
  358.           dG = 1.0F - ctx->Color.BlendColor[1];
  359.           dB = 1.0F - ctx->Color.BlendColor[2];
  360.           dA = 1.0F - ctx->Color.BlendColor[3];
  361.           break;
  362.            case GL_CONSTANT_ALPHA:
  363.           dR = dG = dB = dA = ctx->Color.BlendColor[3];
  364.           break;
  365.            case GL_ONE_MINUS_CONSTANT_ALPHA:
  366.           dR = dG = dB = dA = 1.0F - ctx->Color.BlendColor[3] * ascale;
  367.           break;
  368.            default:
  369.           /* this should never happen */
  370.           gl_problem(ctx, "Bad blend dest factor in do_blend");
  371.         }
  372.  
  373. #ifdef DEBUG
  374.         assert( sR>= 0.0 && sR<=1.0 );
  375.         assert( sG>= 0.0 && sG<=1.0 );
  376.         assert( sB>= 0.0 && sB<=1.0 );
  377.         assert( sA>= 0.0 && sA<=1.0 );
  378.         assert( dR>= 0.0 && dR<=1.0 );
  379.         assert( dG>= 0.0 && dG<=1.0 );
  380.         assert( dB>= 0.0 && dB<=1.0 );
  381.         assert( dA>= 0.0 && dA<=1.0 );
  382. #endif
  383.  
  384.         /* compute blended color */
  385.         if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
  386.            r = Rs * sR + Rd * dR;
  387.            g = Gs * sG + Gd * dG;
  388.            b = Bs * sB + Bd * dB;
  389.            a = As * sA + Ad * dA;
  390.         }
  391.         else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
  392.            r = Rs * sR - Rd * dR;
  393.            g = Gs * sG - Gd * dG;
  394.            b = Bs * sB - Bd * dB;
  395.            a = As * sA - Ad * dA;
  396.         }
  397.         else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
  398.            r = Rd * dR - Rs * sR;
  399.            g = Gd * dG - Gs * sG;
  400.            b = Bd * dB - Bs * sB;
  401.            a = Ad * dA - As * sA;
  402.         }
  403.         red[i]   = (GLint) CLAMP( r, 0.0F, rmax );
  404.         green[i] = (GLint) CLAMP( g, 0.0F, gmax );
  405.         blue[i]  = (GLint) CLAMP( b, 0.0F, bmax );
  406.         alpha[i] = (GLint) CLAMP( a, 0.0F, amax );
  407.      }
  408.       }
  409.    }
  410.    else if (ctx->Color.BlendEquation==GL_MIN_EXT) {
  411.       /* EXTENSION */
  412.       for (i=0;i<n;i++) {
  413.      if (mask[i]) {
  414.         red[i]   = MIN2( red[i],   rdest[i] );
  415.         green[i] = MIN2( green[i], gdest[i] );
  416.         blue[i]  = MIN2( blue[i],  bdest[i] );
  417.         alpha[i] = MIN2( alpha[i], adest[i] );
  418.      }
  419.       }
  420.    }
  421.    else if (ctx->Color.BlendEquation==GL_MAX_EXT) {
  422.       /* EXTENSION */
  423.       for (i=0;i<n;i++) {
  424.      if (mask[i]) {
  425.         red[i]   = MAX2( red[i],   rdest[i] );
  426.         green[i] = MAX2( green[i], gdest[i] );
  427.         blue[i]  = MAX2( blue[i],  bdest[i] );
  428.         alpha[i] = MAX2( alpha[i], adest[i] );
  429.      }
  430.       }
  431.    }
  432.  
  433. }
  434.  
  435.  
  436.  
  437.  
  438.  
  439. /*
  440.  * Apply the blending operator to a span of pixels.
  441.  * Input:  n - number of pixels in span
  442.  *         x, y - location of leftmost pixel in span in window coords.
  443.  *         mask - boolean mask indicating which pixels to blend.
  444.  * In/Out:  red, green, blue, alpha - pixel values
  445.  */
  446. void gl_blend_span( GLcontext* ctx, GLuint n, GLint x, GLint y,
  447.             GLubyte red[], GLubyte green[],
  448.             GLubyte blue[], GLubyte alpha[],
  449.             GLubyte mask[] )
  450. {
  451.    GLubyte rdest[MAX_WIDTH], gdest[MAX_WIDTH];
  452.    GLubyte bdest[MAX_WIDTH], adest[MAX_WIDTH];
  453.  
  454.    /* Check if device driver can do the work */
  455.    if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) {
  456.       return;
  457.    }
  458.  
  459.    /* Read span of current frame buffer pixels */
  460.    gl_read_color_span( ctx, n, x, y, rdest, gdest, bdest, adest );
  461.  
  462.    do_blend( ctx, n, mask, red, green, blue, alpha, rdest, gdest, bdest, adest );
  463. }
  464.  
  465.  
  466.  
  467.  
  468.  
  469. /*
  470.  * Apply the blending operator to an array of pixels.
  471.  * Input:  n - number of pixels in span
  472.  *         x, y - array of pixel locations
  473.  *         mask - boolean mask indicating which pixels to blend.
  474.  * In/Out:  red, green, blue, alpha - array of pixel values
  475.  */
  476. void gl_blend_pixels( GLcontext* ctx,
  477.               GLuint n, const GLint x[], const GLint y[],
  478.               GLubyte red[], GLubyte green[],
  479.               GLubyte blue[], GLubyte alpha[],
  480.               GLubyte mask[] )
  481. {
  482.    GLubyte rdest[PB_SIZE], gdest[PB_SIZE], bdest[PB_SIZE], adest[PB_SIZE];
  483.  
  484.    /* Check if device driver can do the work */
  485.    if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) {
  486.       return;
  487.    }
  488.  
  489.    /* Read pixels from current color buffer */
  490.    (*ctx->Driver.ReadColorPixels)( ctx, n, x, y, rdest, gdest, bdest, adest, mask );
  491.    if (ctx->RasterMask & ALPHABUF_BIT) {
  492.       gl_read_alpha_pixels( ctx, n, x, y, adest, mask );
  493.    }
  494.  
  495.    do_blend( ctx, n, mask, red, green, blue, alpha, rdest, gdest, bdest, adest );
  496. }
  497.