home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / System / Mesa-3.1 / src / accum.c next >
C/C++ Source or Header  |  2000-01-07  |  17KB  |  518 lines

  1. /* $Id: accum.c,v 1.10.2.1 1999/11/27 01:35:42 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  3.1
  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. /* $XFree86: xc/lib/GL/mesa/src/accum.c,v 1.3 1999/04/04 00:20:17 dawes Exp $ */
  29.  
  30. #ifdef PC_HEADER
  31. #include "all.h"
  32. #else
  33. #ifndef XFree86Server
  34. #include <assert.h>
  35. #include <limits.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #else
  39. #include "GL/xf86glx.h"
  40. #endif
  41. #include "accum.h"
  42. #include "context.h"
  43. #include "macros.h"
  44. #include "masking.h"
  45. #include "span.h"
  46. #include "types.h"
  47. #endif
  48.  
  49.  
  50. /*
  51.  * Accumulation buffer notes
  52.  *
  53.  * Normally, accumulation buffer values are GLshorts with values in
  54.  * [-32767, 32767] which represent floating point colors in [-1, 1],
  55.  * as suggested by the OpenGL specification.
  56.  *
  57.  * We optimize for the common case used for full-scene antialiasing:
  58.  *    // start with accum buffer cleared to zero
  59.  *    glAccum(GL_LOAD, w);   // or GL_ACCUM the first image
  60.  *    glAccum(GL_ACCUM, w);
  61.  *    ...
  62.  *    glAccum(GL_ACCUM, w);
  63.  *    glAccum(GL_RETURN, 1.0);
  64.  * That is, we start with an empty accumulation buffer and accumulate
  65.  * n images, each with weight w = 1/n.
  66.  * In this scenario, we can simply store unscaled integer values in
  67.  * the accum buffer instead of scaled integers.  We'll also keep track
  68.  * of the w value so when we do GL_RETURN we simply divide the accumulated
  69.  * values by n (=1/w).
  70.  * This lets us avoid _many_ int->float->int conversions.
  71.  */
  72.  
  73.  
  74. #define USE_OPTIMIZED_ACCUM   /* enable the optimization */
  75.  
  76.  
  77.  
  78. void gl_alloc_accum_buffer( GLcontext *ctx )
  79. {
  80.    GLint n;
  81.  
  82.    if (ctx->Buffer->Accum) {
  83.       FREE( ctx->Buffer->Accum );
  84.       ctx->Buffer->Accum = NULL;
  85.    }
  86.  
  87.    /* allocate accumulation buffer if not already present */
  88.    n = ctx->Buffer->Width * ctx->Buffer->Height * 4 * sizeof(GLaccum);
  89.    ctx->Buffer->Accum = (GLaccum *) MALLOC( n );
  90.    if (!ctx->Buffer->Accum) {
  91.       /* unable to setup accumulation buffer */
  92.       gl_error( ctx, GL_OUT_OF_MEMORY, "glAccum" );
  93.    }
  94. #ifdef USE_OPTIMIZED_ACCUM
  95.    ctx->IntegerAccumMode = GL_TRUE;
  96. #else
  97.    ctx->IntegerAccumMode = GL_FALSE;
  98. #endif
  99.    ctx->IntegerAccumScaler = 0.0;
  100. }
  101.  
  102.  
  103.  
  104. void gl_ClearAccum( GLcontext *ctx,
  105.                     GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
  106. {
  107.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
  108.  
  109.    ctx->Accum.ClearColor[0] = CLAMP( red, -1.0, 1.0 );
  110.    ctx->Accum.ClearColor[1] = CLAMP( green, -1.0, 1.0 );
  111.    ctx->Accum.ClearColor[2] = CLAMP( blue, -1.0, 1.0 );
  112.    ctx->Accum.ClearColor[3] = CLAMP( alpha, -1.0, 1.0 );
  113. }
  114.  
  115.  
  116.  
  117. /*
  118.  * This is called when we fall out of optimized/unscaled accum buffer mode.
  119.  * That is, we convert each unscaled accum buffer value into a scaled value
  120.  * representing the range[-1, 1].
  121.  */
  122. static void rescale_accum( GLcontext *ctx )
  123. {
  124.    const GLuint n = ctx->Buffer->Width * ctx->Buffer->Height * 4;
  125.    const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
  126.    const GLfloat s = ctx->IntegerAccumScaler * (32767.0 / fChanMax);
  127.    GLaccum *accum = ctx->Buffer->Accum;
  128.    GLuint i;
  129.  
  130.    assert(ctx->IntegerAccumMode);
  131.    assert(accum);
  132.  
  133.    for (i = 0; i < n; i++) {
  134.       accum[i] = (GLaccum) (accum[i] * s);
  135.    }
  136.  
  137.    ctx->IntegerAccumMode = GL_FALSE;
  138. }
  139.  
  140.  
  141.  
  142. void gl_Accum( GLcontext *ctx, GLenum op, GLfloat value )
  143. {
  144.    GLuint xpos, ypos, width, height, width4;
  145.    GLfloat acc_scale;
  146.    GLubyte rgba[MAX_WIDTH][4];
  147.    const GLint iChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
  148.    const GLfloat fChanMax = (1 << (sizeof(GLchan) * 8)) - 1;
  149.    
  150.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glAccum");
  151.  
  152.    if (ctx->Visual->AccumBits==0 || !ctx->Buffer->Accum) {
  153.       /* No accumulation buffer! */
  154.       gl_warning(ctx, "Calling glAccum() without an accumulation buffer");
  155.       return;
  156.    }
  157.  
  158.    if (sizeof(GLaccum)==1) {
  159.       acc_scale = 127.0;
  160.    }
  161.    else if (sizeof(GLaccum)==2) {
  162.       acc_scale = 32767.0;
  163.    }
  164.    else {
  165.       /* sizeof(GLaccum) > 2 (Cray) */
  166.       acc_scale = (float) SHRT_MAX;
  167.    }
  168.  
  169.    if (ctx->NewState)
  170.       gl_update_state( ctx );
  171.  
  172.    /* Determine region to operate upon. */
  173.    if (ctx->Scissor.Enabled) {
  174.       xpos = ctx->Scissor.X;
  175.       ypos = ctx->Scissor.Y;
  176.       width = ctx->Scissor.Width;
  177.       height = ctx->Scissor.Height;
  178.    }
  179.    else {
  180.       /* whole window */
  181.       xpos = 0;
  182.       ypos = 0;
  183.       width = ctx->Buffer->Width;
  184.       height = ctx->Buffer->Height;
  185.    }
  186.  
  187.    width4 = 4 * width;
  188.  
  189.    switch (op) {
  190.       case GL_ADD:
  191.          {
  192.         const GLaccum intVal = (GLaccum) (value * acc_scale);
  193.         GLuint j;
  194.             /* Leave optimized accum buffer mode */
  195.             if (ctx->IntegerAccumMode)
  196.                rescale_accum(ctx);
  197.         for (j = 0; j < height; j++) {
  198.            GLaccum * acc = ctx->Buffer->Accum + ypos * width4 + 4 * xpos;
  199.                GLuint i;
  200.            for (i = 0; i < width4; i++) {
  201.                   acc[i] += intVal;
  202.            }
  203.            ypos++;
  204.         }
  205.      }
  206.      break;
  207.  
  208.       case GL_MULT:
  209.      {
  210.         GLuint j;
  211.             /* Leave optimized accum buffer mode */
  212.             if (ctx->IntegerAccumMode)
  213.                rescale_accum(ctx);
  214.         for (j = 0; j < height; j++) {
  215.            GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + 4 * xpos;
  216.                GLuint i;
  217.            for (i = 0; i < width4; i++) {
  218.                   acc[i] = (GLaccum) ( (GLfloat) acc[i] * value );
  219.            }
  220.            ypos++;
  221.         }
  222.      }
  223.      break;
  224.  
  225.       case GL_ACCUM:
  226.          (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.DriverReadBuffer );
  227.  
  228.          /* May have to leave optimized accum buffer mode */
  229.          if (ctx->IntegerAccumScaler == 0.0 && value > 0.0 && value <= 1.0)
  230.             ctx->IntegerAccumScaler = value;
  231.          if (ctx->IntegerAccumMode && value != ctx->IntegerAccumScaler)
  232.             rescale_accum(ctx);
  233.             
  234.          if (ctx->IntegerAccumMode) {
  235.             /* simply add integer color values into accum buffer */
  236.             GLuint j;
  237.             GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
  238.             assert(ctx->IntegerAccumScaler > 0.0);
  239.             assert(ctx->IntegerAccumScaler <= 1.0);
  240.             for (j = 0; j < height; j++) {
  241.                
  242.                GLuint i, i4;
  243.                gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
  244.                for (i = i4 = 0; i < width; i++, i4+=4) {
  245.                   acc[i4+0] += rgba[i][RCOMP];
  246.                   acc[i4+1] += rgba[i][GCOMP];
  247.                   acc[i4+2] += rgba[i][BCOMP];
  248.                   acc[i4+3] += rgba[i][ACOMP];
  249.                }
  250.                acc += width4;
  251.                ypos++;
  252.             }
  253.          }
  254.          else {
  255.             /* scaled integer accum buffer */
  256.             const GLfloat rscale = value * acc_scale / fChanMax;
  257.             const GLfloat gscale = value * acc_scale / fChanMax;
  258.             const GLfloat bscale = value * acc_scale / fChanMax;
  259.             const GLfloat ascale = value * acc_scale / fChanMax;
  260.             GLuint j;
  261.             for (j=0;j<height;j++) {
  262.                GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
  263.                GLuint i;
  264.                gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
  265.                for (i=0;i<width;i++) {
  266.                   *acc += (GLaccum) ( (GLfloat) rgba[i][RCOMP] * rscale );  acc++;
  267.                   *acc += (GLaccum) ( (GLfloat) rgba[i][GCOMP] * gscale );  acc++;
  268.                   *acc += (GLaccum) ( (GLfloat) rgba[i][BCOMP] * bscale );  acc++;
  269.                   *acc += (GLaccum) ( (GLfloat) rgba[i][ACOMP] * ascale );  acc++;
  270.                }
  271.                ypos++;
  272.             }
  273.          }
  274.          (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DriverDrawBuffer );
  275.      break;
  276.  
  277.       case GL_LOAD:
  278.          (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.DriverReadBuffer );
  279.  
  280.          /* This is a change to go into optimized accum buffer mode */
  281.          if (value > 0.0 && value <= 1.0) {
  282. #ifdef USE_OPTIMIZED_ACCUM
  283.             ctx->IntegerAccumMode = GL_TRUE;
  284. #else
  285.             ctx->IntegerAccumMode = GL_FALSE;
  286. #endif
  287.             ctx->IntegerAccumScaler = value;
  288.          }
  289.          else {
  290.             ctx->IntegerAccumMode = GL_FALSE;
  291.             ctx->IntegerAccumScaler = 0.0;
  292.          }
  293.  
  294.          if (ctx->IntegerAccumMode) {
  295.             /* just copy values into accum buffer */
  296.             GLuint j;
  297.             GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
  298.             assert(ctx->IntegerAccumScaler > 0.0);
  299.             assert(ctx->IntegerAccumScaler <= 1.0);
  300.             for (j = 0; j < height; j++) {
  301.                GLuint i, i4;
  302.                gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
  303.                for (i = i4 = 0; i < width; i++, i4 += 4) {
  304.                   acc[i4+0] = rgba[i][RCOMP];
  305.                   acc[i4+1] = rgba[i][GCOMP];
  306.                   acc[i4+2] = rgba[i][BCOMP];
  307.                   acc[i4+3] = rgba[i][ACOMP];
  308.                }
  309.                acc += width4;
  310.                ypos++;
  311.             }
  312.          }
  313.          else {
  314.             /* scaled integer accum buffer */
  315.             const GLfloat rscale = value * acc_scale / fChanMax;
  316.             const GLfloat gscale = value * acc_scale / fChanMax;
  317.             const GLfloat bscale = value * acc_scale / fChanMax;
  318.             const GLfloat ascale = value * acc_scale / fChanMax;
  319.             const GLfloat d = 3.0 / acc_scale;
  320.             GLuint i, j;
  321.             for (j = 0; j < height; j++) {
  322.                GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos * 4;
  323.                gl_read_rgba_span(ctx, width, xpos, ypos, rgba);
  324.                for (i=0;i<width;i++) {
  325.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][RCOMP] * rscale + d);
  326.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][GCOMP] * gscale + d);
  327.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][BCOMP] * bscale + d);
  328.                   *acc++ = (GLaccum) ((GLfloat) rgba[i][ACOMP] * ascale + d);
  329.                }
  330.                ypos++;
  331.             }
  332.          }
  333.          (void) (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DriverDrawBuffer );
  334.      break;
  335.  
  336.       case GL_RETURN:
  337.          /* May have to leave optimized accum buffer mode */
  338.          if (ctx->IntegerAccumMode && value != 1.0)
  339.             rescale_accum(ctx);
  340.  
  341.          if (ctx->IntegerAccumMode) {
  342.             /* build lookup table to avoid many floating point multiplies */
  343.             const GLfloat mult = ctx->IntegerAccumScaler;
  344.             static GLchan multTable[32768];
  345.             static GLfloat prevMult = 0.0;
  346.             GLuint j;
  347.             const GLint max = (GLint) (256 / mult);
  348.             if (mult != prevMult) {
  349.                assert(max <= 32768);
  350.                for (j = 0; j < max; j++)
  351.                   multTable[j] = (GLint) ((GLfloat) j * mult + 0.5F);
  352.                prevMult = mult;
  353.             }
  354.  
  355.             assert(ctx->IntegerAccumScaler > 0.0);
  356.             assert(ctx->IntegerAccumScaler <= 1.0);
  357.             for (j = 0; j < height; j++) {
  358.                const GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos*4;
  359.                GLuint i, i4;
  360.                for (i = i4 = 0; i < width; i++, i4 += 4) {
  361.                   ASSERT(acc[i4+0] < max);
  362.                   ASSERT(acc[i4+1] < max);
  363.                   ASSERT(acc[i4+2] < max);
  364.                   ASSERT(acc[i4+3] < max);
  365.                   rgba[i][RCOMP] = multTable[acc[i4+0]];
  366.                   rgba[i][GCOMP] = multTable[acc[i4+1]];
  367.                   rgba[i][BCOMP] = multTable[acc[i4+2]];
  368.                   rgba[i][ACOMP] = multTable[acc[i4+3]];
  369.                }
  370.                if (ctx->Color.SWmasking) {
  371.                   gl_mask_rgba_span( ctx, width, xpos, ypos, rgba );
  372.                }
  373.                (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos, 
  374.                                              (const GLubyte (*)[4])rgba, NULL );
  375.                ypos++;
  376.             }
  377.          }
  378.          else {
  379.             const GLfloat rscale = value / acc_scale * fChanMax;
  380.             const GLfloat gscale = value / acc_scale * fChanMax;
  381.             const GLfloat bscale = value / acc_scale * fChanMax;
  382.             const GLfloat ascale = value / acc_scale * fChanMax;
  383.             GLuint i, j;
  384.             for (j=0;j<height;j++) {
  385.                const GLaccum *acc = ctx->Buffer->Accum + ypos * width4 + xpos*4;
  386.                for (i=0;i<width;i++) {
  387.                   GLint r, g, b, a;
  388.                   r = (GLint) ( (GLfloat) (*acc++) * rscale + 0.5F );
  389.                   g = (GLint) ( (GLfloat) (*acc++) * gscale + 0.5F );
  390.                   b = (GLint) ( (GLfloat) (*acc++) * bscale + 0.5F );
  391.                   a = (GLint) ( (GLfloat) (*acc++) * ascale + 0.5F );
  392.                   rgba[i][RCOMP] = CLAMP( r, 0, iChanMax );
  393.                   rgba[i][GCOMP] = CLAMP( g, 0, iChanMax );
  394.                   rgba[i][BCOMP] = CLAMP( b, 0, iChanMax );
  395.                   rgba[i][ACOMP] = CLAMP( a, 0, iChanMax );
  396.                }
  397.                if (ctx->Color.SWmasking) {
  398.                   gl_mask_rgba_span( ctx, width, xpos, ypos, rgba );
  399.                }
  400.                (*ctx->Driver.WriteRGBASpan)( ctx, width, xpos, ypos, 
  401.                                              (const GLubyte (*)[4])rgba, NULL );
  402.                ypos++;
  403.             }
  404.      }
  405.      break;
  406.  
  407.       default:
  408.          gl_error( ctx, GL_INVALID_ENUM, "glAccum" );
  409.    }
  410. }
  411.  
  412.  
  413.  
  414. /*
  415.  * Clear the accumulation Buffer.
  416.  */
  417. void gl_clear_accum_buffer( GLcontext *ctx )
  418. {
  419.    GLuint buffersize;
  420.    GLfloat acc_scale;
  421.  
  422.    if (ctx->Visual->AccumBits==0) {
  423.       /* No accumulation buffer! */
  424.       return;
  425.    }
  426.  
  427.    if (sizeof(GLaccum)==1) {
  428.       acc_scale = 127.0;
  429.    }
  430.    else if (sizeof(GLaccum)==2) {
  431.       acc_scale = 32767.0;
  432.    }
  433.    else {
  434.       /* sizeof(GLaccum) > 2 (Cray) */
  435.       acc_scale = (float) SHRT_MAX;
  436.    }
  437.  
  438.    /* number of pixels */
  439.    buffersize = ctx->Buffer->Width * ctx->Buffer->Height;
  440.  
  441.    if (!ctx->Buffer->Accum) {
  442.       /* try to alloc accumulation buffer */
  443.       ctx->Buffer->Accum = (GLaccum *)
  444.                        MALLOC( buffersize * 4 * sizeof(GLaccum) );
  445.    }
  446.  
  447.    if (ctx->Buffer->Accum) {
  448.       if (ctx->Scissor.Enabled) {
  449.      /* Limit clear to scissor box */
  450.      GLaccum r, g, b, a;
  451.      GLint i, j;
  452.          GLint width, height;
  453.          GLaccum *row;
  454.      r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
  455.      g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
  456.      b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
  457.      a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
  458.          /* size of region to clear */
  459.          width = 4 * (ctx->Buffer->Xmax - ctx->Buffer->Xmin + 1);
  460.          height = ctx->Buffer->Ymax - ctx->Buffer->Ymin + 1;
  461.          /* ptr to first element to clear */
  462.          row = ctx->Buffer->Accum
  463.                + 4 * (ctx->Buffer->Ymin * ctx->Buffer->Width
  464.                       + ctx->Buffer->Xmin);
  465.          for (j=0;j<height;j++) {
  466.             for (i=0;i<width;i+=4) {
  467.                row[i+0] = r;
  468.                row[i+1] = g;
  469.                row[i+2] = b;
  470.                row[i+3] = a;
  471.         }
  472.             row += 4 * ctx->Buffer->Width;
  473.      }
  474.       }
  475.       else {
  476.      /* clear whole buffer */
  477.      if (ctx->Accum.ClearColor[0]==0.0 &&
  478.          ctx->Accum.ClearColor[1]==0.0 &&
  479.          ctx->Accum.ClearColor[2]==0.0 &&
  480.          ctx->Accum.ClearColor[3]==0.0) {
  481.         /* Black */
  482.         MEMSET( ctx->Buffer->Accum, 0, buffersize * 4 * sizeof(GLaccum) );
  483.      }
  484.      else {
  485.         /* Not black */
  486.         GLaccum *acc, r, g, b, a;
  487.         GLuint i;
  488.  
  489.         acc = ctx->Buffer->Accum;
  490.         r = (GLaccum) (ctx->Accum.ClearColor[0] * acc_scale);
  491.         g = (GLaccum) (ctx->Accum.ClearColor[1] * acc_scale);
  492.         b = (GLaccum) (ctx->Accum.ClearColor[2] * acc_scale);
  493.         a = (GLaccum) (ctx->Accum.ClearColor[3] * acc_scale);
  494.         for (i=0;i<buffersize;i++) {
  495.            *acc++ = r;
  496.            *acc++ = g;
  497.            *acc++ = b;
  498.            *acc++ = a;
  499.         }
  500.      }
  501.       }
  502.  
  503.       /* update optimized accum state vars */
  504.       if (ctx->Accum.ClearColor[0] == 0.0 && ctx->Accum.ClearColor[1] == 0.0 &&
  505.           ctx->Accum.ClearColor[2] == 0.0 && ctx->Accum.ClearColor[3] == 0.0) {
  506. #ifdef USE_OPTIMIZED_ACCUM
  507.          ctx->IntegerAccumMode = GL_TRUE;
  508. #else
  509.          ctx->IntegerAccumMode = GL_FALSE;
  510. #endif
  511.          ctx->IntegerAccumScaler = 0.0;  /* denotes empty accum buffer */
  512.       }
  513.       else {
  514.          ctx->IntegerAccumMode = GL_FALSE;
  515.       }
  516.    }
  517. }
  518.