home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mesa5.zip / mesa5src.zip / MesaDLL / convolve.cpp < prev    next >
C/C++ Source or Header  |  2002-10-24  |  49KB  |  1,423 lines

  1. /* $Id: convolve.c,v 1.28 2002/10/24 23:57:20 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. /*
  29.  * Image convolution functions.
  30.  *
  31.  * Notes: filter kernel elements are indexed by <n> and <m> as in
  32.  * the GL spec.
  33.  */
  34.  
  35.  
  36. #include "glheader.h"
  37. #include "colormac.h"
  38. #include "convolve.h"
  39. #include "context.h"
  40. #include "image.h"
  41. #include "mtypes.h"
  42. #include "state.h"
  43.  
  44.  
  45. /*
  46.  * Given an internalFormat token passed to glConvolutionFilter
  47.  * or glSeparableFilter, return the corresponding base format.
  48.  * Return -1 if invalid token.
  49.  */
  50. static GLint
  51. base_filter_format( GLenum format )
  52. {
  53.    switch (format) {
  54.       case GL_ALPHA:
  55.       case GL_ALPHA4:
  56.       case GL_ALPHA8:
  57.       case GL_ALPHA12:
  58.       case GL_ALPHA16:
  59.          return GL_ALPHA;
  60.       case GL_LUMINANCE:
  61.       case GL_LUMINANCE4:
  62.       case GL_LUMINANCE8:
  63.       case GL_LUMINANCE12:
  64.       case GL_LUMINANCE16:
  65.          return GL_LUMINANCE;
  66.       case GL_LUMINANCE_ALPHA:
  67.       case GL_LUMINANCE4_ALPHA4:
  68.       case GL_LUMINANCE6_ALPHA2:
  69.       case GL_LUMINANCE8_ALPHA8:
  70.       case GL_LUMINANCE12_ALPHA4:
  71.       case GL_LUMINANCE12_ALPHA12:
  72.       case GL_LUMINANCE16_ALPHA16:
  73.          return GL_LUMINANCE_ALPHA;
  74.       case GL_INTENSITY:
  75.       case GL_INTENSITY4:
  76.       case GL_INTENSITY8:
  77.       case GL_INTENSITY12:
  78.       case GL_INTENSITY16:
  79.          return GL_INTENSITY;
  80.       case GL_RGB:
  81.       case GL_R3_G3_B2:
  82.       case GL_RGB4:
  83.       case GL_RGB5:
  84.       case GL_RGB8:
  85.       case GL_RGB10:
  86.       case GL_RGB12:
  87.       case GL_RGB16:
  88.          return GL_RGB;
  89.       case 4:
  90.       case GL_RGBA:
  91.       case GL_RGBA2:
  92.       case GL_RGBA4:
  93.       case GL_RGB5_A1:
  94.       case GL_RGBA8:
  95.       case GL_RGB10_A2:
  96.       case GL_RGBA12:
  97.       case GL_RGBA16:
  98.          return GL_RGBA;
  99.       default:
  100.          return -1;  /* error */
  101.    }
  102. }
  103.  
  104.  
  105. void
  106. _mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
  107. {
  108.    GLint baseFormat;
  109.    GET_CURRENT_CONTEXT(ctx);
  110.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  111.  
  112.    if (target != GL_CONVOLUTION_1D) {
  113.       _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
  114.       return;
  115.    }
  116.  
  117.    baseFormat = base_filter_format(internalFormat);
  118.    if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
  119.       _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
  120.       return;
  121.    }
  122.  
  123.    if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
  124.       _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
  125.       return;
  126.    }
  127.  
  128.    if (!_mesa_is_legal_format_and_type(format, type)) {
  129.       _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
  130.       return;
  131.    }
  132.  
  133.    if (format == GL_COLOR_INDEX ||
  134.        format == GL_STENCIL_INDEX ||
  135.        format == GL_DEPTH_COMPONENT ||
  136.        format == GL_INTENSITY ||
  137.        type == GL_BITMAP) {
  138.       _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
  139.       return;
  140.    }
  141.  
  142.    ctx->Convolution1D.Format = format;
  143.    ctx->Convolution1D.InternalFormat = internalFormat;
  144.    ctx->Convolution1D.Width = width;
  145.    ctx->Convolution1D.Height = 1;
  146.  
  147.    /* unpack filter image */
  148.    _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
  149.                                  ctx->Convolution1D.Filter,
  150.                                  format, type, image, &ctx->Unpack,
  151.                                  0, GL_FALSE);
  152.  
  153.    /* apply scale and bias */
  154.    {
  155.       const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
  156.       const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
  157.       GLint i;
  158.       for (i = 0; i < width; i++) {
  159.          GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
  160.          GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
  161.          GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
  162.          GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
  163.          r = r * scale[0] + bias[0];
  164.          g = g * scale[1] + bias[1];
  165.          b = b * scale[2] + bias[2];
  166.          a = a * scale[3] + bias[3];
  167.          ctx->Convolution1D.Filter[i * 4 + 0] = r;
  168.          ctx->Convolution1D.Filter[i * 4 + 1] = g;
  169.          ctx->Convolution1D.Filter[i * 4 + 2] = b;
  170.          ctx->Convolution1D.Filter[i * 4 + 3] = a;
  171.       }
  172.    }
  173.  
  174.    ctx->NewState |= _NEW_PIXEL;
  175. }
  176.  
  177.  
  178. void
  179. _mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
  180. {
  181.    GLint baseFormat;
  182.    GLint i, components;
  183.    GET_CURRENT_CONTEXT(ctx);
  184.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  185.  
  186.    if (target != GL_CONVOLUTION_2D) {
  187.       _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
  188.       return;
  189.    }
  190.  
  191.    baseFormat = base_filter_format(internalFormat);
  192.    if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
  193.       _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
  194.       return;
  195.    }
  196.  
  197.    if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
  198.       _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
  199.       return;
  200.    }
  201.    if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
  202.       _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
  203.       return;
  204.    }
  205.  
  206.    if (!_mesa_is_legal_format_and_type(format, type)) {
  207.       _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
  208.       return;
  209.    }
  210.    if (format == GL_COLOR_INDEX ||
  211.        format == GL_STENCIL_INDEX ||
  212.        format == GL_DEPTH_COMPONENT ||
  213.        format == GL_INTENSITY ||
  214.        type == GL_BITMAP) {
  215.       _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
  216.       return;
  217.    }
  218.  
  219.    components = _mesa_components_in_format(format);
  220.    assert(components > 0);  /* this should have been caught earlier */
  221.  
  222.    ctx->Convolution2D.Format = format;
  223.    ctx->Convolution2D.InternalFormat = internalFormat;
  224.    ctx->Convolution2D.Width = width;
  225.    ctx->Convolution2D.Height = height;
  226.  
  227.    /* Unpack filter image.  We always store filters in RGBA format. */
  228.    for (i = 0; i < height; i++) {
  229.       const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
  230.                                               height, format, type, 0, i, 0);
  231.       GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
  232.       _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
  233.                                     format, type, src, &ctx->Unpack,
  234.                                     0, GL_FALSE);
  235.    }
  236.  
  237.    /* apply scale and bias */
  238.    {
  239.       const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
  240.       const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
  241.       for (i = 0; i < width * height; i++) {
  242.          GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
  243.          GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
  244.          GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
  245.          GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
  246.          r = r * scale[0] + bias[0];
  247.          g = g * scale[1] + bias[1];
  248.          b = b * scale[2] + bias[2];
  249.          a = a * scale[3] + bias[3];
  250.          ctx->Convolution2D.Filter[i * 4 + 0] = r;
  251.          ctx->Convolution2D.Filter[i * 4 + 1] = g;
  252.          ctx->Convolution2D.Filter[i * 4 + 2] = b;
  253.          ctx->Convolution2D.Filter[i * 4 + 3] = a;
  254.       }
  255.    }
  256.  
  257.    ctx->NewState |= _NEW_PIXEL;
  258. }
  259.  
  260.  
  261. void
  262. _mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
  263. {
  264.    GET_CURRENT_CONTEXT(ctx);
  265.    GLuint c;
  266.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  267.  
  268.    switch (target) {
  269.       case GL_CONVOLUTION_1D:
  270.          c = 0;
  271.          break;
  272.       case GL_CONVOLUTION_2D:
  273.          c = 1;
  274.          break;
  275.       case GL_SEPARABLE_2D:
  276.          c = 2;
  277.          break;
  278.       default:
  279.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
  280.          return;
  281.    }
  282.  
  283.    switch (pname) {
  284.       case GL_CONVOLUTION_BORDER_MODE:
  285.          if (param == (GLfloat) GL_REDUCE ||
  286.              param == (GLfloat) GL_CONSTANT_BORDER ||
  287.              param == (GLfloat) GL_REPLICATE_BORDER) {
  288.             ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
  289.          }
  290.          else {
  291.             _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
  292.             return;
  293.          }
  294.          break;
  295.       default:
  296.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
  297.          return;
  298.    }
  299.  
  300.    ctx->NewState |= _NEW_PIXEL;
  301. }
  302.  
  303.  
  304. void
  305. _mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
  306. {
  307.    GET_CURRENT_CONTEXT(ctx);
  308.    struct gl_convolution_attrib *conv;
  309.    GLuint c;
  310.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  311.  
  312.    switch (target) {
  313.       case GL_CONVOLUTION_1D:
  314.          c = 0;
  315.          conv = &ctx->Convolution1D;
  316.          break;
  317.       case GL_CONVOLUTION_2D:
  318.          c = 1;
  319.          conv = &ctx->Convolution2D;
  320.          break;
  321.       case GL_SEPARABLE_2D:
  322.          c = 2;
  323.          conv = &ctx->Separable2D;
  324.          break;
  325.       default:
  326.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
  327.          return;
  328.    }
  329.  
  330.    switch (pname) {
  331.       case GL_CONVOLUTION_BORDER_COLOR:
  332.          COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
  333.          break;
  334.       case GL_CONVOLUTION_BORDER_MODE:
  335.          if (params[0] == (GLfloat) GL_REDUCE ||
  336.              params[0] == (GLfloat) GL_CONSTANT_BORDER ||
  337.              params[0] == (GLfloat) GL_REPLICATE_BORDER) {
  338.             ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
  339.          }
  340.          else {
  341.             _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
  342.             return;
  343.          }
  344.          break;
  345.       case GL_CONVOLUTION_FILTER_SCALE:
  346.          COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
  347.          break;
  348.       case GL_CONVOLUTION_FILTER_BIAS:
  349.          COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
  350.          break;
  351.       default:
  352.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
  353.          return;
  354.    }
  355.  
  356.    ctx->NewState |= _NEW_PIXEL;
  357. }
  358.  
  359.  
  360. void
  361. _mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
  362. {
  363.    GET_CURRENT_CONTEXT(ctx);
  364.    GLuint c;
  365.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  366.  
  367.    switch (target) {
  368.       case GL_CONVOLUTION_1D:
  369.          c = 0;
  370.          break;
  371.       case GL_CONVOLUTION_2D:
  372.          c = 1;
  373.          break;
  374.       case GL_SEPARABLE_2D:
  375.          c = 2;
  376.          break;
  377.       default:
  378.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
  379.          return;
  380.    }
  381.  
  382.    switch (pname) {
  383.       case GL_CONVOLUTION_BORDER_MODE:
  384.          if (param == (GLint) GL_REDUCE ||
  385.              param == (GLint) GL_CONSTANT_BORDER ||
  386.              param == (GLint) GL_REPLICATE_BORDER) {
  387.             ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
  388.          }
  389.          else {
  390.             _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
  391.             return;
  392.          }
  393.          break;
  394.       default:
  395.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
  396.          return;
  397.    }
  398.  
  399.    ctx->NewState |= _NEW_PIXEL;
  400. }
  401.  
  402.  
  403. void
  404. _mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
  405. {
  406.    GET_CURRENT_CONTEXT(ctx);
  407.    struct gl_convolution_attrib *conv;
  408.    GLuint c;
  409.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  410.  
  411.    switch (target) {
  412.       case GL_CONVOLUTION_1D:
  413.          c = 0;
  414.          conv = &ctx->Convolution1D;
  415.          break;
  416.       case GL_CONVOLUTION_2D:
  417.          c = 1;
  418.          conv = &ctx->Convolution2D;
  419.          break;
  420.       case GL_SEPARABLE_2D:
  421.          c = 2;
  422.          conv = &ctx->Separable2D;
  423.          break;
  424.       default:
  425.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
  426.          return;
  427.    }
  428.  
  429.    switch (pname) {
  430.       case GL_CONVOLUTION_BORDER_COLOR:
  431.      ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
  432.      ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
  433.      ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
  434.      ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
  435.          break;
  436.       case GL_CONVOLUTION_BORDER_MODE:
  437.          if (params[0] == (GLint) GL_REDUCE ||
  438.              params[0] == (GLint) GL_CONSTANT_BORDER ||
  439.              params[0] == (GLint) GL_REPLICATE_BORDER) {
  440.             ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
  441.          }
  442.          else {
  443.             _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
  444.             return;
  445.          }
  446.          break;
  447.       case GL_CONVOLUTION_FILTER_SCALE:
  448.      /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
  449.      /* need cast to prevent compiler warnings */  
  450.      ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0]; 
  451.      ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1]; 
  452.      ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2]; 
  453.      ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3]; 
  454.          break;
  455.       case GL_CONVOLUTION_FILTER_BIAS:
  456.      /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
  457.      /* need cast to prevent compiler warnings */  
  458.      ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0]; 
  459.      ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1]; 
  460.      ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2]; 
  461.      ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3]; 
  462.          break;
  463.       default:
  464.          _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
  465.          return;
  466.    }
  467.  
  468.    ctx->NewState |= _NEW_PIXEL;
  469. }
  470.  
  471.  
  472. void
  473. _mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
  474. {
  475.    GLint baseFormat;
  476.    GET_CURRENT_CONTEXT(ctx);
  477.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  478.  
  479.    if (target != GL_CONVOLUTION_1D) {
  480.       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
  481.       return;
  482.    }
  483.  
  484.    baseFormat = base_filter_format(internalFormat);
  485.    if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
  486.       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
  487.       return;
  488.    }
  489.  
  490.    if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
  491.       _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
  492.       return;
  493.    }
  494.  
  495.    ctx->Driver.CopyConvolutionFilter1D( ctx, target, 
  496.                     internalFormat, x, y, width);
  497. }
  498.  
  499.  
  500. void
  501. _mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
  502. {
  503.    GLint baseFormat;
  504.    GET_CURRENT_CONTEXT(ctx);
  505.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  506.  
  507.    if (target != GL_CONVOLUTION_2D) {
  508.       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
  509.       return;
  510.    }
  511.  
  512.    baseFormat = base_filter_format(internalFormat);
  513.    if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
  514.       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
  515.       return;
  516.    }
  517.  
  518.    if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
  519.       _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
  520.       return;
  521.    }
  522.    if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
  523.       _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
  524.       return;
  525.    }
  526.  
  527.    ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y, 
  528.                     width, height );
  529.  
  530. }
  531.  
  532.  
  533. void
  534. _mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
  535. {
  536.    const struct gl_convolution_attrib *filter;
  537.    GLuint row;
  538.    GET_CURRENT_CONTEXT(ctx);
  539.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  540.  
  541.    if (ctx->NewState) {
  542.       _mesa_update_state(ctx);
  543.    }
  544.  
  545.    if (!_mesa_is_legal_format_and_type(format, type)) {
  546.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
  547.       return;
  548.    }
  549.  
  550.    if (format == GL_COLOR_INDEX ||
  551.        format == GL_STENCIL_INDEX ||
  552.        format == GL_DEPTH_COMPONENT ||
  553.        format == GL_INTENSITY ||
  554.        type == GL_BITMAP) {
  555.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
  556.       return;
  557.    }
  558.  
  559.    switch (target) {
  560.       case GL_CONVOLUTION_1D:
  561.          filter = &(ctx->Convolution1D);
  562.          break;
  563.       case GL_CONVOLUTION_2D:
  564.          filter = &(ctx->Convolution2D);
  565.          break;
  566.       default:
  567.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
  568.          return;
  569.    }
  570.  
  571.    for (row = 0; row < filter->Height; row++) {
  572.       GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
  573.                                          filter->Height, format, type,
  574.                                          0, row, 0);
  575.       const GLfloat *src = filter->Filter + row * filter->Width * 4;
  576.       _mesa_pack_float_rgba_span(ctx, filter->Width,
  577.                                  (const GLfloat (*)[4]) src,
  578.                                  format, type, dst, &ctx->Pack, 0);
  579.    }
  580. }
  581.  
  582.  
  583. void
  584. _mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
  585. {
  586.    GET_CURRENT_CONTEXT(ctx);
  587.    const struct gl_convolution_attrib *conv;
  588.    GLuint c;
  589.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  590.  
  591.    switch (target) {
  592.       case GL_CONVOLUTION_1D:
  593.          c = 0;
  594.          conv = &ctx->Convolution1D;
  595.          break;
  596.       case GL_CONVOLUTION_2D:
  597.          c = 1;
  598.          conv = &ctx->Convolution2D;
  599.          break;
  600.       case GL_SEPARABLE_2D:
  601.          c = 2;
  602.          conv = &ctx->Separable2D;
  603.          break;
  604.       default:
  605.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
  606.          return;
  607.    }
  608.  
  609.    switch (pname) {
  610.       case GL_CONVOLUTION_BORDER_COLOR:
  611.          COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
  612.          break;
  613.       case GL_CONVOLUTION_BORDER_MODE:
  614.          *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
  615.          break;
  616.       case GL_CONVOLUTION_FILTER_SCALE:
  617.          COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
  618.          break;
  619.       case GL_CONVOLUTION_FILTER_BIAS:
  620.          COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
  621.          break;
  622.       case GL_CONVOLUTION_FORMAT:
  623.          *params = (GLfloat) conv->Format;
  624.          break;
  625.       case GL_CONVOLUTION_WIDTH:
  626.          *params = (GLfloat) conv->Width;
  627.          break;
  628.       case GL_CONVOLUTION_HEIGHT:
  629.          *params = (GLfloat) conv->Height;
  630.          break;
  631.       case GL_MAX_CONVOLUTION_WIDTH:
  632.          *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
  633.          break;
  634.       case GL_MAX_CONVOLUTION_HEIGHT:
  635.          *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
  636.          break;
  637.       default:
  638.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
  639.          return;
  640.    }
  641. }
  642.  
  643.  
  644. void
  645. _mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
  646. {
  647.    GET_CURRENT_CONTEXT(ctx);
  648.    const struct gl_convolution_attrib *conv;
  649.    GLuint c;
  650.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  651.  
  652.    switch (target) {
  653.       case GL_CONVOLUTION_1D:
  654.          c = 0;
  655.          conv = &ctx->Convolution1D;
  656.          break;
  657.       case GL_CONVOLUTION_2D:
  658.          c = 1;
  659.          conv = &ctx->Convolution2D;
  660.          break;
  661.       case GL_SEPARABLE_2D:
  662.          c = 2;
  663.          conv = &ctx->Separable2D;
  664.          break;
  665.       default:
  666.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
  667.          return;
  668.    }
  669.  
  670.    switch (pname) {
  671.       case GL_CONVOLUTION_BORDER_COLOR:
  672.          params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
  673.          params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
  674.          params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
  675.          params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
  676.          break;
  677.       case GL_CONVOLUTION_BORDER_MODE:
  678.          *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
  679.          break;
  680.       case GL_CONVOLUTION_FILTER_SCALE:
  681.          params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
  682.          params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
  683.          params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
  684.          params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
  685.          break;
  686.       case GL_CONVOLUTION_FILTER_BIAS:
  687.          params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
  688.          params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
  689.          params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
  690.          params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
  691.          break;
  692.       case GL_CONVOLUTION_FORMAT:
  693.          *params = (GLint) conv->Format;
  694.          break;
  695.       case GL_CONVOLUTION_WIDTH:
  696.          *params = (GLint) conv->Width;
  697.          break;
  698.       case GL_CONVOLUTION_HEIGHT:
  699.          *params = (GLint) conv->Height;
  700.          break;
  701.       case GL_MAX_CONVOLUTION_WIDTH:
  702.          *params = (GLint) ctx->Const.MaxConvolutionWidth;
  703.          break;
  704.       case GL_MAX_CONVOLUTION_HEIGHT:
  705.          *params = (GLint) ctx->Const.MaxConvolutionHeight;
  706.          break;
  707.       default:
  708.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
  709.          return;
  710.    }
  711. }
  712.  
  713.  
  714. void
  715. _mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
  716. {
  717.    const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
  718.    const struct gl_convolution_attrib *filter;
  719.    GET_CURRENT_CONTEXT(ctx);
  720.    ASSERT_OUTSIDE_BEGIN_END(ctx);
  721.  
  722.    if (ctx->NewState) {
  723.       _mesa_update_state(ctx);
  724.    }
  725.  
  726.    if (target != GL_SEPARABLE_2D) {
  727.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
  728.       return;
  729.    }
  730.  
  731.    if (!_mesa_is_legal_format_and_type(format, type)) {
  732.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
  733.       return;
  734.    }
  735.  
  736.    if (format == GL_COLOR_INDEX ||
  737.        format == GL_STENCIL_INDEX ||
  738.        format == GL_DEPTH_COMPONENT ||
  739.        format == GL_INTENSITY ||
  740.        type == GL_BITMAP) {
  741.       _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
  742.       return;
  743.    }
  744.  
  745.    filter = &ctx->Separable2D;
  746.  
  747.    /* Row filter */
  748.    {
  749.       GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
  750.                                          filter->Height, format, type,
  751.                                          0, 0, 0);
  752.       _mesa_pack_float_rgba_span(ctx, filter->Width,
  753.                                  (const GLfloat (*)[4]) filter->Filter,
  754.                                  format, type, dst, &ctx->Pack, 0);
  755.    }
  756.  
  757.    /* Column filter */
  758.    {
  759.       GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
  760.                                          1, format, type,
  761.                                          0, 0, 0);
  762.       const GLfloat *src = filter->Filter + colStart;
  763.       _mesa_pack_float_rgba_span(ctx, filter->Height,
  764.                                  (const GLfloat (*)[4]) src,
  765.                                  format, type, dst, &ctx->Pack, 0);
  766.    }
  767.  
  768.    (void) span;  /* unused at this time */
  769. }
  770.  
  771.  
  772. void
  773. _mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
  774. {
  775.    const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
  776.    GLint baseFormat;
  777.    GET_CURRENT_CONTEXT(ctx);
  778.    ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
  779.  
  780.    if (target != GL_SEPARABLE_2D) {
  781.       _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
  782.       return;
  783.    }
  784.  
  785.    baseFormat = base_filter_format(internalFormat);
  786.    if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
  787.       _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
  788.       return;
  789.    }
  790.  
  791.    if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
  792.       _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
  793.       return;
  794.    }
  795.    if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
  796.       _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
  797.       return;
  798.    }
  799.  
  800.    if (!_mesa_is_legal_format_and_type(format, type)) {
  801.       _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
  802.       return;
  803.    }
  804.  
  805.    if (format == GL_COLOR_INDEX ||
  806.        format == GL_STENCIL_INDEX ||
  807.        format == GL_DEPTH_COMPONENT ||
  808.        format == GL_INTENSITY ||
  809.        type == GL_BITMAP) {
  810.       _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
  811.       return;
  812.    }
  813.  
  814.    ctx->Separable2D.Format = format;
  815.    ctx->Separable2D.InternalFormat = internalFormat;
  816.    ctx->Separable2D.Width = width;
  817.    ctx->Separable2D.Height = height;
  818.  
  819.    /* unpack row filter */
  820.    _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
  821.                                  ctx->Separable2D.Filter,
  822.                                  format, type, row, &ctx->Unpack,
  823.                                  0, GL_FALSE);
  824.  
  825.    /* apply scale and bias */
  826.    {
  827.       const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
  828.       const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
  829.       GLint i;
  830.       for (i = 0; i < width; i++) {
  831.          GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
  832.          GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
  833.          GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
  834.          GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
  835.          r = r * scale[0] + bias[0];
  836.          g = g * scale[1] + bias[1];
  837.          b = b * scale[2] + bias[2];
  838.          a = a * scale[3] + bias[3];
  839.          ctx->Separable2D.Filter[i * 4 + 0] = r;
  840.          ctx->Separable2D.Filter[i * 4 + 1] = g;
  841.          ctx->Separable2D.Filter[i * 4 + 2] = b;
  842.          ctx->Separable2D.Filter[i * 4 + 3] = a;
  843.       }
  844.    }
  845.  
  846.    /* unpack column filter */
  847.    _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
  848.                                  &ctx->Separable2D.Filter[colStart],
  849.                                  format, type, column, &ctx->Unpack,
  850.                                  0, GL_FALSE);
  851.  
  852.    /* apply scale and bias */
  853.    {
  854.       const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
  855.       const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
  856.       GLint i;
  857.       for (i = 0; i < width; i++) {
  858.          GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
  859.          GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
  860.          GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
  861.          GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
  862.          r = r * scale[0] + bias[0];
  863.          g = g * scale[1] + bias[1];
  864.          b = b * scale[2] + bias[2];
  865.          a = a * scale[3] + bias[3];
  866.          ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
  867.          ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
  868.          ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
  869.          ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
  870.       }
  871.    }
  872.  
  873.    ctx->NewState |= _NEW_PIXEL;
  874. }
  875.  
  876.  
  877. /**********************************************************************/
  878. /***                   image convolution functions                  ***/
  879. /**********************************************************************/
  880.  
  881. static void
  882. convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
  883.                    GLint filterWidth, const GLfloat filter[][4],
  884.                    GLfloat dest[][4])
  885. {
  886.    GLint dstWidth;
  887.    GLint i, n;
  888.  
  889.    if (filterWidth >= 1)
  890.       dstWidth = srcWidth - (filterWidth - 1);
  891.    else
  892.       dstWidth = srcWidth;
  893.  
  894.    if (dstWidth <= 0)
  895.       return;  /* null result */
  896.  
  897.    for (i = 0; i < dstWidth; i++) {
  898.       GLfloat sumR = 0.0;
  899.       GLfloat sumG = 0.0;
  900.       GLfloat sumB = 0.0;
  901.       GLfloat sumA = 0.0;
  902.       for (n = 0; n < filterWidth; n++) {
  903.          sumR += src[i + n][RCOMP] * filter[n][RCOMP];
  904.          sumG += src[i + n][GCOMP] * filter[n][GCOMP];
  905.          sumB += src[i + n][BCOMP] * filter[n][BCOMP];
  906.          sumA += src[i + n][ACOMP] * filter[n][ACOMP];
  907.       }
  908.       dest[i][RCOMP] = sumR;
  909.       dest[i][GCOMP] = sumG;
  910.       dest[i][BCOMP] = sumB;
  911.       dest[i][ACOMP] = sumA;
  912.    }
  913. }
  914.  
  915.  
  916. static void
  917. convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
  918.                      GLint filterWidth, const GLfloat filter[][4],
  919.                      GLfloat dest[][4],
  920.                      const GLfloat borderColor[4])
  921. {
  922.    const GLint halfFilterWidth = filterWidth / 2;
  923.    GLint i, n;
  924.  
  925.    for (i = 0; i < srcWidth; i++) {
  926.       GLfloat sumR = 0.0;
  927.       GLfloat sumG = 0.0;
  928.       GLfloat sumB = 0.0;
  929.       GLfloat sumA = 0.0;
  930.       for (n = 0; n < filterWidth; n++) {
  931.          if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
  932.             sumR += borderColor[RCOMP] * filter[n][RCOMP];
  933.             sumG += borderColor[GCOMP] * filter[n][GCOMP];
  934.             sumB += borderColor[BCOMP] * filter[n][BCOMP];
  935.             sumA += borderColor[ACOMP] * filter[n][ACOMP];
  936.          }
  937.          else {
  938.             sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
  939.             sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
  940.             sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
  941.             sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
  942.          }
  943.       }
  944.       dest[i][RCOMP] = sumR;
  945.       dest[i][GCOMP] = sumG;
  946.       dest[i][BCOMP] = sumB;
  947.       dest[i][ACOMP] = sumA;
  948.    }
  949. }
  950.  
  951.  
  952. static void
  953. convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
  954.                       GLint filterWidth, const GLfloat filter[][4],
  955.                       GLfloat dest[][4])
  956. {
  957.    const GLint halfFilterWidth = filterWidth / 2;
  958.    GLint i, n;
  959.  
  960.    for (i = 0; i < srcWidth; i++) {
  961.       GLfloat sumR = 0.0;
  962.       GLfloat sumG = 0.0;
  963.       GLfloat sumB = 0.0;
  964.       GLfloat sumA = 0.0;
  965.       for (n = 0; n < filterWidth; n++) {
  966.          if (i + n < halfFilterWidth) {
  967.             sumR += src[0][RCOMP] * filter[n][RCOMP];
  968.             sumG += src[0][GCOMP] * filter[n][GCOMP];
  969.             sumB += src[0][BCOMP] * filter[n][BCOMP];
  970.             sumA += src[0][ACOMP] * filter[n][ACOMP];
  971.          }
  972.          else if (i + n - halfFilterWidth >= srcWidth) {
  973.             sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
  974.             sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
  975.             sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
  976.             sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
  977.          }
  978.          else {
  979.             sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
  980.             sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
  981.             sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
  982.             sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
  983.          }
  984.       }
  985.       dest[i][RCOMP] = sumR;
  986.       dest[i][GCOMP] = sumG;
  987.       dest[i][BCOMP] = sumB;
  988.       dest[i][ACOMP] = sumA;
  989.    }
  990. }
  991.  
  992.  
  993. static void
  994. convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
  995.                    const GLfloat src[][4],
  996.                    GLint filterWidth, GLint filterHeight,
  997.                    const GLfloat filter[][4],
  998.                    GLfloat dest[][4])
  999. {
  1000.    GLint dstWidth, dstHeight;
  1001.    GLint i, j, n, m;
  1002.  
  1003.    if (filterWidth >= 1)
  1004.       dstWidth = srcWidth - (filterWidth - 1);
  1005.    else
  1006.       dstWidth = srcWidth;
  1007.  
  1008.    if (filterHeight >= 1)
  1009.       dstHeight = srcHeight - (filterHeight - 1);
  1010.    else
  1011.       dstHeight = srcHeight;
  1012.  
  1013.    if (dstWidth <= 0 || dstHeight <= 0)
  1014.       return;
  1015.  
  1016.    for (j = 0; j < dstHeight; j++) {
  1017.       for (i = 0; i < dstWidth; i++) {
  1018.          GLfloat sumR = 0.0;
  1019.          GLfloat sumG = 0.0;
  1020.          GLfloat sumB = 0.0;
  1021.          GLfloat sumA = 0.0;
  1022.          for (m = 0; m < filterHeight; m++) {
  1023.             for (n = 0; n < filterWidth; n++) {
  1024.                const GLint k = (j + m) * srcWidth + i + n;
  1025.                const GLint f = m * filterWidth + n;
  1026.                sumR += src[k][RCOMP] * filter[f][RCOMP];
  1027.                sumG += src[k][GCOMP] * filter[f][GCOMP];
  1028.                sumB += src[k][BCOMP] * filter[f][BCOMP];
  1029.                sumA += src[k][ACOMP] * filter[f][ACOMP];
  1030.             }
  1031.          }
  1032.          dest[j * dstWidth + i][RCOMP] = sumR;
  1033.          dest[j * dstWidth + i][GCOMP] = sumG;
  1034.          dest[j * dstWidth + i][BCOMP] = sumB;
  1035.          dest[j * dstWidth + i][ACOMP] = sumA;
  1036.       }
  1037.    }
  1038. }
  1039.  
  1040.  
  1041. static void
  1042. convolve_2d_constant(GLint srcWidth, GLint srcHeight,
  1043.                      const GLfloat src[][4],
  1044.                      GLint filterWidth, GLint filterHeight,
  1045.                      const GLfloat filter[][4],
  1046.                      GLfloat dest[][4],
  1047.                      const GLfloat borderColor[4])
  1048. {
  1049.    const GLint halfFilterWidth = filterWidth / 2;
  1050.    const GLint halfFilterHeight = filterHeight / 2;
  1051.    GLint i, j, n, m;
  1052.  
  1053.    for (j = 0; j < srcHeight; j++) {
  1054.       for (i = 0; i < srcWidth; i++) {
  1055.          GLfloat sumR = 0.0;
  1056.          GLfloat sumG = 0.0;
  1057.          GLfloat sumB = 0.0;
  1058.          GLfloat sumA = 0.0;
  1059.          for (m = 0; m < filterHeight; m++) {
  1060.             for (n = 0; n < filterWidth; n++) {
  1061.                const GLint f = m * filterWidth + n;
  1062.                const GLint is = i + n - halfFilterWidth;
  1063.                const GLint js = j + m - halfFilterHeight;
  1064.                if (is < 0 || is >= srcWidth ||
  1065.                    js < 0 || js >= srcHeight) {
  1066.                   sumR += borderColor[RCOMP] * filter[f][RCOMP];
  1067.                   sumG += borderColor[GCOMP] * filter[f][GCOMP];
  1068.                   sumB += borderColor[BCOMP] * filter[f][BCOMP];
  1069.                   sumA += borderColor[ACOMP] * filter[f][ACOMP];
  1070.                }
  1071.                else {
  1072.                   const GLint k = js * srcWidth + is;
  1073.                   sumR += src[k][RCOMP] * filter[f][RCOMP];
  1074.                   sumG += src[k][GCOMP] * filter[f][GCOMP];
  1075.                   sumB += src[k][BCOMP] * filter[f][BCOMP];
  1076.                   sumA += src[k][ACOMP] * filter[f][ACOMP];
  1077.                }
  1078.             }
  1079.          }
  1080.          dest[j * srcWidth + i][RCOMP] = sumR;
  1081.          dest[j * srcWidth + i][GCOMP] = sumG;
  1082.          dest[j * srcWidth + i][BCOMP] = sumB;
  1083.          dest[j * srcWidth + i][ACOMP] = sumA;
  1084.       }
  1085.    }
  1086. }
  1087.  
  1088.  
  1089. static void
  1090. convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
  1091.                       const GLfloat src[][4],
  1092.                       GLint filterWidth, GLint filterHeight,
  1093.                       const GLfloat filter[][4],
  1094.                       GLfloat dest[][4])
  1095. {
  1096.    const GLint halfFilterWidth = filterWidth / 2;
  1097.    const GLint halfFilterHeight = filterHeight / 2;
  1098.    GLint i, j, n, m;
  1099.  
  1100.    for (j = 0; j < srcHeight; j++) {
  1101.       for (i = 0; i < srcWidth; i++) {
  1102.          GLfloat sumR = 0.0;
  1103.          GLfloat sumG = 0.0;
  1104.          GLfloat sumB = 0.0;
  1105.          GLfloat sumA = 0.0;
  1106.          for (m = 0; m < filterHeight; m++) {
  1107.             for (n = 0; n < filterWidth; n++) {
  1108.                const GLint f = m * filterWidth + n;
  1109.                GLint is = i + n - halfFilterWidth;
  1110.                GLint js = j + m - halfFilterHeight;
  1111.                GLint k;
  1112.                if (is < 0)
  1113.                   is = 0;
  1114.                else if (is >= srcWidth)
  1115.                   is = srcWidth - 1;
  1116.                if (js < 0)
  1117.                   js = 0;
  1118.                else if (js >= srcHeight)
  1119.                   js = srcHeight - 1;
  1120.                k = js * srcWidth + is;
  1121.                sumR += src[k][RCOMP] * filter[f][RCOMP];
  1122.                sumG += src[k][GCOMP] * filter[f][GCOMP];
  1123.                sumB += src[k][BCOMP] * filter[f][BCOMP];
  1124.                sumA += src[k][ACOMP] * filter[f][ACOMP];
  1125.             }
  1126.          }
  1127.          dest[j * srcWidth + i][RCOMP] = sumR;
  1128.          dest[j * srcWidth + i][GCOMP] = sumG;
  1129.          dest[j * srcWidth + i][BCOMP] = sumB;
  1130.          dest[j * srcWidth + i][ACOMP] = sumA;
  1131.       }
  1132.    }
  1133. }
  1134.  
  1135.  
  1136. static void
  1137. convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
  1138.                     const GLfloat src[][4],
  1139.                     GLint filterWidth, GLint filterHeight,
  1140.                     const GLfloat rowFilt[][4],
  1141.                     const GLfloat colFilt[][4],
  1142.                     GLfloat dest[][4])
  1143. {
  1144.    GLint dstWidth, dstHeight;
  1145.    GLint i, j, n, m;
  1146.  
  1147.    if (filterWidth >= 1)
  1148.       dstWidth = srcWidth - (filterWidth - 1);
  1149.    else
  1150.       dstWidth = srcWidth;
  1151.  
  1152.    if (filterHeight >= 1)
  1153.       dstHeight = srcHeight - (filterHeight - 1);
  1154.    else
  1155.       dstHeight = srcHeight;
  1156.  
  1157.    if (dstWidth <= 0 || dstHeight <= 0)
  1158.       return;
  1159.  
  1160.    for (j = 0; j < dstHeight; j++) {
  1161.       for (i = 0; i < dstWidth; i++) {
  1162.          GLfloat sumR = 0.0;
  1163.          GLfloat sumG = 0.0;
  1164.          GLfloat sumB = 0.0;
  1165.          GLfloat sumA = 0.0;
  1166.          for (m = 0; m < filterHeight; m++) {
  1167.             for (n = 0; n < filterWidth; n++) {
  1168.                GLint k = (j + m) * srcWidth + i + n;
  1169.                sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
  1170.                sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
  1171.                sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
  1172.                sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
  1173.             }
  1174.          }
  1175.          dest[j * dstWidth + i][RCOMP] = sumR;
  1176.          dest[j * dstWidth + i][GCOMP] = sumG;
  1177.          dest[j * dstWidth + i][BCOMP] = sumB;
  1178.          dest[j * dstWidth + i][ACOMP] = sumA;
  1179.       }
  1180.    }
  1181. }
  1182.  
  1183.  
  1184. static void
  1185. convolve_sep_constant(GLint srcWidth, GLint srcHeight,
  1186.                       const GLfloat src[][4],
  1187.                       GLint filterWidth, GLint filterHeight,
  1188.                       const GLfloat rowFilt[][4],
  1189.                       const GLfloat colFilt[][4],
  1190.                       GLfloat dest[][4],
  1191.                       const GLfloat borderColor[4])
  1192. {
  1193.    const GLint halfFilterWidth = filterWidth / 2;
  1194.    const GLint halfFilterHeight = filterHeight / 2;
  1195.    GLint i, j, n, m;
  1196.  
  1197.    for (j = 0; j < srcHeight; j++) {
  1198.       for (i = 0; i < srcWidth; i++) {
  1199.          GLfloat sumR = 0.0;
  1200.          GLfloat sumG = 0.0;
  1201.          GLfloat sumB = 0.0;
  1202.          GLfloat sumA = 0.0;
  1203.          for (m = 0; m < filterHeight; m++) {
  1204.             for (n = 0; n < filterWidth; n++) {
  1205.                const GLint is = i + n - halfFilterWidth;
  1206.                const GLint js = j + m - halfFilterHeight;
  1207.                if (is < 0 || is >= srcWidth ||
  1208.                    js < 0 || js >= srcHeight) {
  1209.                   sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
  1210.                   sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
  1211.                   sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
  1212.                   sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
  1213.                }
  1214.                else {
  1215.                   GLint k = js * srcWidth + is;
  1216.                   sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
  1217.                   sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
  1218.                   sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
  1219.                   sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
  1220.                }
  1221.  
  1222.             }
  1223.          }
  1224.          dest[j * srcWidth + i][RCOMP] = sumR;
  1225.          dest[j * srcWidth + i][GCOMP] = sumG;
  1226.          dest[j * srcWidth + i][BCOMP] = sumB;
  1227.          dest[j * srcWidth + i][ACOMP] = sumA;
  1228.       }
  1229.    }
  1230. }
  1231.  
  1232.  
  1233. static void
  1234. convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
  1235.                        const GLfloat src[][4],
  1236.                        GLint filterWidth, GLint filterHeight,
  1237.                        const GLfloat rowFilt[][4],
  1238.                        const GLfloat colFilt[][4],
  1239.                        GLfloat dest[][4])
  1240. {
  1241.    const GLint halfFilterWidth = filterWidth / 2;
  1242.    const GLint halfFilterHeight = filterHeight / 2;
  1243.    GLint i, j, n, m;
  1244.  
  1245.    for (j = 0; j < srcHeight; j++) {
  1246.       for (i = 0; i < srcWidth; i++) {
  1247.          GLfloat sumR = 0.0;
  1248.          GLfloat sumG = 0.0;
  1249.          GLfloat sumB = 0.0;
  1250.          GLfloat sumA = 0.0;
  1251.          for (m = 0; m < filterHeight; m++) {
  1252.             for (n = 0; n < filterWidth; n++) {
  1253.                GLint is = i + n - halfFilterWidth;
  1254.                GLint js = j + m - halfFilterHeight;
  1255.                GLint k;
  1256.                if (is < 0)
  1257.                   is = 0;
  1258.                else if (is >= srcWidth)
  1259.                   is = srcWidth - 1;
  1260.                if (js < 0)
  1261.                   js = 0;
  1262.                else if (js >= srcHeight)
  1263.                   js = srcHeight - 1;
  1264.                k = js * srcWidth + is;
  1265.                sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
  1266.                sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
  1267.                sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
  1268.                sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
  1269.             }
  1270.          }
  1271.          dest[j * srcWidth + i][RCOMP] = sumR;
  1272.          dest[j * srcWidth + i][GCOMP] = sumG;
  1273.          dest[j * srcWidth + i][BCOMP] = sumB;
  1274.          dest[j * srcWidth + i][ACOMP] = sumA;
  1275.       }
  1276.    }
  1277. }
  1278.  
  1279.  
  1280.  
  1281. void
  1282. _mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
  1283.                         const GLfloat *srcImage, GLfloat *dstImage)
  1284. {
  1285.    switch (ctx->Pixel.ConvolutionBorderMode[0]) {
  1286.       case GL_REDUCE:
  1287.          convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
  1288.                             ctx->Convolution1D.Width,
  1289.                             (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
  1290.                             (GLfloat (*)[4]) dstImage);
  1291.          *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
  1292.          break;
  1293.       case GL_CONSTANT_BORDER:
  1294.          convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
  1295.                               ctx->Convolution1D.Width,
  1296.                               (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
  1297.                               (GLfloat (*)[4]) dstImage,
  1298.                               ctx->Pixel.ConvolutionBorderColor[0]);
  1299.          break;
  1300.       case GL_REPLICATE_BORDER:
  1301.          convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
  1302.                               ctx->Convolution1D.Width,
  1303.                               (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
  1304.                               (GLfloat (*)[4]) dstImage);
  1305.          break;
  1306.       default:
  1307.          ;
  1308.    }
  1309. }
  1310.  
  1311.  
  1312. void
  1313. _mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
  1314.                         const GLfloat *srcImage, GLfloat *dstImage)
  1315. {
  1316.    switch (ctx->Pixel.ConvolutionBorderMode[1]) {
  1317.       case GL_REDUCE:
  1318.          convolve_2d_reduce(*width, *height,
  1319.                             (const GLfloat (*)[4]) srcImage,
  1320.                             ctx->Convolution2D.Width,
  1321.                             ctx->Convolution2D.Height,
  1322.                             (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
  1323.                             (GLfloat (*)[4]) dstImage);
  1324.          *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
  1325.          *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
  1326.          break;
  1327.       case GL_CONSTANT_BORDER:
  1328.          convolve_2d_constant(*width, *height,
  1329.                               (const GLfloat (*)[4]) srcImage,
  1330.                               ctx->Convolution2D.Width,
  1331.                               ctx->Convolution2D.Height,
  1332.                               (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
  1333.                               (GLfloat (*)[4]) dstImage,
  1334.                               ctx->Pixel.ConvolutionBorderColor[1]);
  1335.          break;
  1336.       case GL_REPLICATE_BORDER:
  1337.          convolve_2d_replicate(*width, *height,
  1338.                                (const GLfloat (*)[4]) srcImage,
  1339.                                ctx->Convolution2D.Width,
  1340.                                ctx->Convolution2D.Height,
  1341.                                (const GLfloat (*)[4])ctx->Convolution2D.Filter,
  1342.                                (GLfloat (*)[4]) dstImage);
  1343.          break;
  1344.       default:
  1345.          ;
  1346.       }
  1347. }
  1348.  
  1349.  
  1350. void
  1351. _mesa_convolve_sep_image(const GLcontext *ctx,
  1352.                          GLsizei *width, GLsizei *height,
  1353.                          const GLfloat *srcImage, GLfloat *dstImage)
  1354. {
  1355.    const GLfloat *rowFilter = ctx->Separable2D.Filter;
  1356.    const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
  1357.  
  1358.    switch (ctx->Pixel.ConvolutionBorderMode[2]) {
  1359.       case GL_REDUCE:
  1360.          convolve_sep_reduce(*width, *height,
  1361.                              (const GLfloat (*)[4]) srcImage,
  1362.                              ctx->Separable2D.Width,
  1363.                              ctx->Separable2D.Height,
  1364.                              (const GLfloat (*)[4]) rowFilter,
  1365.                              (const GLfloat (*)[4]) colFilter,
  1366.                              (GLfloat (*)[4]) dstImage);
  1367.          *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
  1368.          *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
  1369.          break;
  1370.       case GL_CONSTANT_BORDER:
  1371.          convolve_sep_constant(*width, *height,
  1372.                                (const GLfloat (*)[4]) srcImage,
  1373.                                ctx->Separable2D.Width,
  1374.                                ctx->Separable2D.Height,
  1375.                                (const GLfloat (*)[4]) rowFilter,
  1376.                                (const GLfloat (*)[4]) colFilter,
  1377.                                (GLfloat (*)[4]) dstImage,
  1378.                                ctx->Pixel.ConvolutionBorderColor[2]);
  1379.          break;
  1380.       case GL_REPLICATE_BORDER:
  1381.          convolve_sep_replicate(*width, *height,
  1382.                                 (const GLfloat (*)[4]) srcImage,
  1383.                                 ctx->Separable2D.Width,
  1384.                                 ctx->Separable2D.Height,
  1385.                                 (const GLfloat (*)[4]) rowFilter,
  1386.                                 (const GLfloat (*)[4]) colFilter,
  1387.                                 (GLfloat (*)[4]) dstImage);
  1388.          break;
  1389.       default:
  1390.          ;
  1391.    }
  1392. }
  1393.  
  1394.  
  1395.  
  1396. /*
  1397.  * This function computes an image's size after convolution.
  1398.  * If the convolution border mode is GL_REDUCE, the post-convolution
  1399.  * image will be smaller than the original.
  1400.  */
  1401. void
  1402. _mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
  1403.                                    GLsizei *width, GLsizei *height)
  1404. {
  1405.    if (ctx->Pixel.Convolution1DEnabled
  1406.        && dimensions == 1
  1407.        && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
  1408.       *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
  1409.    }
  1410.    else if (ctx->Pixel.Convolution2DEnabled
  1411.             && dimensions > 1
  1412.             && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
  1413.       *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
  1414.       *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
  1415.    }
  1416.    else if (ctx->Pixel.Separable2DEnabled
  1417.             && dimensions > 1
  1418.             && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
  1419.       *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
  1420.       *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
  1421.    }
  1422. }
  1423.