blob: a5e71b8cbdc03c55b102aed53606fbc99e51994f [file] [log] [blame]
Brian Paul3c634522002-10-24 23:57:19 +00001/* $Id: convolve.c,v 1.28 2002/10/24 23:57:20 brianp Exp $ */
Brian Paulcc8e37f2000-07-12 13:00:09 +00002
3/*
4 * Mesa 3-D graphics library
Brian Paul3c634522002-10-24 23:57:19 +00005 * Version: 4.1
Brian Paulcc8e37f2000-07-12 13:00:09 +00006 *
Brian Pauld0570642002-03-19 15:22:50 +00007 * Copyright (C) 1999-2002 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
Brian Paulcc8e37f2000-07-12 13:00:09 +000036#include "glheader.h"
Brian Paulc893a012000-10-28 20:41:13 +000037#include "colormac.h"
Brian Pauld4b799b2000-08-21 14:24:30 +000038#include "convolve.h"
39#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000040#include "image.h"
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +000041#include "mtypes.h"
Jon Taylorcdfba5d2000-11-23 02:50:56 +000042#include "state.h"
Brian Paulcc8e37f2000-07-12 13:00:09 +000043
44
Brian Paul147b0832000-08-23 14:31:25 +000045/*
46 * Given an internalFormat token passed to glConvolutionFilter
47 * or glSeparableFilter, return the corresponding base format.
48 * Return -1 if invalid token.
49 */
50static GLint
51base_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
105void
106_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
107{
Brian Pauld0570642002-03-19 15:22:50 +0000108 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000109 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000110 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000111
112 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000113 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000114 return;
115 }
116
117 baseFormat = base_filter_format(internalFormat);
118 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000119 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000120 return;
121 }
122
123 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000124 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000125 return;
126 }
127
Brian Paul90f042a2000-12-10 19:23:19 +0000128 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000129 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000130 return;
131 }
132
133 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000134 format == GL_STENCIL_INDEX ||
135 format == GL_DEPTH_COMPONENT ||
136 format == GL_INTENSITY ||
137 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000138 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000139 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 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000173
Brian Paulb5012e12000-11-10 18:31:04 +0000174 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000175}
176
177
178void
179_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
180{
Brian Pauld0570642002-03-19 15:22:50 +0000181 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000182 GLint i, components;
183 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000184 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000185
186 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000187 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000188 return;
189 }
190
191 baseFormat = base_filter_format(internalFormat);
192 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000193 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000194 return;
195 }
196
197 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000198 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000199 return;
200 }
201 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000202 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000203 return;
204 }
205
Brian Paul90f042a2000-12-10 19:23:19 +0000206 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000207 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000208 return;
209 }
210 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000211 format == GL_STENCIL_INDEX ||
212 format == GL_DEPTH_COMPONENT ||
213 format == GL_INTENSITY ||
214 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000215 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000216 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];
Brian Paul8acb7e92001-05-09 22:24:22 +0000241 for (i = 0; i < width * height; i++) {
Brian Paul147b0832000-08-23 14:31:25 +0000242 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 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000256
Brian Paulb5012e12000-11-10 18:31:04 +0000257 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000258}
259
260
261void
262_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
263{
264 GET_CURRENT_CONTEXT(ctx);
265 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000266 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000267
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:
Brian Paul08836342001-03-03 20:33:27 +0000279 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000280 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 {
Brian Paul08836342001-03-03 20:33:27 +0000291 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000292 return;
293 }
294 break;
295 default:
Brian Paul08836342001-03-03 20:33:27 +0000296 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000297 return;
298 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000299
300 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000301}
302
303
304void
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;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000310 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000311
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:
Brian Paul08836342001-03-03 20:33:27 +0000326 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000327 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 {
Brian Paul08836342001-03-03 20:33:27 +0000341 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000342 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:
Brian Paul08836342001-03-03 20:33:27 +0000352 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000353 return;
354 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000355
356 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000357}
358
359
360void
361_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
362{
363 GET_CURRENT_CONTEXT(ctx);
364 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000365 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000366
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:
Brian Paul08836342001-03-03 20:33:27 +0000378 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000379 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 {
Brian Paul08836342001-03-03 20:33:27 +0000390 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000391 return;
392 }
393 break;
394 default:
Brian Paul08836342001-03-03 20:33:27 +0000395 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000396 return;
397 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000398
399 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000400}
401
402
403void
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;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000409 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000410
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:
Brian Paul08836342001-03-03 20:33:27 +0000425 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000426 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 {
Brian Paul08836342001-03-03 20:33:27 +0000443 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000444 return;
445 }
446 break;
447 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000448 /* 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];
Brian Paul147b0832000-08-23 14:31:25 +0000454 break;
455 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000456 /* 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];
Brian Paul147b0832000-08-23 14:31:25 +0000462 break;
463 default:
Brian Paul08836342001-03-03 20:33:27 +0000464 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000465 return;
466 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000467
468 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000469}
470
471
472void
473_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
474{
Brian Pauld0570642002-03-19 15:22:50 +0000475 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000476 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000477 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000478
479 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000480 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000481 return;
482 }
483
484 baseFormat = base_filter_format(internalFormat);
485 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000486 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000487 return;
488 }
489
490 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000491 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000492 return;
493 }
494
Keith Whitwell70989242001-03-19 02:25:35 +0000495 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
496 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000497}
498
499
500void
501_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
502{
Brian Pauld0570642002-03-19 15:22:50 +0000503 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000504 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000505 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000506
507 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000508 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000509 return;
510 }
511
512 baseFormat = base_filter_format(internalFormat);
513 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000514 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000515 return;
516 }
517
518 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000519 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000520 return;
521 }
522 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000523 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000524 return;
525 }
526
Keith Whitwell70989242001-03-19 02:25:35 +0000527 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
528 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000529
Brian Paul147b0832000-08-23 14:31:25 +0000530}
531
532
533void
534_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
535{
Brian Paulf75d6972000-09-05 20:28:56 +0000536 const struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000537 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000538 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000539 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000540
Brian Paul0c000ec2000-11-21 23:26:13 +0000541 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000542 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000543 }
544
Brian Paul90f042a2000-12-10 19:23:19 +0000545 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000546 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000547 return;
548 }
549
550 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000551 format == GL_STENCIL_INDEX ||
552 format == GL_DEPTH_COMPONENT ||
553 format == GL_INTENSITY ||
554 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000555 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000556 return;
557 }
558
Brian Paulf75d6972000-09-05 20:28:56 +0000559 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:
Brian Paul08836342001-03-03 20:33:27 +0000567 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000568 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;
Brian Paulf75d6972000-09-05 20:28:56 +0000576 _mesa_pack_float_rgba_span(ctx, filter->Width,
577 (const GLfloat (*)[4]) src,
578 format, type, dst, &ctx->Pack, 0);
579 }
Brian Paul147b0832000-08-23 14:31:25 +0000580}
581
582
583void
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;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000589 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000590
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:
Brian Paul08836342001-03-03 20:33:27 +0000605 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000606 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:
Brian Paul08836342001-03-03 20:33:27 +0000638 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000639 return;
640 }
641}
642
643
644void
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;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000650 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000651
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:
Brian Paul08836342001-03-03 20:33:27 +0000666 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000667 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:
Brian Paul08836342001-03-03 20:33:27 +0000708 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000709 return;
710 }
711}
712
713
714void
715_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
716{
Brian Paulf75d6972000-09-05 20:28:56 +0000717 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
718 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000719 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000720 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000721
Brian Paul0c000ec2000-11-21 23:26:13 +0000722 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000723 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000724 }
725
Brian Paul147b0832000-08-23 14:31:25 +0000726 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000727 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000728 return;
729 }
730
Brian Paul90f042a2000-12-10 19:23:19 +0000731 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000732 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000733 return;
734 }
735
736 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000737 format == GL_STENCIL_INDEX ||
738 format == GL_DEPTH_COMPONENT ||
739 format == GL_INTENSITY ||
740 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000741 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000742 return;
743 }
744
Brian Paulf75d6972000-09-05 20:28:56 +0000745 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 */
Brian Paul147b0832000-08-23 14:31:25 +0000769}
770
771
772void
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;
Brian Pauld0570642002-03-19 15:22:50 +0000776 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000777 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000778 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000779
780 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000781 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000782 return;
783 }
784
785 baseFormat = base_filter_format(internalFormat);
786 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000787 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000788 return;
789 }
790
791 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000792 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000793 return;
794 }
795 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000796 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000797 return;
798 }
799
Brian Paul90f042a2000-12-10 19:23:19 +0000800 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000801 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000802 return;
803 }
804
805 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000806 format == GL_STENCIL_INDEX ||
807 format == GL_DEPTH_COMPONENT ||
808 format == GL_INTENSITY ||
809 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000810 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000811 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 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000872
Brian Paulb5012e12000-11-10 18:31:04 +0000873 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000874}
875
876
877/**********************************************************************/
878/*** image convolution functions ***/
879/**********************************************************************/
880
Brian Pauld4b799b2000-08-21 14:24:30 +0000881static void
882convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
883 GLint filterWidth, const GLfloat filter[][4],
884 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000885{
Brian Paul7e708742000-08-22 18:54:25 +0000886 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000887 GLint i, n;
888
Brian Paul7e708742000-08-22 18:54:25 +0000889 if (filterWidth >= 1)
890 dstWidth = srcWidth - (filterWidth - 1);
891 else
892 dstWidth = srcWidth;
893
Brian Paulcc8e37f2000-07-12 13:00:09 +0000894 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
Brian Pauld4b799b2000-08-21 14:24:30 +0000916static void
917convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
918 GLint filterWidth, const GLfloat filter[][4],
919 GLfloat dest[][4],
920 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000921{
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
Brian Pauld4b799b2000-08-21 14:24:30 +0000952static void
953convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
954 GLint filterWidth, const GLfloat filter[][4],
955 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000956{
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
Brian Pauld4b799b2000-08-21 14:24:30 +0000993static void
994convolve_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])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000999{
Brian Paul7e708742000-08-22 18:54:25 +00001000 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001001 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001002
Brian Paul7e708742000-08-22 18:54:25 +00001003 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
Brian Pauld4b799b2000-08-21 14:24:30 +00001013 if (dstWidth <= 0 || dstHeight <= 0)
1014 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001015
Brian Pauld4b799b2000-08-21 14:24:30 +00001016 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 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001031 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001032 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;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001036 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001037 }
1038}
1039
1040
Brian Pauld4b799b2000-08-21 14:24:30 +00001041static void
1042convolve_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])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001048{
1049 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001050 const GLint halfFilterHeight = filterHeight / 2;
1051 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001052
Brian Pauld4b799b2000-08-21 14:24:30 +00001053 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 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001078 }
1079 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001080 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;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001084 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001085 }
1086}
1087
1088
Brian Pauld4b799b2000-08-21 14:24:30 +00001089static void
1090convolve_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])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001095{
1096 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001097 const GLint halfFilterHeight = filterHeight / 2;
1098 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001099
Brian Pauld4b799b2000-08-21 14:24:30 +00001100 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];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001125 }
1126 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001127 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;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001131 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001132 }
1133}
1134
1135
Brian Pauld4b799b2000-08-21 14:24:30 +00001136static void
1137convolve_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])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001143{
Brian Paul7e708742000-08-22 18:54:25 +00001144 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001145 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001146
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++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001162 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++) {
Brian Paul7e708742000-08-22 18:54:25 +00001168 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];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001173 }
1174 }
Brian Paul7e708742000-08-22 18:54:25 +00001175 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;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001179 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001180 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001181}
1182
1183
Brian Pauld4b799b2000-08-21 14:24:30 +00001184static void
1185convolve_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])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001192{
1193 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001194 const GLint halfFilterHeight = filterHeight / 2;
1195 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001196
Brian Pauld4b799b2000-08-21 14:24:30 +00001197 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++) {
Brian Paul7e708742000-08-22 18:54:25 +00001205 const GLint is = i + n - halfFilterWidth;
1206 const GLint js = j + m - halfFilterHeight;
1207 if (is < 0 || is >= srcWidth ||
1208 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001209 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 {
Brian Paul7e708742000-08-22 18:54:25 +00001215 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001216 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 }
Brian Paul7e708742000-08-22 18:54:25 +00001221
Brian Paulcc8e37f2000-07-12 13:00:09 +00001222 }
1223 }
Brian Paul7e708742000-08-22 18:54:25 +00001224 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;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001228 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001229 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001230}
1231
1232
1233static void
1234convolve_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++) {
Brian Paul7e708742000-08-22 18:54:25 +00001253 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];
Brian Pauld4b799b2000-08-21 14:24:30 +00001269 }
1270 }
Brian Paul7e708742000-08-22 18:54:25 +00001271 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;
Brian Pauld4b799b2000-08-21 14:24:30 +00001275 }
1276 }
1277}
1278
1279
1280
1281void
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);
Brian Paul7e708742000-08-22 18:54:25 +00001291 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001292 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
1312void
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);
Brian Paul7e708742000-08-22 18:54:25 +00001324 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1325 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001326 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
1350void
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,
Brian Paul7e708742000-08-22 18:54:25 +00001362 ctx->Separable2D.Width,
1363 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001364 (const GLfloat (*)[4]) rowFilter,
1365 (const GLfloat (*)[4]) colFilter,
1366 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001367 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1368 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001369 break;
1370 case GL_CONSTANT_BORDER:
1371 convolve_sep_constant(*width, *height,
1372 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001373 ctx->Separable2D.Width,
1374 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001375 (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,
Brian Paul7e708742000-08-22 18:54:25 +00001383 ctx->Separable2D.Width,
1384 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001385 (const GLfloat (*)[4]) rowFilter,
1386 (const GLfloat (*)[4]) colFilter,
1387 (GLfloat (*)[4]) dstImage);
1388 break;
1389 default:
1390 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001391 }
1392}
Brian Paul16461f72001-02-06 17:22:16 +00001393
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 */
1401void
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}