blob: faea445e4c8a7ab8f2abd6129707b63a9f147a16 [file] [log] [blame]
Brian Paul8acb7e92001-05-09 22:24:22 +00001/* $Id: convolve.c,v 1.24 2001/05/09 22:24:22 brianp Exp $ */
Brian Paulcc8e37f2000-07-12 13:00:09 +00002
3/*
4 * Mesa 3-D graphics library
Brian Pauld4b799b2000-08-21 14:24:30 +00005 * Version: 3.5
Brian Paulcc8e37f2000-07-12 13:00:09 +00006 *
Brian Paul16461f72001-02-06 17:22:16 +00007 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
Brian Paulcc8e37f2000-07-12 13:00:09 +00008 *
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#ifdef PC_HEADER
37#include "all.h"
38#else
39#include "glheader.h"
Brian Paulc893a012000-10-28 20:41:13 +000040#include "colormac.h"
Brian Pauld4b799b2000-08-21 14:24:30 +000041#include "convolve.h"
42#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000043#include "image.h"
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +000044#include "mtypes.h"
Jon Taylorcdfba5d2000-11-23 02:50:56 +000045#include "state.h"
Brian Paulba41b8a2000-11-10 17:45:15 +000046#include "swrast/s_span.h" /* XXX SWRAST hack */
Brian Paulcc8e37f2000-07-12 13:00:09 +000047#endif
48
49
Brian Paul147b0832000-08-23 14:31:25 +000050/*
51 * Given an internalFormat token passed to glConvolutionFilter
52 * or glSeparableFilter, return the corresponding base format.
53 * Return -1 if invalid token.
54 */
55static GLint
56base_filter_format( GLenum format )
57{
58 switch (format) {
59 case GL_ALPHA:
60 case GL_ALPHA4:
61 case GL_ALPHA8:
62 case GL_ALPHA12:
63 case GL_ALPHA16:
64 return GL_ALPHA;
65 case GL_LUMINANCE:
66 case GL_LUMINANCE4:
67 case GL_LUMINANCE8:
68 case GL_LUMINANCE12:
69 case GL_LUMINANCE16:
70 return GL_LUMINANCE;
71 case GL_LUMINANCE_ALPHA:
72 case GL_LUMINANCE4_ALPHA4:
73 case GL_LUMINANCE6_ALPHA2:
74 case GL_LUMINANCE8_ALPHA8:
75 case GL_LUMINANCE12_ALPHA4:
76 case GL_LUMINANCE12_ALPHA12:
77 case GL_LUMINANCE16_ALPHA16:
78 return GL_LUMINANCE_ALPHA;
79 case GL_INTENSITY:
80 case GL_INTENSITY4:
81 case GL_INTENSITY8:
82 case GL_INTENSITY12:
83 case GL_INTENSITY16:
84 return GL_INTENSITY;
85 case GL_RGB:
86 case GL_R3_G3_B2:
87 case GL_RGB4:
88 case GL_RGB5:
89 case GL_RGB8:
90 case GL_RGB10:
91 case GL_RGB12:
92 case GL_RGB16:
93 return GL_RGB;
94 case 4:
95 case GL_RGBA:
96 case GL_RGBA2:
97 case GL_RGBA4:
98 case GL_RGB5_A1:
99 case GL_RGBA8:
100 case GL_RGB10_A2:
101 case GL_RGBA12:
102 case GL_RGBA16:
103 return GL_RGBA;
104 default:
105 return -1; /* error */
106 }
107}
108
109
110void
111_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
112{
113 GLenum baseFormat;
114 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000115 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000116
117 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000118 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000119 return;
120 }
121
122 baseFormat = base_filter_format(internalFormat);
123 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000124 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000125 return;
126 }
127
128 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000129 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000130 return;
131 }
132
Brian Paul90f042a2000-12-10 19:23:19 +0000133 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000134 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000135 return;
136 }
137
138 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000139 format == GL_STENCIL_INDEX ||
140 format == GL_DEPTH_COMPONENT ||
141 format == GL_INTENSITY ||
142 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000143 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000144 return;
145 }
146
147 ctx->Convolution1D.Format = format;
148 ctx->Convolution1D.InternalFormat = internalFormat;
149 ctx->Convolution1D.Width = width;
150 ctx->Convolution1D.Height = 1;
151
152 /* unpack filter image */
153 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
154 ctx->Convolution1D.Filter,
155 format, type, image, &ctx->Unpack,
156 0, GL_FALSE);
157
158 /* apply scale and bias */
159 {
160 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
161 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
162 GLint i;
163 for (i = 0; i < width; i++) {
164 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
165 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
166 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
167 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
168 r = r * scale[0] + bias[0];
169 g = g * scale[1] + bias[1];
170 b = b * scale[2] + bias[2];
171 a = a * scale[3] + bias[3];
172 ctx->Convolution1D.Filter[i * 4 + 0] = r;
173 ctx->Convolution1D.Filter[i * 4 + 1] = g;
174 ctx->Convolution1D.Filter[i * 4 + 2] = b;
175 ctx->Convolution1D.Filter[i * 4 + 3] = a;
176 }
177 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000178
Brian Paulb5012e12000-11-10 18:31:04 +0000179 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000180}
181
182
183void
184_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
185{
186 GLenum baseFormat;
187 GLint i, components;
188 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000189 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000190
191 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000192 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000193 return;
194 }
195
196 baseFormat = base_filter_format(internalFormat);
197 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000198 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000199 return;
200 }
201
202 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000203 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000204 return;
205 }
206 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000207 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000208 return;
209 }
210
Brian Paul90f042a2000-12-10 19:23:19 +0000211 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000212 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000213 return;
214 }
215 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000216 format == GL_STENCIL_INDEX ||
217 format == GL_DEPTH_COMPONENT ||
218 format == GL_INTENSITY ||
219 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000220 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000221 return;
222 }
223
224 components = _mesa_components_in_format(format);
225 assert(components > 0); /* this should have been caught earlier */
226
227 ctx->Convolution2D.Format = format;
228 ctx->Convolution2D.InternalFormat = internalFormat;
229 ctx->Convolution2D.Width = width;
230 ctx->Convolution2D.Height = height;
231
232 /* Unpack filter image. We always store filters in RGBA format. */
233 for (i = 0; i < height; i++) {
234 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
235 height, format, type, 0, i, 0);
236 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
237 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
238 format, type, src, &ctx->Unpack,
239 0, GL_FALSE);
240 }
241
242 /* apply scale and bias */
243 {
244 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
245 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
Brian Paul8acb7e92001-05-09 22:24:22 +0000246 for (i = 0; i < width * height; i++) {
Brian Paul147b0832000-08-23 14:31:25 +0000247 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
248 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
249 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
250 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
251 r = r * scale[0] + bias[0];
252 g = g * scale[1] + bias[1];
253 b = b * scale[2] + bias[2];
254 a = a * scale[3] + bias[3];
255 ctx->Convolution2D.Filter[i * 4 + 0] = r;
256 ctx->Convolution2D.Filter[i * 4 + 1] = g;
257 ctx->Convolution2D.Filter[i * 4 + 2] = b;
258 ctx->Convolution2D.Filter[i * 4 + 3] = a;
259 }
260 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000261
Brian Paulb5012e12000-11-10 18:31:04 +0000262 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000263}
264
265
266void
267_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
268{
269 GET_CURRENT_CONTEXT(ctx);
270 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000271 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000272
273 switch (target) {
274 case GL_CONVOLUTION_1D:
275 c = 0;
276 break;
277 case GL_CONVOLUTION_2D:
278 c = 1;
279 break;
280 case GL_SEPARABLE_2D:
281 c = 2;
282 break;
283 default:
Brian Paul08836342001-03-03 20:33:27 +0000284 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000285 return;
286 }
287
288 switch (pname) {
289 case GL_CONVOLUTION_BORDER_MODE:
290 if (param == (GLfloat) GL_REDUCE ||
291 param == (GLfloat) GL_CONSTANT_BORDER ||
292 param == (GLfloat) GL_REPLICATE_BORDER) {
293 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
294 }
295 else {
Brian Paul08836342001-03-03 20:33:27 +0000296 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000297 return;
298 }
299 break;
300 default:
Brian Paul08836342001-03-03 20:33:27 +0000301 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000302 return;
303 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000304
305 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000306}
307
308
309void
310_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
311{
312 GET_CURRENT_CONTEXT(ctx);
313 struct gl_convolution_attrib *conv;
314 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000315 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000316
317 switch (target) {
318 case GL_CONVOLUTION_1D:
319 c = 0;
320 conv = &ctx->Convolution1D;
321 break;
322 case GL_CONVOLUTION_2D:
323 c = 1;
324 conv = &ctx->Convolution2D;
325 break;
326 case GL_SEPARABLE_2D:
327 c = 2;
328 conv = &ctx->Separable2D;
329 break;
330 default:
Brian Paul08836342001-03-03 20:33:27 +0000331 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000332 return;
333 }
334
335 switch (pname) {
336 case GL_CONVOLUTION_BORDER_COLOR:
337 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
338 break;
339 case GL_CONVOLUTION_BORDER_MODE:
340 if (params[0] == (GLfloat) GL_REDUCE ||
341 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
342 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
343 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
344 }
345 else {
Brian Paul08836342001-03-03 20:33:27 +0000346 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000347 return;
348 }
349 break;
350 case GL_CONVOLUTION_FILTER_SCALE:
351 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
352 break;
353 case GL_CONVOLUTION_FILTER_BIAS:
354 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
355 break;
356 default:
Brian Paul08836342001-03-03 20:33:27 +0000357 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000358 return;
359 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000360
361 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000362}
363
364
365void
366_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
367{
368 GET_CURRENT_CONTEXT(ctx);
369 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000370 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000371
372 switch (target) {
373 case GL_CONVOLUTION_1D:
374 c = 0;
375 break;
376 case GL_CONVOLUTION_2D:
377 c = 1;
378 break;
379 case GL_SEPARABLE_2D:
380 c = 2;
381 break;
382 default:
Brian Paul08836342001-03-03 20:33:27 +0000383 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000384 return;
385 }
386
387 switch (pname) {
388 case GL_CONVOLUTION_BORDER_MODE:
389 if (param == (GLint) GL_REDUCE ||
390 param == (GLint) GL_CONSTANT_BORDER ||
391 param == (GLint) GL_REPLICATE_BORDER) {
392 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
393 }
394 else {
Brian Paul08836342001-03-03 20:33:27 +0000395 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000396 return;
397 }
398 break;
399 default:
Brian Paul08836342001-03-03 20:33:27 +0000400 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000401 return;
402 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000403
404 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000405}
406
407
408void
409_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
410{
411 GET_CURRENT_CONTEXT(ctx);
412 struct gl_convolution_attrib *conv;
413 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000414 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000415
416 switch (target) {
417 case GL_CONVOLUTION_1D:
418 c = 0;
419 conv = &ctx->Convolution1D;
420 break;
421 case GL_CONVOLUTION_2D:
422 c = 1;
423 conv = &ctx->Convolution2D;
424 break;
425 case GL_SEPARABLE_2D:
426 c = 2;
427 conv = &ctx->Separable2D;
428 break;
429 default:
Brian Paul08836342001-03-03 20:33:27 +0000430 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000431 return;
432 }
433
434 switch (pname) {
435 case GL_CONVOLUTION_BORDER_COLOR:
436 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
437 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
438 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
439 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
440 break;
441 case GL_CONVOLUTION_BORDER_MODE:
442 if (params[0] == (GLint) GL_REDUCE ||
443 params[0] == (GLint) GL_CONSTANT_BORDER ||
444 params[0] == (GLint) GL_REPLICATE_BORDER) {
445 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
446 }
447 else {
Brian Paul08836342001-03-03 20:33:27 +0000448 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000449 return;
450 }
451 break;
452 case GL_CONVOLUTION_FILTER_SCALE:
453 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
454 break;
455 case GL_CONVOLUTION_FILTER_BIAS:
456 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
457 break;
458 default:
Brian Paul08836342001-03-03 20:33:27 +0000459 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000460 return;
461 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000462
463 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000464}
465
466
467void
468_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
469{
470 GLenum baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000471 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000472 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000473
474 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000475 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000476 return;
477 }
478
479 baseFormat = base_filter_format(internalFormat);
480 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000481 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000482 return;
483 }
484
485 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000486 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000487 return;
488 }
489
Keith Whitwell70989242001-03-19 02:25:35 +0000490 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
491 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000492}
493
494
495void
496_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
497{
498 GLenum baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000499 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000500 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000501
502 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000503 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000504 return;
505 }
506
507 baseFormat = base_filter_format(internalFormat);
508 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000509 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000510 return;
511 }
512
513 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000514 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000515 return;
516 }
517 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000518 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000519 return;
520 }
521
Keith Whitwell70989242001-03-19 02:25:35 +0000522 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
523 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000524
Brian Paul147b0832000-08-23 14:31:25 +0000525}
526
527
528void
529_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
530{
Brian Paulf75d6972000-09-05 20:28:56 +0000531 const struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000532 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000533 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000534 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000535
Brian Paul0c000ec2000-11-21 23:26:13 +0000536 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000537 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000538 }
539
Brian Paul90f042a2000-12-10 19:23:19 +0000540 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000541 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000542 return;
543 }
544
545 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000546 format == GL_STENCIL_INDEX ||
547 format == GL_DEPTH_COMPONENT ||
548 format == GL_INTENSITY ||
549 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000550 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000551 return;
552 }
553
Brian Paulf75d6972000-09-05 20:28:56 +0000554 switch (target) {
555 case GL_CONVOLUTION_1D:
556 filter = &(ctx->Convolution1D);
557 break;
558 case GL_CONVOLUTION_2D:
559 filter = &(ctx->Convolution2D);
560 break;
561 default:
Brian Paul08836342001-03-03 20:33:27 +0000562 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000563 return;
564 }
565
566 for (row = 0; row < filter->Height; row++) {
567 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
568 filter->Height, format, type,
569 0, row, 0);
570 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paulf75d6972000-09-05 20:28:56 +0000571 _mesa_pack_float_rgba_span(ctx, filter->Width,
572 (const GLfloat (*)[4]) src,
573 format, type, dst, &ctx->Pack, 0);
574 }
Brian Paul147b0832000-08-23 14:31:25 +0000575}
576
577
578void
579_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
580{
581 GET_CURRENT_CONTEXT(ctx);
582 const struct gl_convolution_attrib *conv;
583 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000584 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000585
586 switch (target) {
587 case GL_CONVOLUTION_1D:
588 c = 0;
589 conv = &ctx->Convolution1D;
590 break;
591 case GL_CONVOLUTION_2D:
592 c = 1;
593 conv = &ctx->Convolution2D;
594 break;
595 case GL_SEPARABLE_2D:
596 c = 2;
597 conv = &ctx->Separable2D;
598 break;
599 default:
Brian Paul08836342001-03-03 20:33:27 +0000600 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000601 return;
602 }
603
604 switch (pname) {
605 case GL_CONVOLUTION_BORDER_COLOR:
606 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
607 break;
608 case GL_CONVOLUTION_BORDER_MODE:
609 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
610 break;
611 case GL_CONVOLUTION_FILTER_SCALE:
612 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
613 break;
614 case GL_CONVOLUTION_FILTER_BIAS:
615 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
616 break;
617 case GL_CONVOLUTION_FORMAT:
618 *params = (GLfloat) conv->Format;
619 break;
620 case GL_CONVOLUTION_WIDTH:
621 *params = (GLfloat) conv->Width;
622 break;
623 case GL_CONVOLUTION_HEIGHT:
624 *params = (GLfloat) conv->Height;
625 break;
626 case GL_MAX_CONVOLUTION_WIDTH:
627 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
628 break;
629 case GL_MAX_CONVOLUTION_HEIGHT:
630 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
631 break;
632 default:
Brian Paul08836342001-03-03 20:33:27 +0000633 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000634 return;
635 }
636}
637
638
639void
640_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
641{
642 GET_CURRENT_CONTEXT(ctx);
643 const struct gl_convolution_attrib *conv;
644 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000645 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000646
647 switch (target) {
648 case GL_CONVOLUTION_1D:
649 c = 0;
650 conv = &ctx->Convolution1D;
651 break;
652 case GL_CONVOLUTION_2D:
653 c = 1;
654 conv = &ctx->Convolution2D;
655 break;
656 case GL_SEPARABLE_2D:
657 c = 2;
658 conv = &ctx->Separable2D;
659 break;
660 default:
Brian Paul08836342001-03-03 20:33:27 +0000661 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000662 return;
663 }
664
665 switch (pname) {
666 case GL_CONVOLUTION_BORDER_COLOR:
667 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
668 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
669 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
670 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
671 break;
672 case GL_CONVOLUTION_BORDER_MODE:
673 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
674 break;
675 case GL_CONVOLUTION_FILTER_SCALE:
676 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
677 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
678 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
679 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
680 break;
681 case GL_CONVOLUTION_FILTER_BIAS:
682 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
683 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
684 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
685 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
686 break;
687 case GL_CONVOLUTION_FORMAT:
688 *params = (GLint) conv->Format;
689 break;
690 case GL_CONVOLUTION_WIDTH:
691 *params = (GLint) conv->Width;
692 break;
693 case GL_CONVOLUTION_HEIGHT:
694 *params = (GLint) conv->Height;
695 break;
696 case GL_MAX_CONVOLUTION_WIDTH:
697 *params = (GLint) ctx->Const.MaxConvolutionWidth;
698 break;
699 case GL_MAX_CONVOLUTION_HEIGHT:
700 *params = (GLint) ctx->Const.MaxConvolutionHeight;
701 break;
702 default:
Brian Paul08836342001-03-03 20:33:27 +0000703 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000704 return;
705 }
706}
707
708
709void
710_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
711{
Brian Paulf75d6972000-09-05 20:28:56 +0000712 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
713 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000714 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000715 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000716
Brian Paul0c000ec2000-11-21 23:26:13 +0000717 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000718 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000719 }
720
Brian Paul147b0832000-08-23 14:31:25 +0000721 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000722 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000723 return;
724 }
725
Brian Paul90f042a2000-12-10 19:23:19 +0000726 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000727 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000728 return;
729 }
730
731 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000732 format == GL_STENCIL_INDEX ||
733 format == GL_DEPTH_COMPONENT ||
734 format == GL_INTENSITY ||
735 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000736 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000737 return;
738 }
739
Brian Paulf75d6972000-09-05 20:28:56 +0000740 filter = &ctx->Separable2D;
741
742 /* Row filter */
743 {
744 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
745 filter->Height, format, type,
746 0, 0, 0);
747 _mesa_pack_float_rgba_span(ctx, filter->Width,
748 (const GLfloat (*)[4]) filter->Filter,
749 format, type, dst, &ctx->Pack, 0);
750 }
751
752 /* Column filter */
753 {
754 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
755 1, format, type,
756 0, 0, 0);
757 const GLfloat *src = filter->Filter + colStart;
758 _mesa_pack_float_rgba_span(ctx, filter->Height,
759 (const GLfloat (*)[4]) src,
760 format, type, dst, &ctx->Pack, 0);
761 }
762
763 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000764}
765
766
767void
768_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
769{
770 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
771 GLenum baseFormat;
772 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000773 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000774
775 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000776 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000777 return;
778 }
779
780 baseFormat = base_filter_format(internalFormat);
781 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000782 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000783 return;
784 }
785
786 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000787 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000788 return;
789 }
790 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000791 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000792 return;
793 }
794
Brian Paul90f042a2000-12-10 19:23:19 +0000795 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000796 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000797 return;
798 }
799
800 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000801 format == GL_STENCIL_INDEX ||
802 format == GL_DEPTH_COMPONENT ||
803 format == GL_INTENSITY ||
804 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000805 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000806 return;
807 }
808
809 ctx->Separable2D.Format = format;
810 ctx->Separable2D.InternalFormat = internalFormat;
811 ctx->Separable2D.Width = width;
812 ctx->Separable2D.Height = height;
813
814 /* unpack row filter */
815 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
816 ctx->Separable2D.Filter,
817 format, type, row, &ctx->Unpack,
818 0, GL_FALSE);
819
820 /* apply scale and bias */
821 {
822 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
823 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
824 GLint i;
825 for (i = 0; i < width; i++) {
826 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
827 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
828 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
829 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
830 r = r * scale[0] + bias[0];
831 g = g * scale[1] + bias[1];
832 b = b * scale[2] + bias[2];
833 a = a * scale[3] + bias[3];
834 ctx->Separable2D.Filter[i * 4 + 0] = r;
835 ctx->Separable2D.Filter[i * 4 + 1] = g;
836 ctx->Separable2D.Filter[i * 4 + 2] = b;
837 ctx->Separable2D.Filter[i * 4 + 3] = a;
838 }
839 }
840
841 /* unpack column filter */
842 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
843 &ctx->Separable2D.Filter[colStart],
844 format, type, column, &ctx->Unpack,
845 0, GL_FALSE);
846
847 /* apply scale and bias */
848 {
849 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
850 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
851 GLint i;
852 for (i = 0; i < width; i++) {
853 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
854 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
855 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
856 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
857 r = r * scale[0] + bias[0];
858 g = g * scale[1] + bias[1];
859 b = b * scale[2] + bias[2];
860 a = a * scale[3] + bias[3];
861 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
862 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
863 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
864 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
865 }
866 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000867
Brian Paulb5012e12000-11-10 18:31:04 +0000868 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000869}
870
871
872/**********************************************************************/
873/*** image convolution functions ***/
874/**********************************************************************/
875
Brian Pauld4b799b2000-08-21 14:24:30 +0000876static void
877convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
878 GLint filterWidth, const GLfloat filter[][4],
879 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000880{
Brian Paul7e708742000-08-22 18:54:25 +0000881 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000882 GLint i, n;
883
Brian Paul7e708742000-08-22 18:54:25 +0000884 if (filterWidth >= 1)
885 dstWidth = srcWidth - (filterWidth - 1);
886 else
887 dstWidth = srcWidth;
888
Brian Paulcc8e37f2000-07-12 13:00:09 +0000889 if (dstWidth <= 0)
890 return; /* null result */
891
892 for (i = 0; i < dstWidth; i++) {
893 GLfloat sumR = 0.0;
894 GLfloat sumG = 0.0;
895 GLfloat sumB = 0.0;
896 GLfloat sumA = 0.0;
897 for (n = 0; n < filterWidth; n++) {
898 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
899 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
900 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
901 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
902 }
903 dest[i][RCOMP] = sumR;
904 dest[i][GCOMP] = sumG;
905 dest[i][BCOMP] = sumB;
906 dest[i][ACOMP] = sumA;
907 }
908}
909
910
Brian Pauld4b799b2000-08-21 14:24:30 +0000911static void
912convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
913 GLint filterWidth, const GLfloat filter[][4],
914 GLfloat dest[][4],
915 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000916{
917 const GLint halfFilterWidth = filterWidth / 2;
918 GLint i, n;
919
920 for (i = 0; i < srcWidth; i++) {
921 GLfloat sumR = 0.0;
922 GLfloat sumG = 0.0;
923 GLfloat sumB = 0.0;
924 GLfloat sumA = 0.0;
925 for (n = 0; n < filterWidth; n++) {
926 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
927 sumR += borderColor[RCOMP] * filter[n][RCOMP];
928 sumG += borderColor[GCOMP] * filter[n][GCOMP];
929 sumB += borderColor[BCOMP] * filter[n][BCOMP];
930 sumA += borderColor[ACOMP] * filter[n][ACOMP];
931 }
932 else {
933 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
934 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
935 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
936 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
937 }
938 }
939 dest[i][RCOMP] = sumR;
940 dest[i][GCOMP] = sumG;
941 dest[i][BCOMP] = sumB;
942 dest[i][ACOMP] = sumA;
943 }
944}
945
946
Brian Pauld4b799b2000-08-21 14:24:30 +0000947static void
948convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
949 GLint filterWidth, const GLfloat filter[][4],
950 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000951{
952 const GLint halfFilterWidth = filterWidth / 2;
953 GLint i, n;
954
955 for (i = 0; i < srcWidth; i++) {
956 GLfloat sumR = 0.0;
957 GLfloat sumG = 0.0;
958 GLfloat sumB = 0.0;
959 GLfloat sumA = 0.0;
960 for (n = 0; n < filterWidth; n++) {
961 if (i + n < halfFilterWidth) {
962 sumR += src[0][RCOMP] * filter[n][RCOMP];
963 sumG += src[0][GCOMP] * filter[n][GCOMP];
964 sumB += src[0][BCOMP] * filter[n][BCOMP];
965 sumA += src[0][ACOMP] * filter[n][ACOMP];
966 }
967 else if (i + n - halfFilterWidth >= srcWidth) {
968 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
969 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
970 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
971 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
972 }
973 else {
974 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
975 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
976 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
977 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
978 }
979 }
980 dest[i][RCOMP] = sumR;
981 dest[i][GCOMP] = sumG;
982 dest[i][BCOMP] = sumB;
983 dest[i][ACOMP] = sumA;
984 }
985}
986
987
Brian Pauld4b799b2000-08-21 14:24:30 +0000988static void
989convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
990 const GLfloat src[][4],
991 GLint filterWidth, GLint filterHeight,
992 const GLfloat filter[][4],
993 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000994{
Brian Paul7e708742000-08-22 18:54:25 +0000995 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +0000996 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000997
Brian Paul7e708742000-08-22 18:54:25 +0000998 if (filterWidth >= 1)
999 dstWidth = srcWidth - (filterWidth - 1);
1000 else
1001 dstWidth = srcWidth;
1002
1003 if (filterHeight >= 1)
1004 dstHeight = srcHeight - (filterHeight - 1);
1005 else
1006 dstHeight = srcHeight;
1007
Brian Pauld4b799b2000-08-21 14:24:30 +00001008 if (dstWidth <= 0 || dstHeight <= 0)
1009 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001010
Brian Pauld4b799b2000-08-21 14:24:30 +00001011 for (j = 0; j < dstHeight; j++) {
1012 for (i = 0; i < dstWidth; i++) {
1013 GLfloat sumR = 0.0;
1014 GLfloat sumG = 0.0;
1015 GLfloat sumB = 0.0;
1016 GLfloat sumA = 0.0;
1017 for (m = 0; m < filterHeight; m++) {
1018 for (n = 0; n < filterWidth; n++) {
1019 const GLint k = (j + m) * srcWidth + i + n;
1020 const GLint f = m * filterWidth + n;
1021 sumR += src[k][RCOMP] * filter[f][RCOMP];
1022 sumG += src[k][GCOMP] * filter[f][GCOMP];
1023 sumB += src[k][BCOMP] * filter[f][BCOMP];
1024 sumA += src[k][ACOMP] * filter[f][ACOMP];
1025 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001026 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001027 dest[j * dstWidth + i][RCOMP] = sumR;
1028 dest[j * dstWidth + i][GCOMP] = sumG;
1029 dest[j * dstWidth + i][BCOMP] = sumB;
1030 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001031 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001032 }
1033}
1034
1035
Brian Pauld4b799b2000-08-21 14:24:30 +00001036static void
1037convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1038 const GLfloat src[][4],
1039 GLint filterWidth, GLint filterHeight,
1040 const GLfloat filter[][4],
1041 GLfloat dest[][4],
1042 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001043{
1044 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001045 const GLint halfFilterHeight = filterHeight / 2;
1046 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001047
Brian Pauld4b799b2000-08-21 14:24:30 +00001048 for (j = 0; j < srcHeight; j++) {
1049 for (i = 0; i < srcWidth; i++) {
1050 GLfloat sumR = 0.0;
1051 GLfloat sumG = 0.0;
1052 GLfloat sumB = 0.0;
1053 GLfloat sumA = 0.0;
1054 for (m = 0; m < filterHeight; m++) {
1055 for (n = 0; n < filterWidth; n++) {
1056 const GLint f = m * filterWidth + n;
1057 const GLint is = i + n - halfFilterWidth;
1058 const GLint js = j + m - halfFilterHeight;
1059 if (is < 0 || is >= srcWidth ||
1060 js < 0 || js >= srcHeight) {
1061 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1062 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1063 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1064 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1065 }
1066 else {
1067 const GLint k = js * srcWidth + is;
1068 sumR += src[k][RCOMP] * filter[f][RCOMP];
1069 sumG += src[k][GCOMP] * filter[f][GCOMP];
1070 sumB += src[k][BCOMP] * filter[f][BCOMP];
1071 sumA += src[k][ACOMP] * filter[f][ACOMP];
1072 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001073 }
1074 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001075 dest[j * srcWidth + i][RCOMP] = sumR;
1076 dest[j * srcWidth + i][GCOMP] = sumG;
1077 dest[j * srcWidth + i][BCOMP] = sumB;
1078 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001079 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001080 }
1081}
1082
1083
Brian Pauld4b799b2000-08-21 14:24:30 +00001084static void
1085convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1086 const GLfloat src[][4],
1087 GLint filterWidth, GLint filterHeight,
1088 const GLfloat filter[][4],
1089 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001090{
1091 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001092 const GLint halfFilterHeight = filterHeight / 2;
1093 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001094
Brian Pauld4b799b2000-08-21 14:24:30 +00001095 for (j = 0; j < srcHeight; j++) {
1096 for (i = 0; i < srcWidth; i++) {
1097 GLfloat sumR = 0.0;
1098 GLfloat sumG = 0.0;
1099 GLfloat sumB = 0.0;
1100 GLfloat sumA = 0.0;
1101 for (m = 0; m < filterHeight; m++) {
1102 for (n = 0; n < filterWidth; n++) {
1103 const GLint f = m * filterWidth + n;
1104 GLint is = i + n - halfFilterWidth;
1105 GLint js = j + m - halfFilterHeight;
1106 GLint k;
1107 if (is < 0)
1108 is = 0;
1109 else if (is >= srcWidth)
1110 is = srcWidth - 1;
1111 if (js < 0)
1112 js = 0;
1113 else if (js >= srcHeight)
1114 js = srcHeight - 1;
1115 k = js * srcWidth + is;
1116 sumR += src[k][RCOMP] * filter[f][RCOMP];
1117 sumG += src[k][GCOMP] * filter[f][GCOMP];
1118 sumB += src[k][BCOMP] * filter[f][BCOMP];
1119 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001120 }
1121 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001122 dest[j * srcWidth + i][RCOMP] = sumR;
1123 dest[j * srcWidth + i][GCOMP] = sumG;
1124 dest[j * srcWidth + i][BCOMP] = sumB;
1125 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001126 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001127 }
1128}
1129
1130
Brian Pauld4b799b2000-08-21 14:24:30 +00001131static void
1132convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1133 const GLfloat src[][4],
1134 GLint filterWidth, GLint filterHeight,
1135 const GLfloat rowFilt[][4],
1136 const GLfloat colFilt[][4],
1137 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001138{
Brian Paul7e708742000-08-22 18:54:25 +00001139 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001140 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001141
1142 if (filterWidth >= 1)
1143 dstWidth = srcWidth - (filterWidth - 1);
1144 else
1145 dstWidth = srcWidth;
1146
1147 if (filterHeight >= 1)
1148 dstHeight = srcHeight - (filterHeight - 1);
1149 else
1150 dstHeight = srcHeight;
1151
1152 if (dstWidth <= 0 || dstHeight <= 0)
1153 return;
1154
1155 for (j = 0; j < dstHeight; j++) {
1156 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001157 GLfloat sumR = 0.0;
1158 GLfloat sumG = 0.0;
1159 GLfloat sumB = 0.0;
1160 GLfloat sumA = 0.0;
1161 for (m = 0; m < filterHeight; m++) {
1162 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001163 GLint k = (j + m) * srcWidth + i + n;
1164 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1165 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1166 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1167 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001168 }
1169 }
Brian Paul7e708742000-08-22 18:54:25 +00001170 dest[j * dstWidth + i][RCOMP] = sumR;
1171 dest[j * dstWidth + i][GCOMP] = sumG;
1172 dest[j * dstWidth + i][BCOMP] = sumB;
1173 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001174 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001175 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001176}
1177
1178
Brian Pauld4b799b2000-08-21 14:24:30 +00001179static void
1180convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1181 const GLfloat src[][4],
1182 GLint filterWidth, GLint filterHeight,
1183 const GLfloat rowFilt[][4],
1184 const GLfloat colFilt[][4],
1185 GLfloat dest[][4],
1186 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001187{
1188 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001189 const GLint halfFilterHeight = filterHeight / 2;
1190 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001191
Brian Pauld4b799b2000-08-21 14:24:30 +00001192 for (j = 0; j < srcHeight; j++) {
1193 for (i = 0; i < srcWidth; i++) {
1194 GLfloat sumR = 0.0;
1195 GLfloat sumG = 0.0;
1196 GLfloat sumB = 0.0;
1197 GLfloat sumA = 0.0;
1198 for (m = 0; m < filterHeight; m++) {
1199 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001200 const GLint is = i + n - halfFilterWidth;
1201 const GLint js = j + m - halfFilterHeight;
1202 if (is < 0 || is >= srcWidth ||
1203 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001204 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1205 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1206 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1207 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1208 }
1209 else {
Brian Paul7e708742000-08-22 18:54:25 +00001210 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001211 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1212 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1213 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1214 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1215 }
Brian Paul7e708742000-08-22 18:54:25 +00001216
Brian Paulcc8e37f2000-07-12 13:00:09 +00001217 }
1218 }
Brian Paul7e708742000-08-22 18:54:25 +00001219 dest[j * srcWidth + i][RCOMP] = sumR;
1220 dest[j * srcWidth + i][GCOMP] = sumG;
1221 dest[j * srcWidth + i][BCOMP] = sumB;
1222 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001223 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001224 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001225}
1226
1227
1228static void
1229convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1230 const GLfloat src[][4],
1231 GLint filterWidth, GLint filterHeight,
1232 const GLfloat rowFilt[][4],
1233 const GLfloat colFilt[][4],
1234 GLfloat dest[][4])
1235{
1236 const GLint halfFilterWidth = filterWidth / 2;
1237 const GLint halfFilterHeight = filterHeight / 2;
1238 GLint i, j, n, m;
1239
1240 for (j = 0; j < srcHeight; j++) {
1241 for (i = 0; i < srcWidth; i++) {
1242 GLfloat sumR = 0.0;
1243 GLfloat sumG = 0.0;
1244 GLfloat sumB = 0.0;
1245 GLfloat sumA = 0.0;
1246 for (m = 0; m < filterHeight; m++) {
1247 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001248 GLint is = i + n - halfFilterWidth;
1249 GLint js = j + m - halfFilterHeight;
1250 GLint k;
1251 if (is < 0)
1252 is = 0;
1253 else if (is >= srcWidth)
1254 is = srcWidth - 1;
1255 if (js < 0)
1256 js = 0;
1257 else if (js >= srcHeight)
1258 js = srcHeight - 1;
1259 k = js * srcWidth + is;
1260 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1261 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1262 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1263 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001264 }
1265 }
Brian Paul7e708742000-08-22 18:54:25 +00001266 dest[j * srcWidth + i][RCOMP] = sumR;
1267 dest[j * srcWidth + i][GCOMP] = sumG;
1268 dest[j * srcWidth + i][BCOMP] = sumB;
1269 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001270 }
1271 }
1272}
1273
1274
1275
1276void
1277_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1278 const GLfloat *srcImage, GLfloat *dstImage)
1279{
1280 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1281 case GL_REDUCE:
1282 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1283 ctx->Convolution1D.Width,
1284 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1285 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001286 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001287 break;
1288 case GL_CONSTANT_BORDER:
1289 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1290 ctx->Convolution1D.Width,
1291 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1292 (GLfloat (*)[4]) dstImage,
1293 ctx->Pixel.ConvolutionBorderColor[0]);
1294 break;
1295 case GL_REPLICATE_BORDER:
1296 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1297 ctx->Convolution1D.Width,
1298 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1299 (GLfloat (*)[4]) dstImage);
1300 break;
1301 default:
1302 ;
1303 }
1304}
1305
1306
1307void
1308_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1309 const GLfloat *srcImage, GLfloat *dstImage)
1310{
1311 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1312 case GL_REDUCE:
1313 convolve_2d_reduce(*width, *height,
1314 (const GLfloat (*)[4]) srcImage,
1315 ctx->Convolution2D.Width,
1316 ctx->Convolution2D.Height,
1317 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1318 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001319 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1320 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001321 break;
1322 case GL_CONSTANT_BORDER:
1323 convolve_2d_constant(*width, *height,
1324 (const GLfloat (*)[4]) srcImage,
1325 ctx->Convolution2D.Width,
1326 ctx->Convolution2D.Height,
1327 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1328 (GLfloat (*)[4]) dstImage,
1329 ctx->Pixel.ConvolutionBorderColor[1]);
1330 break;
1331 case GL_REPLICATE_BORDER:
1332 convolve_2d_replicate(*width, *height,
1333 (const GLfloat (*)[4]) srcImage,
1334 ctx->Convolution2D.Width,
1335 ctx->Convolution2D.Height,
1336 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1337 (GLfloat (*)[4]) dstImage);
1338 break;
1339 default:
1340 ;
1341 }
1342}
1343
1344
1345void
1346_mesa_convolve_sep_image(const GLcontext *ctx,
1347 GLsizei *width, GLsizei *height,
1348 const GLfloat *srcImage, GLfloat *dstImage)
1349{
1350 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1351 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1352
1353 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1354 case GL_REDUCE:
1355 convolve_sep_reduce(*width, *height,
1356 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001357 ctx->Separable2D.Width,
1358 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001359 (const GLfloat (*)[4]) rowFilter,
1360 (const GLfloat (*)[4]) colFilter,
1361 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001362 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1363 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001364 break;
1365 case GL_CONSTANT_BORDER:
1366 convolve_sep_constant(*width, *height,
1367 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001368 ctx->Separable2D.Width,
1369 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001370 (const GLfloat (*)[4]) rowFilter,
1371 (const GLfloat (*)[4]) colFilter,
1372 (GLfloat (*)[4]) dstImage,
1373 ctx->Pixel.ConvolutionBorderColor[2]);
1374 break;
1375 case GL_REPLICATE_BORDER:
1376 convolve_sep_replicate(*width, *height,
1377 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001378 ctx->Separable2D.Width,
1379 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001380 (const GLfloat (*)[4]) rowFilter,
1381 (const GLfloat (*)[4]) colFilter,
1382 (GLfloat (*)[4]) dstImage);
1383 break;
1384 default:
1385 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001386 }
1387}
Brian Paul16461f72001-02-06 17:22:16 +00001388
1389
1390
1391/*
1392 * This function computes an image's size after convolution.
1393 * If the convolution border mode is GL_REDUCE, the post-convolution
1394 * image will be smaller than the original.
1395 */
1396void
1397_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1398 GLsizei *width, GLsizei *height)
1399{
1400 if (ctx->Pixel.Convolution1DEnabled
1401 && dimensions == 1
1402 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1403 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1404 }
1405 else if (ctx->Pixel.Convolution2DEnabled
1406 && dimensions > 1
1407 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1408 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1409 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1410 }
1411 else if (ctx->Pixel.Separable2DEnabled
1412 && dimensions > 1
1413 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1414 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1415 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1416 }
1417}