blob: 0b1d4113c6fe917a9a9a0fa9582c8d715fea4348 [file] [log] [blame]
Brian Paul08836342001-03-03 20:33:27 +00001/* $Id: convolve.c,v 1.20 2001/03/03 20:33:27 brianp Exp $ */
Brian Paulcc8e37f2000-07-12 13:00:09 +00002
3/*
4 * Mesa 3-D graphics library
Brian Pauld4b799b2000-08-21 14:24:30 +00005 * Version: 3.5
Brian Paulcc8e37f2000-07-12 13:00:09 +00006 *
Brian Paul16461f72001-02-06 17:22:16 +00007 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
Brian Paulcc8e37f2000-07-12 13:00:09 +00008 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/*
29 * Image convolution functions.
30 *
31 * Notes: filter kernel elements are indexed by <n> and <m> as in
32 * the GL spec.
33 */
34
35
36#ifdef PC_HEADER
37#include "all.h"
38#else
39#include "glheader.h"
Brian Paulc893a012000-10-28 20:41:13 +000040#include "colormac.h"
Brian Pauld4b799b2000-08-21 14:24:30 +000041#include "convolve.h"
42#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000043#include "image.h"
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +000044#include "mtypes.h"
Jon Taylorcdfba5d2000-11-23 02:50:56 +000045#include "state.h"
Brian Paulba41b8a2000-11-10 17:45:15 +000046#include "swrast/s_span.h" /* XXX SWRAST hack */
Brian Paulcc8e37f2000-07-12 13:00:09 +000047#endif
48
49
Brian Paul147b0832000-08-23 14:31:25 +000050/*
51 * Given an internalFormat token passed to glConvolutionFilter
52 * or glSeparableFilter, return the corresponding base format.
53 * Return -1 if invalid token.
54 */
55static GLint
56base_filter_format( GLenum format )
57{
58 switch (format) {
59 case GL_ALPHA:
60 case GL_ALPHA4:
61 case GL_ALPHA8:
62 case GL_ALPHA12:
63 case GL_ALPHA16:
64 return GL_ALPHA;
65 case GL_LUMINANCE:
66 case GL_LUMINANCE4:
67 case GL_LUMINANCE8:
68 case GL_LUMINANCE12:
69 case GL_LUMINANCE16:
70 return GL_LUMINANCE;
71 case GL_LUMINANCE_ALPHA:
72 case GL_LUMINANCE4_ALPHA4:
73 case GL_LUMINANCE6_ALPHA2:
74 case GL_LUMINANCE8_ALPHA8:
75 case GL_LUMINANCE12_ALPHA4:
76 case GL_LUMINANCE12_ALPHA12:
77 case GL_LUMINANCE16_ALPHA16:
78 return GL_LUMINANCE_ALPHA;
79 case GL_INTENSITY:
80 case GL_INTENSITY4:
81 case GL_INTENSITY8:
82 case GL_INTENSITY12:
83 case GL_INTENSITY16:
84 return GL_INTENSITY;
85 case GL_RGB:
86 case GL_R3_G3_B2:
87 case GL_RGB4:
88 case GL_RGB5:
89 case GL_RGB8:
90 case GL_RGB10:
91 case GL_RGB12:
92 case GL_RGB16:
93 return GL_RGB;
94 case 4:
95 case GL_RGBA:
96 case GL_RGBA2:
97 case GL_RGBA4:
98 case GL_RGB5_A1:
99 case GL_RGBA8:
100 case GL_RGB10_A2:
101 case GL_RGBA12:
102 case GL_RGBA16:
103 return GL_RGBA;
104 default:
105 return -1; /* error */
106 }
107}
108
109
110void
111_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
112{
113 GLenum baseFormat;
114 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000115 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000116
117 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000118 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000119 return;
120 }
121
122 baseFormat = base_filter_format(internalFormat);
123 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000124 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000125 return;
126 }
127
128 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000129 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000130 return;
131 }
132
Brian Paul90f042a2000-12-10 19:23:19 +0000133 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000134 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000135 return;
136 }
137
138 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000139 format == GL_STENCIL_INDEX ||
140 format == GL_DEPTH_COMPONENT ||
141 format == GL_INTENSITY ||
142 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000143 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000144 return;
145 }
146
147 ctx->Convolution1D.Format = format;
148 ctx->Convolution1D.InternalFormat = internalFormat;
149 ctx->Convolution1D.Width = width;
150 ctx->Convolution1D.Height = 1;
151
152 /* unpack filter image */
153 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
154 ctx->Convolution1D.Filter,
155 format, type, image, &ctx->Unpack,
156 0, GL_FALSE);
157
158 /* apply scale and bias */
159 {
160 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
161 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
162 GLint i;
163 for (i = 0; i < width; i++) {
164 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
165 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
166 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
167 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
168 r = r * scale[0] + bias[0];
169 g = g * scale[1] + bias[1];
170 b = b * scale[2] + bias[2];
171 a = a * scale[3] + bias[3];
172 ctx->Convolution1D.Filter[i * 4 + 0] = r;
173 ctx->Convolution1D.Filter[i * 4 + 1] = g;
174 ctx->Convolution1D.Filter[i * 4 + 2] = b;
175 ctx->Convolution1D.Filter[i * 4 + 3] = a;
176 }
177 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000178
Brian Paulb5012e12000-11-10 18:31:04 +0000179 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000180}
181
182
183void
184_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
185{
186 GLenum baseFormat;
187 GLint i, components;
188 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000189 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000190
191 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000192 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000193 return;
194 }
195
196 baseFormat = base_filter_format(internalFormat);
197 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000198 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000199 return;
200 }
201
202 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000203 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000204 return;
205 }
206 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000207 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000208 return;
209 }
210
Brian Paul90f042a2000-12-10 19:23:19 +0000211 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000212 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000213 return;
214 }
215 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000216 format == GL_STENCIL_INDEX ||
217 format == GL_DEPTH_COMPONENT ||
218 format == GL_INTENSITY ||
219 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000220 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000221 return;
222 }
223
224 components = _mesa_components_in_format(format);
225 assert(components > 0); /* this should have been caught earlier */
226
227 ctx->Convolution2D.Format = format;
228 ctx->Convolution2D.InternalFormat = internalFormat;
229 ctx->Convolution2D.Width = width;
230 ctx->Convolution2D.Height = height;
231
232 /* Unpack filter image. We always store filters in RGBA format. */
233 for (i = 0; i < height; i++) {
234 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
235 height, format, type, 0, i, 0);
236 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
237 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
238 format, type, src, &ctx->Unpack,
239 0, GL_FALSE);
240 }
241
242 /* apply scale and bias */
243 {
244 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
245 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
246 for (i = 0; i < width * height * 4; i++) {
247 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
248 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
249 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
250 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
251 r = r * scale[0] + bias[0];
252 g = g * scale[1] + bias[1];
253 b = b * scale[2] + bias[2];
254 a = a * scale[3] + bias[3];
255 ctx->Convolution2D.Filter[i * 4 + 0] = r;
256 ctx->Convolution2D.Filter[i * 4 + 1] = g;
257 ctx->Convolution2D.Filter[i * 4 + 2] = b;
258 ctx->Convolution2D.Filter[i * 4 + 3] = a;
259 }
260 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000261
Brian Paulb5012e12000-11-10 18:31:04 +0000262 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000263}
264
265
266void
267_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
268{
269 GET_CURRENT_CONTEXT(ctx);
270 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000271 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000272
273 switch (target) {
274 case GL_CONVOLUTION_1D:
275 c = 0;
276 break;
277 case GL_CONVOLUTION_2D:
278 c = 1;
279 break;
280 case GL_SEPARABLE_2D:
281 c = 2;
282 break;
283 default:
Brian Paul08836342001-03-03 20:33:27 +0000284 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000285 return;
286 }
287
288 switch (pname) {
289 case GL_CONVOLUTION_BORDER_MODE:
290 if (param == (GLfloat) GL_REDUCE ||
291 param == (GLfloat) GL_CONSTANT_BORDER ||
292 param == (GLfloat) GL_REPLICATE_BORDER) {
293 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
294 }
295 else {
Brian Paul08836342001-03-03 20:33:27 +0000296 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000297 return;
298 }
299 break;
300 default:
Brian Paul08836342001-03-03 20:33:27 +0000301 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000302 return;
303 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000304
305 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000306}
307
308
309void
310_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
311{
312 GET_CURRENT_CONTEXT(ctx);
313 struct gl_convolution_attrib *conv;
314 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000315 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000316
317 switch (target) {
318 case GL_CONVOLUTION_1D:
319 c = 0;
320 conv = &ctx->Convolution1D;
321 break;
322 case GL_CONVOLUTION_2D:
323 c = 1;
324 conv = &ctx->Convolution2D;
325 break;
326 case GL_SEPARABLE_2D:
327 c = 2;
328 conv = &ctx->Separable2D;
329 break;
330 default:
Brian Paul08836342001-03-03 20:33:27 +0000331 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000332 return;
333 }
334
335 switch (pname) {
336 case GL_CONVOLUTION_BORDER_COLOR:
337 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
338 break;
339 case GL_CONVOLUTION_BORDER_MODE:
340 if (params[0] == (GLfloat) GL_REDUCE ||
341 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
342 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
343 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
344 }
345 else {
Brian Paul08836342001-03-03 20:33:27 +0000346 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000347 return;
348 }
349 break;
350 case GL_CONVOLUTION_FILTER_SCALE:
351 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
352 break;
353 case GL_CONVOLUTION_FILTER_BIAS:
354 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
355 break;
356 default:
Brian Paul08836342001-03-03 20:33:27 +0000357 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000358 return;
359 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000360
361 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000362}
363
364
365void
366_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
367{
368 GET_CURRENT_CONTEXT(ctx);
369 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000370 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000371
372 switch (target) {
373 case GL_CONVOLUTION_1D:
374 c = 0;
375 break;
376 case GL_CONVOLUTION_2D:
377 c = 1;
378 break;
379 case GL_SEPARABLE_2D:
380 c = 2;
381 break;
382 default:
Brian Paul08836342001-03-03 20:33:27 +0000383 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000384 return;
385 }
386
387 switch (pname) {
388 case GL_CONVOLUTION_BORDER_MODE:
389 if (param == (GLint) GL_REDUCE ||
390 param == (GLint) GL_CONSTANT_BORDER ||
391 param == (GLint) GL_REPLICATE_BORDER) {
392 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
393 }
394 else {
Brian Paul08836342001-03-03 20:33:27 +0000395 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000396 return;
397 }
398 break;
399 default:
Brian Paul08836342001-03-03 20:33:27 +0000400 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000401 return;
402 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000403
404 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000405}
406
407
408void
409_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
410{
411 GET_CURRENT_CONTEXT(ctx);
412 struct gl_convolution_attrib *conv;
413 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000414 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000415
416 switch (target) {
417 case GL_CONVOLUTION_1D:
418 c = 0;
419 conv = &ctx->Convolution1D;
420 break;
421 case GL_CONVOLUTION_2D:
422 c = 1;
423 conv = &ctx->Convolution2D;
424 break;
425 case GL_SEPARABLE_2D:
426 c = 2;
427 conv = &ctx->Separable2D;
428 break;
429 default:
Brian Paul08836342001-03-03 20:33:27 +0000430 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000431 return;
432 }
433
434 switch (pname) {
435 case GL_CONVOLUTION_BORDER_COLOR:
436 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
437 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
438 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
439 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
440 break;
441 case GL_CONVOLUTION_BORDER_MODE:
442 if (params[0] == (GLint) GL_REDUCE ||
443 params[0] == (GLint) GL_CONSTANT_BORDER ||
444 params[0] == (GLint) GL_REPLICATE_BORDER) {
445 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
446 }
447 else {
Brian Paul08836342001-03-03 20:33:27 +0000448 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000449 return;
450 }
451 break;
452 case GL_CONVOLUTION_FILTER_SCALE:
453 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
454 break;
455 case GL_CONVOLUTION_FILTER_BIAS:
456 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
457 break;
458 default:
Brian Paul08836342001-03-03 20:33:27 +0000459 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000460 return;
461 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000462
463 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000464}
465
466
467void
468_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
469{
470 GLenum baseFormat;
Brian Paulbaf3e772000-11-21 23:01:22 +0000471 GLchan rgba[MAX_CONVOLUTION_WIDTH][4];
Brian Paul147b0832000-08-23 14:31:25 +0000472 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000473 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000474
475 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000476 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000477 return;
478 }
479
480 baseFormat = base_filter_format(internalFormat);
481 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000482 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000483 return;
484 }
485
486 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000487 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000488 return;
489 }
490
491 /* read pixels from framebuffer */
Brian Paulbaf3e772000-11-21 23:01:22 +0000492 RENDER_START(ctx);
Brian Paul08836342001-03-03 20:33:27 +0000493 _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
Brian Paulbaf3e772000-11-21 23:01:22 +0000494 RENDER_FINISH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000495
496 /* store as convolution filter */
497 _mesa_ConvolutionFilter1D(target, internalFormat, width,
Brian Paulbaf3e772000-11-21 23:01:22 +0000498 GL_RGBA, CHAN_TYPE, rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000499}
500
501
502void
503_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
504{
505 GLenum baseFormat;
506 GLint i;
507 struct gl_pixelstore_attrib packSave;
Brian Paulbaf3e772000-11-21 23:01:22 +0000508 GLchan rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
Brian Paul147b0832000-08-23 14:31:25 +0000509 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000510 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000511
512 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000513 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000514 return;
515 }
516
517 baseFormat = base_filter_format(internalFormat);
518 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000519 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000520 return;
521 }
522
523 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000524 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000525 return;
526 }
527 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000528 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000529 return;
530 }
531
532 /* read pixels from framebuffer */
Brian Paulbaf3e772000-11-21 23:01:22 +0000533 RENDER_START(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000534 for (i = 0; i < height; i++) {
Brian Paul08836342001-03-03 20:33:27 +0000535 _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
Brian Paulba643a22000-10-28 18:34:48 +0000536 (GLchan (*)[4]) rgba[i]);
Brian Paul147b0832000-08-23 14:31:25 +0000537 }
Brian Paulbaf3e772000-11-21 23:01:22 +0000538 RENDER_FINISH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000539
540 /*
541 * store as convolution filter
542 */
543 packSave = ctx->Unpack; /* save pixel packing params */
544
545 ctx->Unpack.Alignment = 1;
546 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
547 ctx->Unpack.SkipPixels = 0;
548 ctx->Unpack.SkipRows = 0;
549 ctx->Unpack.ImageHeight = 0;
550 ctx->Unpack.SkipImages = 0;
551 ctx->Unpack.SwapBytes = GL_FALSE;
552 ctx->Unpack.LsbFirst = GL_FALSE;
Keith Whitwella96308c2000-10-30 13:31:59 +0000553 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000554
555 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
Brian Paulbaf3e772000-11-21 23:01:22 +0000556 GL_RGBA, CHAN_TYPE, rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000557
558 ctx->Unpack = packSave; /* restore pixel packing params */
Keith Whitwella96308c2000-10-30 13:31:59 +0000559 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000560}
561
562
563void
564_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
565{
Brian Paulf75d6972000-09-05 20:28:56 +0000566 const struct gl_convolution_attrib *filter;
567 GLint row;
Brian Paul147b0832000-08-23 14:31:25 +0000568 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000569 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000570
Brian Paul0c000ec2000-11-21 23:26:13 +0000571 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000572 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000573 }
574
Brian Paul90f042a2000-12-10 19:23:19 +0000575 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000576 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000577 return;
578 }
579
580 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000581 format == GL_STENCIL_INDEX ||
582 format == GL_DEPTH_COMPONENT ||
583 format == GL_INTENSITY ||
584 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000585 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000586 return;
587 }
588
Brian Paulf75d6972000-09-05 20:28:56 +0000589 switch (target) {
590 case GL_CONVOLUTION_1D:
591 filter = &(ctx->Convolution1D);
592 break;
593 case GL_CONVOLUTION_2D:
594 filter = &(ctx->Convolution2D);
595 break;
596 default:
Brian Paul08836342001-03-03 20:33:27 +0000597 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000598 return;
599 }
600
601 for (row = 0; row < filter->Height; row++) {
602 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
603 filter->Height, format, type,
604 0, row, 0);
605 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paulf75d6972000-09-05 20:28:56 +0000606 _mesa_pack_float_rgba_span(ctx, filter->Width,
607 (const GLfloat (*)[4]) src,
608 format, type, dst, &ctx->Pack, 0);
609 }
Brian Paul147b0832000-08-23 14:31:25 +0000610}
611
612
613void
614_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
615{
616 GET_CURRENT_CONTEXT(ctx);
617 const struct gl_convolution_attrib *conv;
618 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000619 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000620
621 switch (target) {
622 case GL_CONVOLUTION_1D:
623 c = 0;
624 conv = &ctx->Convolution1D;
625 break;
626 case GL_CONVOLUTION_2D:
627 c = 1;
628 conv = &ctx->Convolution2D;
629 break;
630 case GL_SEPARABLE_2D:
631 c = 2;
632 conv = &ctx->Separable2D;
633 break;
634 default:
Brian Paul08836342001-03-03 20:33:27 +0000635 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000636 return;
637 }
638
639 switch (pname) {
640 case GL_CONVOLUTION_BORDER_COLOR:
641 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
642 break;
643 case GL_CONVOLUTION_BORDER_MODE:
644 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
645 break;
646 case GL_CONVOLUTION_FILTER_SCALE:
647 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
648 break;
649 case GL_CONVOLUTION_FILTER_BIAS:
650 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
651 break;
652 case GL_CONVOLUTION_FORMAT:
653 *params = (GLfloat) conv->Format;
654 break;
655 case GL_CONVOLUTION_WIDTH:
656 *params = (GLfloat) conv->Width;
657 break;
658 case GL_CONVOLUTION_HEIGHT:
659 *params = (GLfloat) conv->Height;
660 break;
661 case GL_MAX_CONVOLUTION_WIDTH:
662 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
663 break;
664 case GL_MAX_CONVOLUTION_HEIGHT:
665 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
666 break;
667 default:
Brian Paul08836342001-03-03 20:33:27 +0000668 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000669 return;
670 }
671}
672
673
674void
675_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
676{
677 GET_CURRENT_CONTEXT(ctx);
678 const struct gl_convolution_attrib *conv;
679 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000680 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000681
682 switch (target) {
683 case GL_CONVOLUTION_1D:
684 c = 0;
685 conv = &ctx->Convolution1D;
686 break;
687 case GL_CONVOLUTION_2D:
688 c = 1;
689 conv = &ctx->Convolution2D;
690 break;
691 case GL_SEPARABLE_2D:
692 c = 2;
693 conv = &ctx->Separable2D;
694 break;
695 default:
Brian Paul08836342001-03-03 20:33:27 +0000696 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000697 return;
698 }
699
700 switch (pname) {
701 case GL_CONVOLUTION_BORDER_COLOR:
702 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
703 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
704 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
705 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
706 break;
707 case GL_CONVOLUTION_BORDER_MODE:
708 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
709 break;
710 case GL_CONVOLUTION_FILTER_SCALE:
711 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
712 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
713 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
714 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
715 break;
716 case GL_CONVOLUTION_FILTER_BIAS:
717 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
718 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
719 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
720 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
721 break;
722 case GL_CONVOLUTION_FORMAT:
723 *params = (GLint) conv->Format;
724 break;
725 case GL_CONVOLUTION_WIDTH:
726 *params = (GLint) conv->Width;
727 break;
728 case GL_CONVOLUTION_HEIGHT:
729 *params = (GLint) conv->Height;
730 break;
731 case GL_MAX_CONVOLUTION_WIDTH:
732 *params = (GLint) ctx->Const.MaxConvolutionWidth;
733 break;
734 case GL_MAX_CONVOLUTION_HEIGHT:
735 *params = (GLint) ctx->Const.MaxConvolutionHeight;
736 break;
737 default:
Brian Paul08836342001-03-03 20:33:27 +0000738 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000739 return;
740 }
741}
742
743
744void
745_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
746{
Brian Paulf75d6972000-09-05 20:28:56 +0000747 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
748 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000749 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000750 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000751
Brian Paul0c000ec2000-11-21 23:26:13 +0000752 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000753 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000754 }
755
Brian Paul147b0832000-08-23 14:31:25 +0000756 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000757 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000758 return;
759 }
760
Brian Paul90f042a2000-12-10 19:23:19 +0000761 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000762 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000763 return;
764 }
765
766 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000767 format == GL_STENCIL_INDEX ||
768 format == GL_DEPTH_COMPONENT ||
769 format == GL_INTENSITY ||
770 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000771 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000772 return;
773 }
774
Brian Paulf75d6972000-09-05 20:28:56 +0000775 filter = &ctx->Separable2D;
776
777 /* Row filter */
778 {
779 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
780 filter->Height, format, type,
781 0, 0, 0);
782 _mesa_pack_float_rgba_span(ctx, filter->Width,
783 (const GLfloat (*)[4]) filter->Filter,
784 format, type, dst, &ctx->Pack, 0);
785 }
786
787 /* Column filter */
788 {
789 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
790 1, format, type,
791 0, 0, 0);
792 const GLfloat *src = filter->Filter + colStart;
793 _mesa_pack_float_rgba_span(ctx, filter->Height,
794 (const GLfloat (*)[4]) src,
795 format, type, dst, &ctx->Pack, 0);
796 }
797
798 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000799}
800
801
802void
803_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
804{
805 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
806 GLenum baseFormat;
807 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000808 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000809
810 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000811 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000812 return;
813 }
814
815 baseFormat = base_filter_format(internalFormat);
816 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000817 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000818 return;
819 }
820
821 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000822 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000823 return;
824 }
825 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000826 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000827 return;
828 }
829
Brian Paul90f042a2000-12-10 19:23:19 +0000830 if (!_mesa_is_legal_format_and_type(format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000831 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000832 return;
833 }
834
835 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000836 format == GL_STENCIL_INDEX ||
837 format == GL_DEPTH_COMPONENT ||
838 format == GL_INTENSITY ||
839 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000840 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000841 return;
842 }
843
844 ctx->Separable2D.Format = format;
845 ctx->Separable2D.InternalFormat = internalFormat;
846 ctx->Separable2D.Width = width;
847 ctx->Separable2D.Height = height;
848
849 /* unpack row filter */
850 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
851 ctx->Separable2D.Filter,
852 format, type, row, &ctx->Unpack,
853 0, GL_FALSE);
854
855 /* apply scale and bias */
856 {
857 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
858 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
859 GLint i;
860 for (i = 0; i < width; i++) {
861 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
862 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
863 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
864 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
865 r = r * scale[0] + bias[0];
866 g = g * scale[1] + bias[1];
867 b = b * scale[2] + bias[2];
868 a = a * scale[3] + bias[3];
869 ctx->Separable2D.Filter[i * 4 + 0] = r;
870 ctx->Separable2D.Filter[i * 4 + 1] = g;
871 ctx->Separable2D.Filter[i * 4 + 2] = b;
872 ctx->Separable2D.Filter[i * 4 + 3] = a;
873 }
874 }
875
876 /* unpack column filter */
877 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
878 &ctx->Separable2D.Filter[colStart],
879 format, type, column, &ctx->Unpack,
880 0, GL_FALSE);
881
882 /* apply scale and bias */
883 {
884 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
885 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
886 GLint i;
887 for (i = 0; i < width; i++) {
888 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
889 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
890 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
891 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
892 r = r * scale[0] + bias[0];
893 g = g * scale[1] + bias[1];
894 b = b * scale[2] + bias[2];
895 a = a * scale[3] + bias[3];
896 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
897 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
898 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
899 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
900 }
901 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000902
Brian Paulb5012e12000-11-10 18:31:04 +0000903 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000904}
905
906
907/**********************************************************************/
908/*** image convolution functions ***/
909/**********************************************************************/
910
Brian Pauld4b799b2000-08-21 14:24:30 +0000911static void
912convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
913 GLint filterWidth, const GLfloat filter[][4],
914 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000915{
Brian Paul7e708742000-08-22 18:54:25 +0000916 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000917 GLint i, n;
918
Brian Paul7e708742000-08-22 18:54:25 +0000919 if (filterWidth >= 1)
920 dstWidth = srcWidth - (filterWidth - 1);
921 else
922 dstWidth = srcWidth;
923
Brian Paulcc8e37f2000-07-12 13:00:09 +0000924 if (dstWidth <= 0)
925 return; /* null result */
926
927 for (i = 0; i < dstWidth; i++) {
928 GLfloat sumR = 0.0;
929 GLfloat sumG = 0.0;
930 GLfloat sumB = 0.0;
931 GLfloat sumA = 0.0;
932 for (n = 0; n < filterWidth; n++) {
933 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
934 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
935 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
936 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
937 }
938 dest[i][RCOMP] = sumR;
939 dest[i][GCOMP] = sumG;
940 dest[i][BCOMP] = sumB;
941 dest[i][ACOMP] = sumA;
942 }
943}
944
945
Brian Pauld4b799b2000-08-21 14:24:30 +0000946static void
947convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
948 GLint filterWidth, const GLfloat filter[][4],
949 GLfloat dest[][4],
950 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000951{
952 const GLint halfFilterWidth = filterWidth / 2;
953 GLint i, n;
954
955 for (i = 0; i < srcWidth; i++) {
956 GLfloat sumR = 0.0;
957 GLfloat sumG = 0.0;
958 GLfloat sumB = 0.0;
959 GLfloat sumA = 0.0;
960 for (n = 0; n < filterWidth; n++) {
961 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
962 sumR += borderColor[RCOMP] * filter[n][RCOMP];
963 sumG += borderColor[GCOMP] * filter[n][GCOMP];
964 sumB += borderColor[BCOMP] * filter[n][BCOMP];
965 sumA += borderColor[ACOMP] * filter[n][ACOMP];
966 }
967 else {
968 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
969 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
970 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
971 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
972 }
973 }
974 dest[i][RCOMP] = sumR;
975 dest[i][GCOMP] = sumG;
976 dest[i][BCOMP] = sumB;
977 dest[i][ACOMP] = sumA;
978 }
979}
980
981
Brian Pauld4b799b2000-08-21 14:24:30 +0000982static void
983convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
984 GLint filterWidth, const GLfloat filter[][4],
985 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000986{
987 const GLint halfFilterWidth = filterWidth / 2;
988 GLint i, n;
989
990 for (i = 0; i < srcWidth; i++) {
991 GLfloat sumR = 0.0;
992 GLfloat sumG = 0.0;
993 GLfloat sumB = 0.0;
994 GLfloat sumA = 0.0;
995 for (n = 0; n < filterWidth; n++) {
996 if (i + n < halfFilterWidth) {
997 sumR += src[0][RCOMP] * filter[n][RCOMP];
998 sumG += src[0][GCOMP] * filter[n][GCOMP];
999 sumB += src[0][BCOMP] * filter[n][BCOMP];
1000 sumA += src[0][ACOMP] * filter[n][ACOMP];
1001 }
1002 else if (i + n - halfFilterWidth >= srcWidth) {
1003 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
1004 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
1005 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
1006 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
1007 }
1008 else {
1009 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1010 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1011 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1012 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1013 }
1014 }
1015 dest[i][RCOMP] = sumR;
1016 dest[i][GCOMP] = sumG;
1017 dest[i][BCOMP] = sumB;
1018 dest[i][ACOMP] = sumA;
1019 }
1020}
1021
1022
Brian Pauld4b799b2000-08-21 14:24:30 +00001023static void
1024convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1025 const GLfloat src[][4],
1026 GLint filterWidth, GLint filterHeight,
1027 const GLfloat filter[][4],
1028 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001029{
Brian Paul7e708742000-08-22 18:54:25 +00001030 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001031 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001032
Brian Paul7e708742000-08-22 18:54:25 +00001033 if (filterWidth >= 1)
1034 dstWidth = srcWidth - (filterWidth - 1);
1035 else
1036 dstWidth = srcWidth;
1037
1038 if (filterHeight >= 1)
1039 dstHeight = srcHeight - (filterHeight - 1);
1040 else
1041 dstHeight = srcHeight;
1042
Brian Pauld4b799b2000-08-21 14:24:30 +00001043 if (dstWidth <= 0 || dstHeight <= 0)
1044 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001045
Brian Pauld4b799b2000-08-21 14:24:30 +00001046 for (j = 0; j < dstHeight; j++) {
1047 for (i = 0; i < dstWidth; i++) {
1048 GLfloat sumR = 0.0;
1049 GLfloat sumG = 0.0;
1050 GLfloat sumB = 0.0;
1051 GLfloat sumA = 0.0;
1052 for (m = 0; m < filterHeight; m++) {
1053 for (n = 0; n < filterWidth; n++) {
1054 const GLint k = (j + m) * srcWidth + i + n;
1055 const GLint f = m * filterWidth + n;
1056 sumR += src[k][RCOMP] * filter[f][RCOMP];
1057 sumG += src[k][GCOMP] * filter[f][GCOMP];
1058 sumB += src[k][BCOMP] * filter[f][BCOMP];
1059 sumA += src[k][ACOMP] * filter[f][ACOMP];
1060 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001061 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001062 dest[j * dstWidth + i][RCOMP] = sumR;
1063 dest[j * dstWidth + i][GCOMP] = sumG;
1064 dest[j * dstWidth + i][BCOMP] = sumB;
1065 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001066 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001067 }
1068}
1069
1070
Brian Pauld4b799b2000-08-21 14:24:30 +00001071static void
1072convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1073 const GLfloat src[][4],
1074 GLint filterWidth, GLint filterHeight,
1075 const GLfloat filter[][4],
1076 GLfloat dest[][4],
1077 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001078{
1079 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001080 const GLint halfFilterHeight = filterHeight / 2;
1081 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001082
Brian Pauld4b799b2000-08-21 14:24:30 +00001083 for (j = 0; j < srcHeight; j++) {
1084 for (i = 0; i < srcWidth; i++) {
1085 GLfloat sumR = 0.0;
1086 GLfloat sumG = 0.0;
1087 GLfloat sumB = 0.0;
1088 GLfloat sumA = 0.0;
1089 for (m = 0; m < filterHeight; m++) {
1090 for (n = 0; n < filterWidth; n++) {
1091 const GLint f = m * filterWidth + n;
1092 const GLint is = i + n - halfFilterWidth;
1093 const GLint js = j + m - halfFilterHeight;
1094 if (is < 0 || is >= srcWidth ||
1095 js < 0 || js >= srcHeight) {
1096 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1097 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1098 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1099 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1100 }
1101 else {
1102 const GLint k = js * srcWidth + is;
1103 sumR += src[k][RCOMP] * filter[f][RCOMP];
1104 sumG += src[k][GCOMP] * filter[f][GCOMP];
1105 sumB += src[k][BCOMP] * filter[f][BCOMP];
1106 sumA += src[k][ACOMP] * filter[f][ACOMP];
1107 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001108 }
1109 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001110 dest[j * srcWidth + i][RCOMP] = sumR;
1111 dest[j * srcWidth + i][GCOMP] = sumG;
1112 dest[j * srcWidth + i][BCOMP] = sumB;
1113 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001114 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001115 }
1116}
1117
1118
Brian Pauld4b799b2000-08-21 14:24:30 +00001119static void
1120convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1121 const GLfloat src[][4],
1122 GLint filterWidth, GLint filterHeight,
1123 const GLfloat filter[][4],
1124 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001125{
1126 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001127 const GLint halfFilterHeight = filterHeight / 2;
1128 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001129
Brian Pauld4b799b2000-08-21 14:24:30 +00001130 for (j = 0; j < srcHeight; j++) {
1131 for (i = 0; i < srcWidth; i++) {
1132 GLfloat sumR = 0.0;
1133 GLfloat sumG = 0.0;
1134 GLfloat sumB = 0.0;
1135 GLfloat sumA = 0.0;
1136 for (m = 0; m < filterHeight; m++) {
1137 for (n = 0; n < filterWidth; n++) {
1138 const GLint f = m * filterWidth + n;
1139 GLint is = i + n - halfFilterWidth;
1140 GLint js = j + m - halfFilterHeight;
1141 GLint k;
1142 if (is < 0)
1143 is = 0;
1144 else if (is >= srcWidth)
1145 is = srcWidth - 1;
1146 if (js < 0)
1147 js = 0;
1148 else if (js >= srcHeight)
1149 js = srcHeight - 1;
1150 k = js * srcWidth + is;
1151 sumR += src[k][RCOMP] * filter[f][RCOMP];
1152 sumG += src[k][GCOMP] * filter[f][GCOMP];
1153 sumB += src[k][BCOMP] * filter[f][BCOMP];
1154 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001155 }
1156 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001157 dest[j * srcWidth + i][RCOMP] = sumR;
1158 dest[j * srcWidth + i][GCOMP] = sumG;
1159 dest[j * srcWidth + i][BCOMP] = sumB;
1160 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001161 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001162 }
1163}
1164
1165
Brian Pauld4b799b2000-08-21 14:24:30 +00001166static void
1167convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1168 const GLfloat src[][4],
1169 GLint filterWidth, GLint filterHeight,
1170 const GLfloat rowFilt[][4],
1171 const GLfloat colFilt[][4],
1172 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001173{
Brian Paul7e708742000-08-22 18:54:25 +00001174 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001175 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001176
1177 if (filterWidth >= 1)
1178 dstWidth = srcWidth - (filterWidth - 1);
1179 else
1180 dstWidth = srcWidth;
1181
1182 if (filterHeight >= 1)
1183 dstHeight = srcHeight - (filterHeight - 1);
1184 else
1185 dstHeight = srcHeight;
1186
1187 if (dstWidth <= 0 || dstHeight <= 0)
1188 return;
1189
1190 for (j = 0; j < dstHeight; j++) {
1191 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001192 GLfloat sumR = 0.0;
1193 GLfloat sumG = 0.0;
1194 GLfloat sumB = 0.0;
1195 GLfloat sumA = 0.0;
1196 for (m = 0; m < filterHeight; m++) {
1197 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001198 GLint k = (j + m) * srcWidth + i + n;
1199 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1200 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1201 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1202 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001203 }
1204 }
Brian Paul7e708742000-08-22 18:54:25 +00001205 dest[j * dstWidth + i][RCOMP] = sumR;
1206 dest[j * dstWidth + i][GCOMP] = sumG;
1207 dest[j * dstWidth + i][BCOMP] = sumB;
1208 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001209 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001210 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001211}
1212
1213
Brian Pauld4b799b2000-08-21 14:24:30 +00001214static void
1215convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1216 const GLfloat src[][4],
1217 GLint filterWidth, GLint filterHeight,
1218 const GLfloat rowFilt[][4],
1219 const GLfloat colFilt[][4],
1220 GLfloat dest[][4],
1221 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001222{
1223 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001224 const GLint halfFilterHeight = filterHeight / 2;
1225 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001226
Brian Pauld4b799b2000-08-21 14:24:30 +00001227 for (j = 0; j < srcHeight; j++) {
1228 for (i = 0; i < srcWidth; i++) {
1229 GLfloat sumR = 0.0;
1230 GLfloat sumG = 0.0;
1231 GLfloat sumB = 0.0;
1232 GLfloat sumA = 0.0;
1233 for (m = 0; m < filterHeight; m++) {
1234 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001235 const GLint is = i + n - halfFilterWidth;
1236 const GLint js = j + m - halfFilterHeight;
1237 if (is < 0 || is >= srcWidth ||
1238 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001239 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1240 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1241 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1242 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1243 }
1244 else {
Brian Paul7e708742000-08-22 18:54:25 +00001245 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001246 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1247 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1248 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1249 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1250 }
Brian Paul7e708742000-08-22 18:54:25 +00001251
Brian Paulcc8e37f2000-07-12 13:00:09 +00001252 }
1253 }
Brian Paul7e708742000-08-22 18:54:25 +00001254 dest[j * srcWidth + i][RCOMP] = sumR;
1255 dest[j * srcWidth + i][GCOMP] = sumG;
1256 dest[j * srcWidth + i][BCOMP] = sumB;
1257 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001258 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001259 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001260}
1261
1262
1263static void
1264convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1265 const GLfloat src[][4],
1266 GLint filterWidth, GLint filterHeight,
1267 const GLfloat rowFilt[][4],
1268 const GLfloat colFilt[][4],
1269 GLfloat dest[][4])
1270{
1271 const GLint halfFilterWidth = filterWidth / 2;
1272 const GLint halfFilterHeight = filterHeight / 2;
1273 GLint i, j, n, m;
1274
1275 for (j = 0; j < srcHeight; j++) {
1276 for (i = 0; i < srcWidth; i++) {
1277 GLfloat sumR = 0.0;
1278 GLfloat sumG = 0.0;
1279 GLfloat sumB = 0.0;
1280 GLfloat sumA = 0.0;
1281 for (m = 0; m < filterHeight; m++) {
1282 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001283 GLint is = i + n - halfFilterWidth;
1284 GLint js = j + m - halfFilterHeight;
1285 GLint k;
1286 if (is < 0)
1287 is = 0;
1288 else if (is >= srcWidth)
1289 is = srcWidth - 1;
1290 if (js < 0)
1291 js = 0;
1292 else if (js >= srcHeight)
1293 js = srcHeight - 1;
1294 k = js * srcWidth + is;
1295 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1296 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1297 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1298 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001299 }
1300 }
Brian Paul7e708742000-08-22 18:54:25 +00001301 dest[j * srcWidth + i][RCOMP] = sumR;
1302 dest[j * srcWidth + i][GCOMP] = sumG;
1303 dest[j * srcWidth + i][BCOMP] = sumB;
1304 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001305 }
1306 }
1307}
1308
1309
1310
1311void
1312_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1313 const GLfloat *srcImage, GLfloat *dstImage)
1314{
1315 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1316 case GL_REDUCE:
1317 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1318 ctx->Convolution1D.Width,
1319 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1320 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001321 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001322 break;
1323 case GL_CONSTANT_BORDER:
1324 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1325 ctx->Convolution1D.Width,
1326 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1327 (GLfloat (*)[4]) dstImage,
1328 ctx->Pixel.ConvolutionBorderColor[0]);
1329 break;
1330 case GL_REPLICATE_BORDER:
1331 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1332 ctx->Convolution1D.Width,
1333 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1334 (GLfloat (*)[4]) dstImage);
1335 break;
1336 default:
1337 ;
1338 }
1339}
1340
1341
1342void
1343_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1344 const GLfloat *srcImage, GLfloat *dstImage)
1345{
1346 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1347 case GL_REDUCE:
1348 convolve_2d_reduce(*width, *height,
1349 (const GLfloat (*)[4]) srcImage,
1350 ctx->Convolution2D.Width,
1351 ctx->Convolution2D.Height,
1352 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1353 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001354 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1355 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001356 break;
1357 case GL_CONSTANT_BORDER:
1358 convolve_2d_constant(*width, *height,
1359 (const GLfloat (*)[4]) srcImage,
1360 ctx->Convolution2D.Width,
1361 ctx->Convolution2D.Height,
1362 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1363 (GLfloat (*)[4]) dstImage,
1364 ctx->Pixel.ConvolutionBorderColor[1]);
1365 break;
1366 case GL_REPLICATE_BORDER:
1367 convolve_2d_replicate(*width, *height,
1368 (const GLfloat (*)[4]) srcImage,
1369 ctx->Convolution2D.Width,
1370 ctx->Convolution2D.Height,
1371 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1372 (GLfloat (*)[4]) dstImage);
1373 break;
1374 default:
1375 ;
1376 }
1377}
1378
1379
1380void
1381_mesa_convolve_sep_image(const GLcontext *ctx,
1382 GLsizei *width, GLsizei *height,
1383 const GLfloat *srcImage, GLfloat *dstImage)
1384{
1385 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1386 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1387
1388 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1389 case GL_REDUCE:
1390 convolve_sep_reduce(*width, *height,
1391 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001392 ctx->Separable2D.Width,
1393 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001394 (const GLfloat (*)[4]) rowFilter,
1395 (const GLfloat (*)[4]) colFilter,
1396 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001397 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1398 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001399 break;
1400 case GL_CONSTANT_BORDER:
1401 convolve_sep_constant(*width, *height,
1402 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001403 ctx->Separable2D.Width,
1404 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001405 (const GLfloat (*)[4]) rowFilter,
1406 (const GLfloat (*)[4]) colFilter,
1407 (GLfloat (*)[4]) dstImage,
1408 ctx->Pixel.ConvolutionBorderColor[2]);
1409 break;
1410 case GL_REPLICATE_BORDER:
1411 convolve_sep_replicate(*width, *height,
1412 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001413 ctx->Separable2D.Width,
1414 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001415 (const GLfloat (*)[4]) rowFilter,
1416 (const GLfloat (*)[4]) colFilter,
1417 (GLfloat (*)[4]) dstImage);
1418 break;
1419 default:
1420 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001421 }
1422}
Brian Paul16461f72001-02-06 17:22:16 +00001423
1424
1425
1426/*
1427 * This function computes an image's size after convolution.
1428 * If the convolution border mode is GL_REDUCE, the post-convolution
1429 * image will be smaller than the original.
1430 */
1431void
1432_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1433 GLsizei *width, GLsizei *height)
1434{
1435 if (ctx->Pixel.Convolution1DEnabled
1436 && dimensions == 1
1437 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1438 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1439 }
1440 else if (ctx->Pixel.Convolution2DEnabled
1441 && dimensions > 1
1442 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1443 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1444 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1445 }
1446 else if (ctx->Pixel.Separable2DEnabled
1447 && dimensions > 1
1448 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1449 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1450 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1451 }
1452}
1453