blob: ce01a121871c89e0310744865d4b7a45857a1708 [file] [log] [blame]
Brian Paul3b4fbbc2002-07-09 01:22:50 +00001/* $Id: convolve.c,v 1.27 2002/07/09 01:22:50 brianp Exp $ */
Brian Paulcc8e37f2000-07-12 13:00:09 +00002
3/*
4 * Mesa 3-D graphics library
Brian Pauld0570642002-03-19 15:22:50 +00005 * Version: 4.0.2
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
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 Paulcc8e37f2000-07-12 13:00:09 +000046#endif
47
48
Brian Paul147b0832000-08-23 14:31:25 +000049/*
50 * Given an internalFormat token passed to glConvolutionFilter
51 * or glSeparableFilter, return the corresponding base format.
52 * Return -1 if invalid token.
53 */
54static GLint
55base_filter_format( GLenum format )
56{
57 switch (format) {
58 case GL_ALPHA:
59 case GL_ALPHA4:
60 case GL_ALPHA8:
61 case GL_ALPHA12:
62 case GL_ALPHA16:
63 return GL_ALPHA;
64 case GL_LUMINANCE:
65 case GL_LUMINANCE4:
66 case GL_LUMINANCE8:
67 case GL_LUMINANCE12:
68 case GL_LUMINANCE16:
69 return GL_LUMINANCE;
70 case GL_LUMINANCE_ALPHA:
71 case GL_LUMINANCE4_ALPHA4:
72 case GL_LUMINANCE6_ALPHA2:
73 case GL_LUMINANCE8_ALPHA8:
74 case GL_LUMINANCE12_ALPHA4:
75 case GL_LUMINANCE12_ALPHA12:
76 case GL_LUMINANCE16_ALPHA16:
77 return GL_LUMINANCE_ALPHA;
78 case GL_INTENSITY:
79 case GL_INTENSITY4:
80 case GL_INTENSITY8:
81 case GL_INTENSITY12:
82 case GL_INTENSITY16:
83 return GL_INTENSITY;
84 case GL_RGB:
85 case GL_R3_G3_B2:
86 case GL_RGB4:
87 case GL_RGB5:
88 case GL_RGB8:
89 case GL_RGB10:
90 case GL_RGB12:
91 case GL_RGB16:
92 return GL_RGB;
93 case 4:
94 case GL_RGBA:
95 case GL_RGBA2:
96 case GL_RGBA4:
97 case GL_RGB5_A1:
98 case GL_RGBA8:
99 case GL_RGB10_A2:
100 case GL_RGBA12:
101 case GL_RGBA16:
102 return GL_RGBA;
103 default:
104 return -1; /* error */
105 }
106}
107
108
109void
110_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
111{
Brian Pauld0570642002-03-19 15:22:50 +0000112 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000113 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000115
116 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000117 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000118 return;
119 }
120
121 baseFormat = base_filter_format(internalFormat);
122 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000123 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000124 return;
125 }
126
127 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000128 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000129 return;
130 }
131
Brian Paul90f042a2000-12-10 19:23:19 +0000132 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000133 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000134 return;
135 }
136
137 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000138 format == GL_STENCIL_INDEX ||
139 format == GL_DEPTH_COMPONENT ||
140 format == GL_INTENSITY ||
141 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000142 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000143 return;
144 }
145
146 ctx->Convolution1D.Format = format;
147 ctx->Convolution1D.InternalFormat = internalFormat;
148 ctx->Convolution1D.Width = width;
149 ctx->Convolution1D.Height = 1;
150
151 /* unpack filter image */
152 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
153 ctx->Convolution1D.Filter,
154 format, type, image, &ctx->Unpack,
155 0, GL_FALSE);
156
157 /* apply scale and bias */
158 {
159 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
160 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
161 GLint i;
162 for (i = 0; i < width; i++) {
163 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
164 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
165 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
166 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
167 r = r * scale[0] + bias[0];
168 g = g * scale[1] + bias[1];
169 b = b * scale[2] + bias[2];
170 a = a * scale[3] + bias[3];
171 ctx->Convolution1D.Filter[i * 4 + 0] = r;
172 ctx->Convolution1D.Filter[i * 4 + 1] = g;
173 ctx->Convolution1D.Filter[i * 4 + 2] = b;
174 ctx->Convolution1D.Filter[i * 4 + 3] = a;
175 }
176 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000177
Brian Paulb5012e12000-11-10 18:31:04 +0000178 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000179}
180
181
182void
183_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
184{
Brian Pauld0570642002-03-19 15:22:50 +0000185 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000186 GLint i, components;
187 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000188 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000189
190 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000191 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000192 return;
193 }
194
195 baseFormat = base_filter_format(internalFormat);
196 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000197 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000198 return;
199 }
200
201 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000202 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000203 return;
204 }
205 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000206 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000207 return;
208 }
209
Brian Paul90f042a2000-12-10 19:23:19 +0000210 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000211 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000212 return;
213 }
214 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000215 format == GL_STENCIL_INDEX ||
216 format == GL_DEPTH_COMPONENT ||
217 format == GL_INTENSITY ||
218 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000219 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000220 return;
221 }
222
223 components = _mesa_components_in_format(format);
224 assert(components > 0); /* this should have been caught earlier */
225
226 ctx->Convolution2D.Format = format;
227 ctx->Convolution2D.InternalFormat = internalFormat;
228 ctx->Convolution2D.Width = width;
229 ctx->Convolution2D.Height = height;
230
231 /* Unpack filter image. We always store filters in RGBA format. */
232 for (i = 0; i < height; i++) {
233 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
234 height, format, type, 0, i, 0);
235 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
236 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
237 format, type, src, &ctx->Unpack,
238 0, GL_FALSE);
239 }
240
241 /* apply scale and bias */
242 {
243 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
244 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
Brian Paul8acb7e92001-05-09 22:24:22 +0000245 for (i = 0; i < width * height; i++) {
Brian Paul147b0832000-08-23 14:31:25 +0000246 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
247 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
248 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
249 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
250 r = r * scale[0] + bias[0];
251 g = g * scale[1] + bias[1];
252 b = b * scale[2] + bias[2];
253 a = a * scale[3] + bias[3];
254 ctx->Convolution2D.Filter[i * 4 + 0] = r;
255 ctx->Convolution2D.Filter[i * 4 + 1] = g;
256 ctx->Convolution2D.Filter[i * 4 + 2] = b;
257 ctx->Convolution2D.Filter[i * 4 + 3] = a;
258 }
259 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000260
Brian Paulb5012e12000-11-10 18:31:04 +0000261 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000262}
263
264
265void
266_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
267{
268 GET_CURRENT_CONTEXT(ctx);
269 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000270 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000271
272 switch (target) {
273 case GL_CONVOLUTION_1D:
274 c = 0;
275 break;
276 case GL_CONVOLUTION_2D:
277 c = 1;
278 break;
279 case GL_SEPARABLE_2D:
280 c = 2;
281 break;
282 default:
Brian Paul08836342001-03-03 20:33:27 +0000283 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000284 return;
285 }
286
287 switch (pname) {
288 case GL_CONVOLUTION_BORDER_MODE:
289 if (param == (GLfloat) GL_REDUCE ||
290 param == (GLfloat) GL_CONSTANT_BORDER ||
291 param == (GLfloat) GL_REPLICATE_BORDER) {
292 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
293 }
294 else {
Brian Paul08836342001-03-03 20:33:27 +0000295 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000296 return;
297 }
298 break;
299 default:
Brian Paul08836342001-03-03 20:33:27 +0000300 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000301 return;
302 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000303
304 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000305}
306
307
308void
309_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
310{
311 GET_CURRENT_CONTEXT(ctx);
312 struct gl_convolution_attrib *conv;
313 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000314 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000315
316 switch (target) {
317 case GL_CONVOLUTION_1D:
318 c = 0;
319 conv = &ctx->Convolution1D;
320 break;
321 case GL_CONVOLUTION_2D:
322 c = 1;
323 conv = &ctx->Convolution2D;
324 break;
325 case GL_SEPARABLE_2D:
326 c = 2;
327 conv = &ctx->Separable2D;
328 break;
329 default:
Brian Paul08836342001-03-03 20:33:27 +0000330 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000331 return;
332 }
333
334 switch (pname) {
335 case GL_CONVOLUTION_BORDER_COLOR:
336 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
337 break;
338 case GL_CONVOLUTION_BORDER_MODE:
339 if (params[0] == (GLfloat) GL_REDUCE ||
340 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
341 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
342 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
343 }
344 else {
Brian Paul08836342001-03-03 20:33:27 +0000345 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000346 return;
347 }
348 break;
349 case GL_CONVOLUTION_FILTER_SCALE:
350 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
351 break;
352 case GL_CONVOLUTION_FILTER_BIAS:
353 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
354 break;
355 default:
Brian Paul08836342001-03-03 20:33:27 +0000356 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000357 return;
358 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000359
360 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000361}
362
363
364void
365_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
366{
367 GET_CURRENT_CONTEXT(ctx);
368 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000369 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000370
371 switch (target) {
372 case GL_CONVOLUTION_1D:
373 c = 0;
374 break;
375 case GL_CONVOLUTION_2D:
376 c = 1;
377 break;
378 case GL_SEPARABLE_2D:
379 c = 2;
380 break;
381 default:
Brian Paul08836342001-03-03 20:33:27 +0000382 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000383 return;
384 }
385
386 switch (pname) {
387 case GL_CONVOLUTION_BORDER_MODE:
388 if (param == (GLint) GL_REDUCE ||
389 param == (GLint) GL_CONSTANT_BORDER ||
390 param == (GLint) GL_REPLICATE_BORDER) {
391 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
392 }
393 else {
Brian Paul08836342001-03-03 20:33:27 +0000394 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000395 return;
396 }
397 break;
398 default:
Brian Paul08836342001-03-03 20:33:27 +0000399 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000400 return;
401 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000402
403 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000404}
405
406
407void
408_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
409{
410 GET_CURRENT_CONTEXT(ctx);
411 struct gl_convolution_attrib *conv;
412 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000413 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000414
415 switch (target) {
416 case GL_CONVOLUTION_1D:
417 c = 0;
418 conv = &ctx->Convolution1D;
419 break;
420 case GL_CONVOLUTION_2D:
421 c = 1;
422 conv = &ctx->Convolution2D;
423 break;
424 case GL_SEPARABLE_2D:
425 c = 2;
426 conv = &ctx->Separable2D;
427 break;
428 default:
Brian Paul08836342001-03-03 20:33:27 +0000429 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000430 return;
431 }
432
433 switch (pname) {
434 case GL_CONVOLUTION_BORDER_COLOR:
435 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
436 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
437 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
438 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
439 break;
440 case GL_CONVOLUTION_BORDER_MODE:
441 if (params[0] == (GLint) GL_REDUCE ||
442 params[0] == (GLint) GL_CONSTANT_BORDER ||
443 params[0] == (GLint) GL_REPLICATE_BORDER) {
444 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
445 }
446 else {
Brian Paul08836342001-03-03 20:33:27 +0000447 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000448 return;
449 }
450 break;
451 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000452 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
453 /* need cast to prevent compiler warnings */
454 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
455 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
456 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
457 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000458 break;
459 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000460 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
461 /* need cast to prevent compiler warnings */
462 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
463 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
464 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
465 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000466 break;
467 default:
Brian Paul08836342001-03-03 20:33:27 +0000468 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000469 return;
470 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000471
472 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000473}
474
475
476void
477_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
478{
Brian Pauld0570642002-03-19 15:22:50 +0000479 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000480 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000481 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000482
483 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000484 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000485 return;
486 }
487
488 baseFormat = base_filter_format(internalFormat);
489 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000490 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000491 return;
492 }
493
494 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000495 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000496 return;
497 }
498
Keith Whitwell70989242001-03-19 02:25:35 +0000499 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
500 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000501}
502
503
504void
505_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
506{
Brian Pauld0570642002-03-19 15:22:50 +0000507 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000508 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000509 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000510
511 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000512 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000513 return;
514 }
515
516 baseFormat = base_filter_format(internalFormat);
517 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000518 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000519 return;
520 }
521
522 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000523 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000524 return;
525 }
526 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000527 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000528 return;
529 }
530
Keith Whitwell70989242001-03-19 02:25:35 +0000531 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
532 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000533
Brian Paul147b0832000-08-23 14:31:25 +0000534}
535
536
537void
538_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
539{
Brian Paulf75d6972000-09-05 20:28:56 +0000540 const struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000541 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000542 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000543 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000544
Brian Paul0c000ec2000-11-21 23:26:13 +0000545 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000546 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000547 }
548
Brian Paul90f042a2000-12-10 19:23:19 +0000549 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000550 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000551 return;
552 }
553
554 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000555 format == GL_STENCIL_INDEX ||
556 format == GL_DEPTH_COMPONENT ||
557 format == GL_INTENSITY ||
558 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000559 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000560 return;
561 }
562
Brian Paulf75d6972000-09-05 20:28:56 +0000563 switch (target) {
564 case GL_CONVOLUTION_1D:
565 filter = &(ctx->Convolution1D);
566 break;
567 case GL_CONVOLUTION_2D:
568 filter = &(ctx->Convolution2D);
569 break;
570 default:
Brian Paul08836342001-03-03 20:33:27 +0000571 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000572 return;
573 }
574
575 for (row = 0; row < filter->Height; row++) {
576 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
577 filter->Height, format, type,
578 0, row, 0);
579 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paulf75d6972000-09-05 20:28:56 +0000580 _mesa_pack_float_rgba_span(ctx, filter->Width,
581 (const GLfloat (*)[4]) src,
582 format, type, dst, &ctx->Pack, 0);
583 }
Brian Paul147b0832000-08-23 14:31:25 +0000584}
585
586
587void
588_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
589{
590 GET_CURRENT_CONTEXT(ctx);
591 const struct gl_convolution_attrib *conv;
592 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000593 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000594
595 switch (target) {
596 case GL_CONVOLUTION_1D:
597 c = 0;
598 conv = &ctx->Convolution1D;
599 break;
600 case GL_CONVOLUTION_2D:
601 c = 1;
602 conv = &ctx->Convolution2D;
603 break;
604 case GL_SEPARABLE_2D:
605 c = 2;
606 conv = &ctx->Separable2D;
607 break;
608 default:
Brian Paul08836342001-03-03 20:33:27 +0000609 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000610 return;
611 }
612
613 switch (pname) {
614 case GL_CONVOLUTION_BORDER_COLOR:
615 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
616 break;
617 case GL_CONVOLUTION_BORDER_MODE:
618 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
619 break;
620 case GL_CONVOLUTION_FILTER_SCALE:
621 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
622 break;
623 case GL_CONVOLUTION_FILTER_BIAS:
624 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
625 break;
626 case GL_CONVOLUTION_FORMAT:
627 *params = (GLfloat) conv->Format;
628 break;
629 case GL_CONVOLUTION_WIDTH:
630 *params = (GLfloat) conv->Width;
631 break;
632 case GL_CONVOLUTION_HEIGHT:
633 *params = (GLfloat) conv->Height;
634 break;
635 case GL_MAX_CONVOLUTION_WIDTH:
636 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
637 break;
638 case GL_MAX_CONVOLUTION_HEIGHT:
639 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
640 break;
641 default:
Brian Paul08836342001-03-03 20:33:27 +0000642 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000643 return;
644 }
645}
646
647
648void
649_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
650{
651 GET_CURRENT_CONTEXT(ctx);
652 const struct gl_convolution_attrib *conv;
653 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000654 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000655
656 switch (target) {
657 case GL_CONVOLUTION_1D:
658 c = 0;
659 conv = &ctx->Convolution1D;
660 break;
661 case GL_CONVOLUTION_2D:
662 c = 1;
663 conv = &ctx->Convolution2D;
664 break;
665 case GL_SEPARABLE_2D:
666 c = 2;
667 conv = &ctx->Separable2D;
668 break;
669 default:
Brian Paul08836342001-03-03 20:33:27 +0000670 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000671 return;
672 }
673
674 switch (pname) {
675 case GL_CONVOLUTION_BORDER_COLOR:
676 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
677 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
678 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
679 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
680 break;
681 case GL_CONVOLUTION_BORDER_MODE:
682 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
683 break;
684 case GL_CONVOLUTION_FILTER_SCALE:
685 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
686 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
687 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
688 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
689 break;
690 case GL_CONVOLUTION_FILTER_BIAS:
691 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
692 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
693 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
694 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
695 break;
696 case GL_CONVOLUTION_FORMAT:
697 *params = (GLint) conv->Format;
698 break;
699 case GL_CONVOLUTION_WIDTH:
700 *params = (GLint) conv->Width;
701 break;
702 case GL_CONVOLUTION_HEIGHT:
703 *params = (GLint) conv->Height;
704 break;
705 case GL_MAX_CONVOLUTION_WIDTH:
706 *params = (GLint) ctx->Const.MaxConvolutionWidth;
707 break;
708 case GL_MAX_CONVOLUTION_HEIGHT:
709 *params = (GLint) ctx->Const.MaxConvolutionHeight;
710 break;
711 default:
Brian Paul08836342001-03-03 20:33:27 +0000712 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000713 return;
714 }
715}
716
717
718void
719_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
720{
Brian Paulf75d6972000-09-05 20:28:56 +0000721 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
722 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000723 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000724 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000725
Brian Paul0c000ec2000-11-21 23:26:13 +0000726 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000727 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000728 }
729
Brian Paul147b0832000-08-23 14:31:25 +0000730 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000731 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000732 return;
733 }
734
Brian Paul90f042a2000-12-10 19:23:19 +0000735 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000736 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000737 return;
738 }
739
740 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000741 format == GL_STENCIL_INDEX ||
742 format == GL_DEPTH_COMPONENT ||
743 format == GL_INTENSITY ||
744 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000745 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000746 return;
747 }
748
Brian Paulf75d6972000-09-05 20:28:56 +0000749 filter = &ctx->Separable2D;
750
751 /* Row filter */
752 {
753 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
754 filter->Height, format, type,
755 0, 0, 0);
756 _mesa_pack_float_rgba_span(ctx, filter->Width,
757 (const GLfloat (*)[4]) filter->Filter,
758 format, type, dst, &ctx->Pack, 0);
759 }
760
761 /* Column filter */
762 {
763 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
764 1, format, type,
765 0, 0, 0);
766 const GLfloat *src = filter->Filter + colStart;
767 _mesa_pack_float_rgba_span(ctx, filter->Height,
768 (const GLfloat (*)[4]) src,
769 format, type, dst, &ctx->Pack, 0);
770 }
771
772 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000773}
774
775
776void
777_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
778{
779 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000780 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000781 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000782 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000783
784 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000785 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000786 return;
787 }
788
789 baseFormat = base_filter_format(internalFormat);
790 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000791 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000792 return;
793 }
794
795 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000796 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000797 return;
798 }
799 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000800 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000801 return;
802 }
803
Brian Paul90f042a2000-12-10 19:23:19 +0000804 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000805 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000806 return;
807 }
808
809 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000810 format == GL_STENCIL_INDEX ||
811 format == GL_DEPTH_COMPONENT ||
812 format == GL_INTENSITY ||
813 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000814 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000815 return;
816 }
817
818 ctx->Separable2D.Format = format;
819 ctx->Separable2D.InternalFormat = internalFormat;
820 ctx->Separable2D.Width = width;
821 ctx->Separable2D.Height = height;
822
823 /* unpack row filter */
824 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
825 ctx->Separable2D.Filter,
826 format, type, row, &ctx->Unpack,
827 0, GL_FALSE);
828
829 /* apply scale and bias */
830 {
831 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
832 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
833 GLint i;
834 for (i = 0; i < width; i++) {
835 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
836 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
837 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
838 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
839 r = r * scale[0] + bias[0];
840 g = g * scale[1] + bias[1];
841 b = b * scale[2] + bias[2];
842 a = a * scale[3] + bias[3];
843 ctx->Separable2D.Filter[i * 4 + 0] = r;
844 ctx->Separable2D.Filter[i * 4 + 1] = g;
845 ctx->Separable2D.Filter[i * 4 + 2] = b;
846 ctx->Separable2D.Filter[i * 4 + 3] = a;
847 }
848 }
849
850 /* unpack column filter */
851 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
852 &ctx->Separable2D.Filter[colStart],
853 format, type, column, &ctx->Unpack,
854 0, GL_FALSE);
855
856 /* apply scale and bias */
857 {
858 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
859 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
860 GLint i;
861 for (i = 0; i < width; i++) {
862 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
863 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
864 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
865 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
866 r = r * scale[0] + bias[0];
867 g = g * scale[1] + bias[1];
868 b = b * scale[2] + bias[2];
869 a = a * scale[3] + bias[3];
870 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
871 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
872 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
873 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
874 }
875 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000876
Brian Paulb5012e12000-11-10 18:31:04 +0000877 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000878}
879
880
881/**********************************************************************/
882/*** image convolution functions ***/
883/**********************************************************************/
884
Brian Pauld4b799b2000-08-21 14:24:30 +0000885static void
886convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
887 GLint filterWidth, const GLfloat filter[][4],
888 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000889{
Brian Paul7e708742000-08-22 18:54:25 +0000890 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000891 GLint i, n;
892
Brian Paul7e708742000-08-22 18:54:25 +0000893 if (filterWidth >= 1)
894 dstWidth = srcWidth - (filterWidth - 1);
895 else
896 dstWidth = srcWidth;
897
Brian Paulcc8e37f2000-07-12 13:00:09 +0000898 if (dstWidth <= 0)
899 return; /* null result */
900
901 for (i = 0; i < dstWidth; i++) {
902 GLfloat sumR = 0.0;
903 GLfloat sumG = 0.0;
904 GLfloat sumB = 0.0;
905 GLfloat sumA = 0.0;
906 for (n = 0; n < filterWidth; n++) {
907 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
908 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
909 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
910 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
911 }
912 dest[i][RCOMP] = sumR;
913 dest[i][GCOMP] = sumG;
914 dest[i][BCOMP] = sumB;
915 dest[i][ACOMP] = sumA;
916 }
917}
918
919
Brian Pauld4b799b2000-08-21 14:24:30 +0000920static void
921convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
922 GLint filterWidth, const GLfloat filter[][4],
923 GLfloat dest[][4],
924 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000925{
926 const GLint halfFilterWidth = filterWidth / 2;
927 GLint i, n;
928
929 for (i = 0; i < srcWidth; i++) {
930 GLfloat sumR = 0.0;
931 GLfloat sumG = 0.0;
932 GLfloat sumB = 0.0;
933 GLfloat sumA = 0.0;
934 for (n = 0; n < filterWidth; n++) {
935 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
936 sumR += borderColor[RCOMP] * filter[n][RCOMP];
937 sumG += borderColor[GCOMP] * filter[n][GCOMP];
938 sumB += borderColor[BCOMP] * filter[n][BCOMP];
939 sumA += borderColor[ACOMP] * filter[n][ACOMP];
940 }
941 else {
942 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
943 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
944 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
945 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
946 }
947 }
948 dest[i][RCOMP] = sumR;
949 dest[i][GCOMP] = sumG;
950 dest[i][BCOMP] = sumB;
951 dest[i][ACOMP] = sumA;
952 }
953}
954
955
Brian Pauld4b799b2000-08-21 14:24:30 +0000956static void
957convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
958 GLint filterWidth, const GLfloat filter[][4],
959 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000960{
961 const GLint halfFilterWidth = filterWidth / 2;
962 GLint i, n;
963
964 for (i = 0; i < srcWidth; i++) {
965 GLfloat sumR = 0.0;
966 GLfloat sumG = 0.0;
967 GLfloat sumB = 0.0;
968 GLfloat sumA = 0.0;
969 for (n = 0; n < filterWidth; n++) {
970 if (i + n < halfFilterWidth) {
971 sumR += src[0][RCOMP] * filter[n][RCOMP];
972 sumG += src[0][GCOMP] * filter[n][GCOMP];
973 sumB += src[0][BCOMP] * filter[n][BCOMP];
974 sumA += src[0][ACOMP] * filter[n][ACOMP];
975 }
976 else if (i + n - halfFilterWidth >= srcWidth) {
977 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
978 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
979 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
980 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
981 }
982 else {
983 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
984 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
985 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
986 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
987 }
988 }
989 dest[i][RCOMP] = sumR;
990 dest[i][GCOMP] = sumG;
991 dest[i][BCOMP] = sumB;
992 dest[i][ACOMP] = sumA;
993 }
994}
995
996
Brian Pauld4b799b2000-08-21 14:24:30 +0000997static void
998convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
999 const GLfloat src[][4],
1000 GLint filterWidth, GLint filterHeight,
1001 const GLfloat filter[][4],
1002 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001003{
Brian Paul7e708742000-08-22 18:54:25 +00001004 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001005 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001006
Brian Paul7e708742000-08-22 18:54:25 +00001007 if (filterWidth >= 1)
1008 dstWidth = srcWidth - (filterWidth - 1);
1009 else
1010 dstWidth = srcWidth;
1011
1012 if (filterHeight >= 1)
1013 dstHeight = srcHeight - (filterHeight - 1);
1014 else
1015 dstHeight = srcHeight;
1016
Brian Pauld4b799b2000-08-21 14:24:30 +00001017 if (dstWidth <= 0 || dstHeight <= 0)
1018 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001019
Brian Pauld4b799b2000-08-21 14:24:30 +00001020 for (j = 0; j < dstHeight; j++) {
1021 for (i = 0; i < dstWidth; i++) {
1022 GLfloat sumR = 0.0;
1023 GLfloat sumG = 0.0;
1024 GLfloat sumB = 0.0;
1025 GLfloat sumA = 0.0;
1026 for (m = 0; m < filterHeight; m++) {
1027 for (n = 0; n < filterWidth; n++) {
1028 const GLint k = (j + m) * srcWidth + i + n;
1029 const GLint f = m * filterWidth + n;
1030 sumR += src[k][RCOMP] * filter[f][RCOMP];
1031 sumG += src[k][GCOMP] * filter[f][GCOMP];
1032 sumB += src[k][BCOMP] * filter[f][BCOMP];
1033 sumA += src[k][ACOMP] * filter[f][ACOMP];
1034 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001035 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001036 dest[j * dstWidth + i][RCOMP] = sumR;
1037 dest[j * dstWidth + i][GCOMP] = sumG;
1038 dest[j * dstWidth + i][BCOMP] = sumB;
1039 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001040 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001041 }
1042}
1043
1044
Brian Pauld4b799b2000-08-21 14:24:30 +00001045static void
1046convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1047 const GLfloat src[][4],
1048 GLint filterWidth, GLint filterHeight,
1049 const GLfloat filter[][4],
1050 GLfloat dest[][4],
1051 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001052{
1053 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001054 const GLint halfFilterHeight = filterHeight / 2;
1055 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001056
Brian Pauld4b799b2000-08-21 14:24:30 +00001057 for (j = 0; j < srcHeight; j++) {
1058 for (i = 0; i < srcWidth; i++) {
1059 GLfloat sumR = 0.0;
1060 GLfloat sumG = 0.0;
1061 GLfloat sumB = 0.0;
1062 GLfloat sumA = 0.0;
1063 for (m = 0; m < filterHeight; m++) {
1064 for (n = 0; n < filterWidth; n++) {
1065 const GLint f = m * filterWidth + n;
1066 const GLint is = i + n - halfFilterWidth;
1067 const GLint js = j + m - halfFilterHeight;
1068 if (is < 0 || is >= srcWidth ||
1069 js < 0 || js >= srcHeight) {
1070 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1071 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1072 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1073 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1074 }
1075 else {
1076 const GLint k = js * srcWidth + is;
1077 sumR += src[k][RCOMP] * filter[f][RCOMP];
1078 sumG += src[k][GCOMP] * filter[f][GCOMP];
1079 sumB += src[k][BCOMP] * filter[f][BCOMP];
1080 sumA += src[k][ACOMP] * filter[f][ACOMP];
1081 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001082 }
1083 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001084 dest[j * srcWidth + i][RCOMP] = sumR;
1085 dest[j * srcWidth + i][GCOMP] = sumG;
1086 dest[j * srcWidth + i][BCOMP] = sumB;
1087 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001088 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001089 }
1090}
1091
1092
Brian Pauld4b799b2000-08-21 14:24:30 +00001093static void
1094convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1095 const GLfloat src[][4],
1096 GLint filterWidth, GLint filterHeight,
1097 const GLfloat filter[][4],
1098 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001099{
1100 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001101 const GLint halfFilterHeight = filterHeight / 2;
1102 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001103
Brian Pauld4b799b2000-08-21 14:24:30 +00001104 for (j = 0; j < srcHeight; j++) {
1105 for (i = 0; i < srcWidth; i++) {
1106 GLfloat sumR = 0.0;
1107 GLfloat sumG = 0.0;
1108 GLfloat sumB = 0.0;
1109 GLfloat sumA = 0.0;
1110 for (m = 0; m < filterHeight; m++) {
1111 for (n = 0; n < filterWidth; n++) {
1112 const GLint f = m * filterWidth + n;
1113 GLint is = i + n - halfFilterWidth;
1114 GLint js = j + m - halfFilterHeight;
1115 GLint k;
1116 if (is < 0)
1117 is = 0;
1118 else if (is >= srcWidth)
1119 is = srcWidth - 1;
1120 if (js < 0)
1121 js = 0;
1122 else if (js >= srcHeight)
1123 js = srcHeight - 1;
1124 k = js * srcWidth + is;
1125 sumR += src[k][RCOMP] * filter[f][RCOMP];
1126 sumG += src[k][GCOMP] * filter[f][GCOMP];
1127 sumB += src[k][BCOMP] * filter[f][BCOMP];
1128 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001129 }
1130 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001131 dest[j * srcWidth + i][RCOMP] = sumR;
1132 dest[j * srcWidth + i][GCOMP] = sumG;
1133 dest[j * srcWidth + i][BCOMP] = sumB;
1134 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001135 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001136 }
1137}
1138
1139
Brian Pauld4b799b2000-08-21 14:24:30 +00001140static void
1141convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1142 const GLfloat src[][4],
1143 GLint filterWidth, GLint filterHeight,
1144 const GLfloat rowFilt[][4],
1145 const GLfloat colFilt[][4],
1146 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001147{
Brian Paul7e708742000-08-22 18:54:25 +00001148 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001149 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001150
1151 if (filterWidth >= 1)
1152 dstWidth = srcWidth - (filterWidth - 1);
1153 else
1154 dstWidth = srcWidth;
1155
1156 if (filterHeight >= 1)
1157 dstHeight = srcHeight - (filterHeight - 1);
1158 else
1159 dstHeight = srcHeight;
1160
1161 if (dstWidth <= 0 || dstHeight <= 0)
1162 return;
1163
1164 for (j = 0; j < dstHeight; j++) {
1165 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001166 GLfloat sumR = 0.0;
1167 GLfloat sumG = 0.0;
1168 GLfloat sumB = 0.0;
1169 GLfloat sumA = 0.0;
1170 for (m = 0; m < filterHeight; m++) {
1171 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001172 GLint k = (j + m) * srcWidth + i + n;
1173 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1174 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1175 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1176 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001177 }
1178 }
Brian Paul7e708742000-08-22 18:54:25 +00001179 dest[j * dstWidth + i][RCOMP] = sumR;
1180 dest[j * dstWidth + i][GCOMP] = sumG;
1181 dest[j * dstWidth + i][BCOMP] = sumB;
1182 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001183 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001184 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001185}
1186
1187
Brian Pauld4b799b2000-08-21 14:24:30 +00001188static void
1189convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1190 const GLfloat src[][4],
1191 GLint filterWidth, GLint filterHeight,
1192 const GLfloat rowFilt[][4],
1193 const GLfloat colFilt[][4],
1194 GLfloat dest[][4],
1195 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001196{
1197 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001198 const GLint halfFilterHeight = filterHeight / 2;
1199 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001200
Brian Pauld4b799b2000-08-21 14:24:30 +00001201 for (j = 0; j < srcHeight; j++) {
1202 for (i = 0; i < srcWidth; i++) {
1203 GLfloat sumR = 0.0;
1204 GLfloat sumG = 0.0;
1205 GLfloat sumB = 0.0;
1206 GLfloat sumA = 0.0;
1207 for (m = 0; m < filterHeight; m++) {
1208 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001209 const GLint is = i + n - halfFilterWidth;
1210 const GLint js = j + m - halfFilterHeight;
1211 if (is < 0 || is >= srcWidth ||
1212 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001213 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1214 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1215 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1216 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1217 }
1218 else {
Brian Paul7e708742000-08-22 18:54:25 +00001219 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001220 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1221 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1222 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1223 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1224 }
Brian Paul7e708742000-08-22 18:54:25 +00001225
Brian Paulcc8e37f2000-07-12 13:00:09 +00001226 }
1227 }
Brian Paul7e708742000-08-22 18:54:25 +00001228 dest[j * srcWidth + i][RCOMP] = sumR;
1229 dest[j * srcWidth + i][GCOMP] = sumG;
1230 dest[j * srcWidth + i][BCOMP] = sumB;
1231 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001232 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001233 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001234}
1235
1236
1237static void
1238convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1239 const GLfloat src[][4],
1240 GLint filterWidth, GLint filterHeight,
1241 const GLfloat rowFilt[][4],
1242 const GLfloat colFilt[][4],
1243 GLfloat dest[][4])
1244{
1245 const GLint halfFilterWidth = filterWidth / 2;
1246 const GLint halfFilterHeight = filterHeight / 2;
1247 GLint i, j, n, m;
1248
1249 for (j = 0; j < srcHeight; j++) {
1250 for (i = 0; i < srcWidth; i++) {
1251 GLfloat sumR = 0.0;
1252 GLfloat sumG = 0.0;
1253 GLfloat sumB = 0.0;
1254 GLfloat sumA = 0.0;
1255 for (m = 0; m < filterHeight; m++) {
1256 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001257 GLint is = i + n - halfFilterWidth;
1258 GLint js = j + m - halfFilterHeight;
1259 GLint k;
1260 if (is < 0)
1261 is = 0;
1262 else if (is >= srcWidth)
1263 is = srcWidth - 1;
1264 if (js < 0)
1265 js = 0;
1266 else if (js >= srcHeight)
1267 js = srcHeight - 1;
1268 k = js * srcWidth + is;
1269 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1270 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1271 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1272 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001273 }
1274 }
Brian Paul7e708742000-08-22 18:54:25 +00001275 dest[j * srcWidth + i][RCOMP] = sumR;
1276 dest[j * srcWidth + i][GCOMP] = sumG;
1277 dest[j * srcWidth + i][BCOMP] = sumB;
1278 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001279 }
1280 }
1281}
1282
1283
1284
1285void
1286_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1287 const GLfloat *srcImage, GLfloat *dstImage)
1288{
1289 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1290 case GL_REDUCE:
1291 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1292 ctx->Convolution1D.Width,
1293 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1294 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001295 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001296 break;
1297 case GL_CONSTANT_BORDER:
1298 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1299 ctx->Convolution1D.Width,
1300 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1301 (GLfloat (*)[4]) dstImage,
1302 ctx->Pixel.ConvolutionBorderColor[0]);
1303 break;
1304 case GL_REPLICATE_BORDER:
1305 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1306 ctx->Convolution1D.Width,
1307 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1308 (GLfloat (*)[4]) dstImage);
1309 break;
1310 default:
1311 ;
1312 }
1313}
1314
1315
1316void
1317_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1318 const GLfloat *srcImage, GLfloat *dstImage)
1319{
1320 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1321 case GL_REDUCE:
1322 convolve_2d_reduce(*width, *height,
1323 (const GLfloat (*)[4]) srcImage,
1324 ctx->Convolution2D.Width,
1325 ctx->Convolution2D.Height,
1326 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1327 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001328 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1329 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001330 break;
1331 case GL_CONSTANT_BORDER:
1332 convolve_2d_constant(*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 ctx->Pixel.ConvolutionBorderColor[1]);
1339 break;
1340 case GL_REPLICATE_BORDER:
1341 convolve_2d_replicate(*width, *height,
1342 (const GLfloat (*)[4]) srcImage,
1343 ctx->Convolution2D.Width,
1344 ctx->Convolution2D.Height,
1345 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1346 (GLfloat (*)[4]) dstImage);
1347 break;
1348 default:
1349 ;
1350 }
1351}
1352
1353
1354void
1355_mesa_convolve_sep_image(const GLcontext *ctx,
1356 GLsizei *width, GLsizei *height,
1357 const GLfloat *srcImage, GLfloat *dstImage)
1358{
1359 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1360 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1361
1362 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1363 case GL_REDUCE:
1364 convolve_sep_reduce(*width, *height,
1365 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001366 ctx->Separable2D.Width,
1367 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001368 (const GLfloat (*)[4]) rowFilter,
1369 (const GLfloat (*)[4]) colFilter,
1370 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001371 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1372 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001373 break;
1374 case GL_CONSTANT_BORDER:
1375 convolve_sep_constant(*width, *height,
1376 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001377 ctx->Separable2D.Width,
1378 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001379 (const GLfloat (*)[4]) rowFilter,
1380 (const GLfloat (*)[4]) colFilter,
1381 (GLfloat (*)[4]) dstImage,
1382 ctx->Pixel.ConvolutionBorderColor[2]);
1383 break;
1384 case GL_REPLICATE_BORDER:
1385 convolve_sep_replicate(*width, *height,
1386 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001387 ctx->Separable2D.Width,
1388 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001389 (const GLfloat (*)[4]) rowFilter,
1390 (const GLfloat (*)[4]) colFilter,
1391 (GLfloat (*)[4]) dstImage);
1392 break;
1393 default:
1394 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001395 }
1396}
Brian Paul16461f72001-02-06 17:22:16 +00001397
1398
1399
1400/*
1401 * This function computes an image's size after convolution.
1402 * If the convolution border mode is GL_REDUCE, the post-convolution
1403 * image will be smaller than the original.
1404 */
1405void
1406_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1407 GLsizei *width, GLsizei *height)
1408{
1409 if (ctx->Pixel.Convolution1DEnabled
1410 && dimensions == 1
1411 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1412 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1413 }
1414 else if (ctx->Pixel.Convolution2DEnabled
1415 && dimensions > 1
1416 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1417 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1418 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1419 }
1420 else if (ctx->Pixel.Separable2DEnabled
1421 && dimensions > 1
1422 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1423 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1424 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1425 }
1426}