blob: 8db3e79d384c6ff10d97cfdcc2feb2fad9e4c3d5 [file] [log] [blame]
Brian Paulcc8e37f2000-07-12 13:00:09 +00001/*
2 * Mesa 3-D graphics library
Brian Paul176501d2006-10-13 16:34:25 +00003 * Version: 6.5.2
Brian Paulcc8e37f2000-07-12 13:00:09 +00004 *
Brian Paul176501d2006-10-13 16:34:25 +00005 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
Brian Paulcc8e37f2000-07-12 13:00:09 +00006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/*
27 * Image convolution functions.
28 *
29 * Notes: filter kernel elements are indexed by <n> and <m> as in
30 * the GL spec.
31 */
32
33
Brian Paulcc8e37f2000-07-12 13:00:09 +000034#include "glheader.h"
Brian Paulbd3b40a2004-10-31 17:36:23 +000035#include "bufferobj.h"
Brian Paulc893a012000-10-28 20:41:13 +000036#include "colormac.h"
Brian Pauld4b799b2000-08-21 14:24:30 +000037#include "convolve.h"
38#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000039#include "image.h"
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +000040#include "mtypes.h"
Brian Paul450e9172004-10-31 18:40:55 +000041#include "pixel.h"
Jon Taylorcdfba5d2000-11-23 02:50:56 +000042#include "state.h"
Chia-I Wu5a1e25a2009-09-23 16:56:20 +080043#include "glapi/dispatch.h"
44
45
46#if FEATURE_convolve
Brian Paulcc8e37f2000-07-12 13:00:09 +000047
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
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000109void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000110_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 Paulf959f6e2004-04-22 00:27:31 +0000132 if (!_mesa_is_legal_format_and_type(ctx, 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
Brian Paul95027a02009-09-03 11:23:05 -0600151 image = _mesa_map_validate_pbo_source(ctx,
152 1, &ctx->Unpack, width, 1, 1,
153 format, type, image,
154 "glConvolutionFilter1D");
155 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600156 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000157
Brian Paul8cfd08b2004-02-28 20:35:57 +0000158 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
Brian Paul147b0832000-08-23 14:31:25 +0000159 ctx->Convolution1D.Filter,
160 format, type, image, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000161 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000162
Brian Paul203f3952009-09-03 10:41:14 -0600163 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000164
Brian Paul450e9172004-10-31 18:40:55 +0000165 _mesa_scale_and_bias_rgba(width,
166 (GLfloat (*)[4]) ctx->Convolution1D.Filter,
167 ctx->Pixel.ConvolutionFilterScale[0][0],
168 ctx->Pixel.ConvolutionFilterScale[0][1],
169 ctx->Pixel.ConvolutionFilterScale[0][2],
170 ctx->Pixel.ConvolutionFilterScale[0][3],
171 ctx->Pixel.ConvolutionFilterBias[0][0],
172 ctx->Pixel.ConvolutionFilterBias[0][1],
173 ctx->Pixel.ConvolutionFilterBias[0][2],
174 ctx->Pixel.ConvolutionFilterBias[0][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000175
Brian Paulb5012e12000-11-10 18:31:04 +0000176 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000177}
178
179
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000180void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000181_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
182{
Brian Pauld0570642002-03-19 15:22:50 +0000183 GLint baseFormat;
Brian Paulb3050282003-12-04 03:19:46 +0000184 GLint i;
Brian Paul147b0832000-08-23 14:31:25 +0000185 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000186 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000187
188 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000189 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000190 return;
191 }
192
193 baseFormat = base_filter_format(internalFormat);
194 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000195 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000196 return;
197 }
198
199 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000200 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000201 return;
202 }
203 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000204 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000205 return;
206 }
207
Brian Paulf959f6e2004-04-22 00:27:31 +0000208 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000209 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000210 return;
211 }
212 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000213 format == GL_STENCIL_INDEX ||
214 format == GL_DEPTH_COMPONENT ||
215 format == GL_INTENSITY ||
216 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000217 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000218 return;
219 }
220
Brian Paulb3050282003-12-04 03:19:46 +0000221 /* this should have been caught earlier */
222 assert(_mesa_components_in_format(format));
Brian Paul147b0832000-08-23 14:31:25 +0000223
224 ctx->Convolution2D.Format = format;
225 ctx->Convolution2D.InternalFormat = internalFormat;
226 ctx->Convolution2D.Width = width;
227 ctx->Convolution2D.Height = height;
228
Brian Paul95027a02009-09-03 11:23:05 -0600229 image = _mesa_map_validate_pbo_source(ctx,
230 2, &ctx->Unpack, width, height, 1,
231 format, type, image,
232 "glConvolutionFilter2D");
233 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600234 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000235
Brian Paul147b0832000-08-23 14:31:25 +0000236 /* Unpack filter image. We always store filters in RGBA format. */
237 for (i = 0; i < height; i++) {
Brian Paul60909382004-11-10 15:46:52 +0000238 const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width,
239 height, format, type, i, 0);
Brian Paul147b0832000-08-23 14:31:25 +0000240 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000241 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
Brian Paul147b0832000-08-23 14:31:25 +0000242 format, type, src, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000243 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000244 }
245
Brian Paul203f3952009-09-03 10:41:14 -0600246 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000247
Brian Paul450e9172004-10-31 18:40:55 +0000248 _mesa_scale_and_bias_rgba(width * height,
249 (GLfloat (*)[4]) ctx->Convolution2D.Filter,
250 ctx->Pixel.ConvolutionFilterScale[1][0],
251 ctx->Pixel.ConvolutionFilterScale[1][1],
252 ctx->Pixel.ConvolutionFilterScale[1][2],
253 ctx->Pixel.ConvolutionFilterScale[1][3],
254 ctx->Pixel.ConvolutionFilterBias[1][0],
255 ctx->Pixel.ConvolutionFilterBias[1][1],
256 ctx->Pixel.ConvolutionFilterBias[1][2],
257 ctx->Pixel.ConvolutionFilterBias[1][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000258
Brian Paulb5012e12000-11-10 18:31:04 +0000259 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000260}
261
262
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800263static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000264_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
265{
266 GET_CURRENT_CONTEXT(ctx);
267 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000268 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000269
270 switch (target) {
271 case GL_CONVOLUTION_1D:
272 c = 0;
273 break;
274 case GL_CONVOLUTION_2D:
275 c = 1;
276 break;
277 case GL_SEPARABLE_2D:
278 c = 2;
279 break;
280 default:
Brian Paul08836342001-03-03 20:33:27 +0000281 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000282 return;
283 }
284
285 switch (pname) {
286 case GL_CONVOLUTION_BORDER_MODE:
287 if (param == (GLfloat) GL_REDUCE ||
288 param == (GLfloat) GL_CONSTANT_BORDER ||
289 param == (GLfloat) GL_REPLICATE_BORDER) {
290 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
291 }
292 else {
Brian Paul08836342001-03-03 20:33:27 +0000293 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000294 return;
295 }
296 break;
297 default:
Brian Paul08836342001-03-03 20:33:27 +0000298 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000299 return;
300 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000301
302 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000303}
304
305
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800306static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000307_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
308{
309 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000310 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000311 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000312
313 switch (target) {
314 case GL_CONVOLUTION_1D:
315 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000316 break;
317 case GL_CONVOLUTION_2D:
318 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000319 break;
320 case GL_SEPARABLE_2D:
321 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000322 break;
323 default:
Brian Paul08836342001-03-03 20:33:27 +0000324 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000325 return;
326 }
327
328 switch (pname) {
329 case GL_CONVOLUTION_BORDER_COLOR:
330 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
331 break;
332 case GL_CONVOLUTION_BORDER_MODE:
333 if (params[0] == (GLfloat) GL_REDUCE ||
334 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
335 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
336 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
337 }
338 else {
Brian Paul08836342001-03-03 20:33:27 +0000339 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000340 return;
341 }
342 break;
343 case GL_CONVOLUTION_FILTER_SCALE:
344 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
345 break;
346 case GL_CONVOLUTION_FILTER_BIAS:
347 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
348 break;
349 default:
Brian Paul08836342001-03-03 20:33:27 +0000350 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000351 return;
352 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000353
354 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000355}
356
357
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800358static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000359_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
360{
361 GET_CURRENT_CONTEXT(ctx);
362 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000363 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000364
365 switch (target) {
366 case GL_CONVOLUTION_1D:
367 c = 0;
368 break;
369 case GL_CONVOLUTION_2D:
370 c = 1;
371 break;
372 case GL_SEPARABLE_2D:
373 c = 2;
374 break;
375 default:
Brian Paul08836342001-03-03 20:33:27 +0000376 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000377 return;
378 }
379
380 switch (pname) {
381 case GL_CONVOLUTION_BORDER_MODE:
382 if (param == (GLint) GL_REDUCE ||
383 param == (GLint) GL_CONSTANT_BORDER ||
384 param == (GLint) GL_REPLICATE_BORDER) {
385 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
386 }
387 else {
Brian Paul08836342001-03-03 20:33:27 +0000388 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000389 return;
390 }
391 break;
392 default:
Brian Paul08836342001-03-03 20:33:27 +0000393 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000394 return;
395 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000396
397 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000398}
399
400
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800401static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000402_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
403{
404 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000405 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000406 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000407
408 switch (target) {
409 case GL_CONVOLUTION_1D:
410 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000411 break;
412 case GL_CONVOLUTION_2D:
413 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000414 break;
415 case GL_SEPARABLE_2D:
416 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000417 break;
418 default:
Brian Paul08836342001-03-03 20:33:27 +0000419 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000420 return;
421 }
422
423 switch (pname) {
424 case GL_CONVOLUTION_BORDER_COLOR:
425 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
426 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
427 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
428 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
429 break;
430 case GL_CONVOLUTION_BORDER_MODE:
431 if (params[0] == (GLint) GL_REDUCE ||
432 params[0] == (GLint) GL_CONSTANT_BORDER ||
433 params[0] == (GLint) GL_REPLICATE_BORDER) {
434 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
435 }
436 else {
Brian Paul08836342001-03-03 20:33:27 +0000437 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000438 return;
439 }
440 break;
441 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000442 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
443 /* need cast to prevent compiler warnings */
444 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
445 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
446 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
447 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000448 break;
449 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000450 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
451 /* need cast to prevent compiler warnings */
452 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
453 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
454 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
455 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000456 break;
457 default:
Brian Paul08836342001-03-03 20:33:27 +0000458 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000459 return;
460 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000461
462 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000463}
464
465
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800466static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000467_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
468{
Brian Pauld0570642002-03-19 15:22:50 +0000469 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000470 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000471 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000472
473 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000474 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000475 return;
476 }
477
478 baseFormat = base_filter_format(internalFormat);
479 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000480 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000481 return;
482 }
483
484 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000485 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000486 return;
487 }
488
Brian Pauldc3839e2009-09-19 16:27:59 -0600489 if (!ctx->ReadBuffer->_ColorReadBuffer) {
490 return; /* no readbuffer - OK */
491 }
492
Keith Whitwell70989242001-03-19 02:25:35 +0000493 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
494 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000495}
496
497
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800498static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000499_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
500{
Brian Pauld0570642002-03-19 15:22:50 +0000501 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000502 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000503 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000504
505 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000506 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000507 return;
508 }
509
510 baseFormat = base_filter_format(internalFormat);
511 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000512 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000513 return;
514 }
515
516 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000517 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000518 return;
519 }
520 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000521 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000522 return;
523 }
524
Brian Pauldc3839e2009-09-19 16:27:59 -0600525 if (!ctx->ReadBuffer->_ColorReadBuffer) {
526 return; /* no readbuffer - OK */
527 }
528
Keith Whitwell70989242001-03-19 02:25:35 +0000529 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
530 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000531}
532
533
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800534static void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000535_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type,
536 GLvoid *image)
Brian Paul147b0832000-08-23 14:31:25 +0000537{
Brian Paul176501d2006-10-13 16:34:25 +0000538 struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000539 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000540 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000541 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000542
Brian Paul0c000ec2000-11-21 23:26:13 +0000543 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000544 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000545 }
546
Brian Paulf959f6e2004-04-22 00:27:31 +0000547 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000548 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000549 return;
550 }
551
552 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000553 format == GL_STENCIL_INDEX ||
554 format == GL_DEPTH_COMPONENT ||
555 format == GL_INTENSITY ||
556 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000557 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000558 return;
559 }
560
Brian Paulf75d6972000-09-05 20:28:56 +0000561 switch (target) {
562 case GL_CONVOLUTION_1D:
563 filter = &(ctx->Convolution1D);
564 break;
565 case GL_CONVOLUTION_2D:
566 filter = &(ctx->Convolution2D);
567 break;
568 default:
Brian Paul08836342001-03-03 20:33:27 +0000569 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000570 return;
571 }
572
Brian Paul95027a02009-09-03 11:23:05 -0600573 image = _mesa_map_validate_pbo_dest(ctx, 2, &ctx->Pack,
574 filter->Width, filter->Height, 1,
575 format, type, image,
576 "glGetConvolutionFilter");
577 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600578 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000579
Brian Paulf75d6972000-09-05 20:28:56 +0000580 for (row = 0; row < filter->Height; row++) {
Brian Paul60909382004-11-10 15:46:52 +0000581 GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width,
582 filter->Height, format, type,
583 row, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000584 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + row * filter->Width * 4);
585 _mesa_pack_rgba_span_float(ctx, filter->Width, src,
586 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000587 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000588
Brian Paul203f3952009-09-03 10:41:14 -0600589 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paul147b0832000-08-23 14:31:25 +0000590}
591
592
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800593static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000594_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
595{
596 GET_CURRENT_CONTEXT(ctx);
597 const struct gl_convolution_attrib *conv;
598 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000599 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000600
601 switch (target) {
602 case GL_CONVOLUTION_1D:
603 c = 0;
604 conv = &ctx->Convolution1D;
605 break;
606 case GL_CONVOLUTION_2D:
607 c = 1;
608 conv = &ctx->Convolution2D;
609 break;
610 case GL_SEPARABLE_2D:
611 c = 2;
612 conv = &ctx->Separable2D;
613 break;
614 default:
Brian Paul08836342001-03-03 20:33:27 +0000615 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000616 return;
617 }
618
619 switch (pname) {
620 case GL_CONVOLUTION_BORDER_COLOR:
621 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
622 break;
623 case GL_CONVOLUTION_BORDER_MODE:
624 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
625 break;
626 case GL_CONVOLUTION_FILTER_SCALE:
627 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
628 break;
629 case GL_CONVOLUTION_FILTER_BIAS:
630 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
631 break;
632 case GL_CONVOLUTION_FORMAT:
633 *params = (GLfloat) conv->Format;
634 break;
635 case GL_CONVOLUTION_WIDTH:
636 *params = (GLfloat) conv->Width;
637 break;
638 case GL_CONVOLUTION_HEIGHT:
639 *params = (GLfloat) conv->Height;
640 break;
641 case GL_MAX_CONVOLUTION_WIDTH:
642 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
643 break;
644 case GL_MAX_CONVOLUTION_HEIGHT:
645 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
646 break;
647 default:
Brian Paul08836342001-03-03 20:33:27 +0000648 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000649 return;
650 }
651}
652
653
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800654static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000655_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
656{
657 GET_CURRENT_CONTEXT(ctx);
658 const struct gl_convolution_attrib *conv;
659 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000660 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000661
662 switch (target) {
663 case GL_CONVOLUTION_1D:
664 c = 0;
665 conv = &ctx->Convolution1D;
666 break;
667 case GL_CONVOLUTION_2D:
668 c = 1;
669 conv = &ctx->Convolution2D;
670 break;
671 case GL_SEPARABLE_2D:
672 c = 2;
673 conv = &ctx->Separable2D;
674 break;
675 default:
Brian Paul08836342001-03-03 20:33:27 +0000676 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000677 return;
678 }
679
680 switch (pname) {
681 case GL_CONVOLUTION_BORDER_COLOR:
682 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
683 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
684 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
685 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
686 break;
687 case GL_CONVOLUTION_BORDER_MODE:
688 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
689 break;
690 case GL_CONVOLUTION_FILTER_SCALE:
691 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
692 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
693 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
694 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
695 break;
696 case GL_CONVOLUTION_FILTER_BIAS:
697 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
698 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
699 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
700 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
701 break;
702 case GL_CONVOLUTION_FORMAT:
703 *params = (GLint) conv->Format;
704 break;
705 case GL_CONVOLUTION_WIDTH:
706 *params = (GLint) conv->Width;
707 break;
708 case GL_CONVOLUTION_HEIGHT:
709 *params = (GLint) conv->Height;
710 break;
711 case GL_MAX_CONVOLUTION_WIDTH:
712 *params = (GLint) ctx->Const.MaxConvolutionWidth;
713 break;
714 case GL_MAX_CONVOLUTION_HEIGHT:
715 *params = (GLint) ctx->Const.MaxConvolutionHeight;
716 break;
717 default:
Brian Paul08836342001-03-03 20:33:27 +0000718 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000719 return;
720 }
721}
722
723
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800724static void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000725_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type,
726 GLvoid *row, GLvoid *column, GLvoid *span)
Brian Paul147b0832000-08-23 14:31:25 +0000727{
Brian Paulf75d6972000-09-05 20:28:56 +0000728 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Paul176501d2006-10-13 16:34:25 +0000729 struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000730 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000731 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000732
Brian Paul0c000ec2000-11-21 23:26:13 +0000733 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000734 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000735 }
736
Brian Paul147b0832000-08-23 14:31:25 +0000737 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000738 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000739 return;
740 }
741
Brian Paulf959f6e2004-04-22 00:27:31 +0000742 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul176501d2006-10-13 16:34:25 +0000743 _mesa_error(ctx, GL_INVALID_OPERATION,
744 "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000745 return;
746 }
747
748 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000749 format == GL_STENCIL_INDEX ||
750 format == GL_DEPTH_COMPONENT ||
751 format == GL_INTENSITY ||
752 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000753 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000754 return;
755 }
756
Brian Paulf75d6972000-09-05 20:28:56 +0000757 filter = &ctx->Separable2D;
758
Brian Paul2db37ef2009-09-03 11:41:29 -0600759 /* Get row filter */
760 row = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack,
761 filter->Width, 1, 1,
762 format, type, row,
763 "glGetConvolutionFilter");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000764 if (row) {
Brian Paul60909382004-11-10 15:46:52 +0000765 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width,
766 format, type, 0);
Brian Paul8cfd08b2004-02-28 20:35:57 +0000767 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paul176501d2006-10-13 16:34:25 +0000768 (GLfloat (*)[4]) filter->Filter,
769 format, type, dst, &ctx->Pack, 0x0);
Brian Paul2db37ef2009-09-03 11:41:29 -0600770 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paulf75d6972000-09-05 20:28:56 +0000771 }
772
Brian Paul2db37ef2009-09-03 11:41:29 -0600773 /* get column filter */
774 column = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack,
775 filter->Height, 1, 1,
Brian Pauld75a99e2009-09-03 12:10:53 -0600776 format, type, column,
Brian Paul2db37ef2009-09-03 11:41:29 -0600777 "glGetConvolutionFilter");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000778 if (column) {
Brian Paul60909382004-11-10 15:46:52 +0000779 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height,
780 format, type, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000781 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + colStart);
782 _mesa_pack_rgba_span_float(ctx, filter->Height, src,
783 format, type, dst, &ctx->Pack, 0x0);
Brian Paul2db37ef2009-09-03 11:41:29 -0600784 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paulf75d6972000-09-05 20:28:56 +0000785 }
786
787 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000788}
789
790
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800791static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000792_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
793{
794 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000795 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000796 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000797 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000798
799 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000800 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000801 return;
802 }
803
804 baseFormat = base_filter_format(internalFormat);
805 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000806 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000807 return;
808 }
809
810 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000811 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000812 return;
813 }
814 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000815 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000816 return;
817 }
818
Brian Paulf959f6e2004-04-22 00:27:31 +0000819 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000820 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000821 return;
822 }
823
824 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000825 format == GL_STENCIL_INDEX ||
826 format == GL_DEPTH_COMPONENT ||
827 format == GL_INTENSITY ||
828 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000829 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000830 return;
831 }
832
833 ctx->Separable2D.Format = format;
834 ctx->Separable2D.InternalFormat = internalFormat;
835 ctx->Separable2D.Width = width;
836 ctx->Separable2D.Height = height;
837
Brian Paulbd3b40a2004-10-31 17:36:23 +0000838 /* unpack row filter */
Brian Paul2db37ef2009-09-03 11:41:29 -0600839 row = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack,
840 width, 1, 1,
841 format, type, row,
Brian Pauld75a99e2009-09-03 12:10:53 -0600842 "glSeparableFilter2D");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000843 if (row) {
844 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
845 ctx->Separable2D.Filter,
846 format, type, row, &ctx->Unpack,
Brian Paul2db37ef2009-09-03 11:41:29 -0600847 0x0); /* transferOps */
Brian Paul450e9172004-10-31 18:40:55 +0000848 _mesa_scale_and_bias_rgba(width,
849 (GLfloat (*)[4]) ctx->Separable2D.Filter,
850 ctx->Pixel.ConvolutionFilterScale[2][0],
851 ctx->Pixel.ConvolutionFilterScale[2][1],
852 ctx->Pixel.ConvolutionFilterScale[2][2],
853 ctx->Pixel.ConvolutionFilterScale[2][3],
854 ctx->Pixel.ConvolutionFilterBias[2][0],
855 ctx->Pixel.ConvolutionFilterBias[2][1],
856 ctx->Pixel.ConvolutionFilterBias[2][2],
857 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul2db37ef2009-09-03 11:41:29 -0600858 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paul147b0832000-08-23 14:31:25 +0000859 }
860
861 /* unpack column filter */
Brian Paul2db37ef2009-09-03 11:41:29 -0600862 column = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack,
863 height, 1, 1,
Brian Pauld75a99e2009-09-03 12:10:53 -0600864 format, type, column,
865 "glSeparableFilter2D");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000866 if (column) {
Brian Pauleffb7202004-10-31 18:41:38 +0000867 _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
868 &ctx->Separable2D.Filter[colStart],
869 format, type, column, &ctx->Unpack,
870 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000871
Brian Paul450e9172004-10-31 18:40:55 +0000872 _mesa_scale_and_bias_rgba(height,
873 (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart),
874 ctx->Pixel.ConvolutionFilterScale[2][0],
875 ctx->Pixel.ConvolutionFilterScale[2][1],
876 ctx->Pixel.ConvolutionFilterScale[2][2],
877 ctx->Pixel.ConvolutionFilterScale[2][3],
878 ctx->Pixel.ConvolutionFilterBias[2][0],
879 ctx->Pixel.ConvolutionFilterBias[2][1],
880 ctx->Pixel.ConvolutionFilterBias[2][2],
881 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul2db37ef2009-09-03 11:41:29 -0600882 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000883 }
884
Brian Paul434ec3a2009-08-12 13:46:16 -0600885 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000886 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
887 ctx->Unpack.BufferObj);
Brian Paul147b0832000-08-23 14:31:25 +0000888 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000889
Brian Paulb5012e12000-11-10 18:31:04 +0000890 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000891}
892
893
894/**********************************************************************/
895/*** image convolution functions ***/
896/**********************************************************************/
897
Brian Pauld4b799b2000-08-21 14:24:30 +0000898static void
899convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
900 GLint filterWidth, const GLfloat filter[][4],
901 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000902{
Brian Paul7e708742000-08-22 18:54:25 +0000903 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000904 GLint i, n;
905
Brian Paul7e708742000-08-22 18:54:25 +0000906 if (filterWidth >= 1)
907 dstWidth = srcWidth - (filterWidth - 1);
908 else
909 dstWidth = srcWidth;
910
Brian Paulcc8e37f2000-07-12 13:00:09 +0000911 if (dstWidth <= 0)
912 return; /* null result */
913
914 for (i = 0; i < dstWidth; i++) {
915 GLfloat sumR = 0.0;
916 GLfloat sumG = 0.0;
917 GLfloat sumB = 0.0;
918 GLfloat sumA = 0.0;
919 for (n = 0; n < filterWidth; n++) {
920 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
921 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
922 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
923 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
924 }
925 dest[i][RCOMP] = sumR;
926 dest[i][GCOMP] = sumG;
927 dest[i][BCOMP] = sumB;
928 dest[i][ACOMP] = sumA;
929 }
930}
931
932
Brian Pauld4b799b2000-08-21 14:24:30 +0000933static void
934convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
935 GLint filterWidth, const GLfloat filter[][4],
936 GLfloat dest[][4],
937 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000938{
939 const GLint halfFilterWidth = filterWidth / 2;
940 GLint i, n;
941
942 for (i = 0; i < srcWidth; i++) {
943 GLfloat sumR = 0.0;
944 GLfloat sumG = 0.0;
945 GLfloat sumB = 0.0;
946 GLfloat sumA = 0.0;
947 for (n = 0; n < filterWidth; n++) {
948 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
949 sumR += borderColor[RCOMP] * filter[n][RCOMP];
950 sumG += borderColor[GCOMP] * filter[n][GCOMP];
951 sumB += borderColor[BCOMP] * filter[n][BCOMP];
952 sumA += borderColor[ACOMP] * filter[n][ACOMP];
953 }
954 else {
955 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
956 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
957 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
958 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
959 }
960 }
961 dest[i][RCOMP] = sumR;
962 dest[i][GCOMP] = sumG;
963 dest[i][BCOMP] = sumB;
964 dest[i][ACOMP] = sumA;
965 }
966}
967
968
Brian Pauld4b799b2000-08-21 14:24:30 +0000969static void
970convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
971 GLint filterWidth, const GLfloat filter[][4],
972 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000973{
974 const GLint halfFilterWidth = filterWidth / 2;
975 GLint i, n;
976
977 for (i = 0; i < srcWidth; i++) {
978 GLfloat sumR = 0.0;
979 GLfloat sumG = 0.0;
980 GLfloat sumB = 0.0;
981 GLfloat sumA = 0.0;
982 for (n = 0; n < filterWidth; n++) {
983 if (i + n < halfFilterWidth) {
984 sumR += src[0][RCOMP] * filter[n][RCOMP];
985 sumG += src[0][GCOMP] * filter[n][GCOMP];
986 sumB += src[0][BCOMP] * filter[n][BCOMP];
987 sumA += src[0][ACOMP] * filter[n][ACOMP];
988 }
989 else if (i + n - halfFilterWidth >= srcWidth) {
990 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
991 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
992 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
993 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
994 }
995 else {
996 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
997 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
998 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
999 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1000 }
1001 }
1002 dest[i][RCOMP] = sumR;
1003 dest[i][GCOMP] = sumG;
1004 dest[i][BCOMP] = sumB;
1005 dest[i][ACOMP] = sumA;
1006 }
1007}
1008
1009
Brian Pauld4b799b2000-08-21 14:24:30 +00001010static void
1011convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1012 const GLfloat src[][4],
1013 GLint filterWidth, GLint filterHeight,
1014 const GLfloat filter[][4],
1015 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001016{
Brian Paul7e708742000-08-22 18:54:25 +00001017 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001018 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001019
Brian Paul7e708742000-08-22 18:54:25 +00001020 if (filterWidth >= 1)
1021 dstWidth = srcWidth - (filterWidth - 1);
1022 else
1023 dstWidth = srcWidth;
1024
1025 if (filterHeight >= 1)
1026 dstHeight = srcHeight - (filterHeight - 1);
1027 else
1028 dstHeight = srcHeight;
1029
Brian Pauld4b799b2000-08-21 14:24:30 +00001030 if (dstWidth <= 0 || dstHeight <= 0)
1031 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001032
Brian Pauld4b799b2000-08-21 14:24:30 +00001033 for (j = 0; j < dstHeight; j++) {
1034 for (i = 0; i < dstWidth; i++) {
1035 GLfloat sumR = 0.0;
1036 GLfloat sumG = 0.0;
1037 GLfloat sumB = 0.0;
1038 GLfloat sumA = 0.0;
1039 for (m = 0; m < filterHeight; m++) {
1040 for (n = 0; n < filterWidth; n++) {
1041 const GLint k = (j + m) * srcWidth + i + n;
1042 const GLint f = m * filterWidth + n;
1043 sumR += src[k][RCOMP] * filter[f][RCOMP];
1044 sumG += src[k][GCOMP] * filter[f][GCOMP];
1045 sumB += src[k][BCOMP] * filter[f][BCOMP];
1046 sumA += src[k][ACOMP] * filter[f][ACOMP];
1047 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001048 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001049 dest[j * dstWidth + i][RCOMP] = sumR;
1050 dest[j * dstWidth + i][GCOMP] = sumG;
1051 dest[j * dstWidth + i][BCOMP] = sumB;
1052 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001053 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001054 }
1055}
1056
1057
Brian Pauld4b799b2000-08-21 14:24:30 +00001058static void
1059convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1060 const GLfloat src[][4],
1061 GLint filterWidth, GLint filterHeight,
1062 const GLfloat filter[][4],
1063 GLfloat dest[][4],
1064 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001065{
1066 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001067 const GLint halfFilterHeight = filterHeight / 2;
1068 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001069
Brian Pauld4b799b2000-08-21 14:24:30 +00001070 for (j = 0; j < srcHeight; j++) {
1071 for (i = 0; i < srcWidth; i++) {
1072 GLfloat sumR = 0.0;
1073 GLfloat sumG = 0.0;
1074 GLfloat sumB = 0.0;
1075 GLfloat sumA = 0.0;
1076 for (m = 0; m < filterHeight; m++) {
1077 for (n = 0; n < filterWidth; n++) {
1078 const GLint f = m * filterWidth + n;
1079 const GLint is = i + n - halfFilterWidth;
1080 const GLint js = j + m - halfFilterHeight;
1081 if (is < 0 || is >= srcWidth ||
1082 js < 0 || js >= srcHeight) {
1083 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1084 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1085 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1086 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1087 }
1088 else {
1089 const GLint k = js * srcWidth + is;
1090 sumR += src[k][RCOMP] * filter[f][RCOMP];
1091 sumG += src[k][GCOMP] * filter[f][GCOMP];
1092 sumB += src[k][BCOMP] * filter[f][BCOMP];
1093 sumA += src[k][ACOMP] * filter[f][ACOMP];
1094 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001095 }
1096 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001097 dest[j * srcWidth + i][RCOMP] = sumR;
1098 dest[j * srcWidth + i][GCOMP] = sumG;
1099 dest[j * srcWidth + i][BCOMP] = sumB;
1100 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001101 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001102 }
1103}
1104
1105
Brian Pauld4b799b2000-08-21 14:24:30 +00001106static void
1107convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1108 const GLfloat src[][4],
1109 GLint filterWidth, GLint filterHeight,
1110 const GLfloat filter[][4],
1111 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001112{
1113 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001114 const GLint halfFilterHeight = filterHeight / 2;
1115 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001116
Brian Pauld4b799b2000-08-21 14:24:30 +00001117 for (j = 0; j < srcHeight; j++) {
1118 for (i = 0; i < srcWidth; i++) {
1119 GLfloat sumR = 0.0;
1120 GLfloat sumG = 0.0;
1121 GLfloat sumB = 0.0;
1122 GLfloat sumA = 0.0;
1123 for (m = 0; m < filterHeight; m++) {
1124 for (n = 0; n < filterWidth; n++) {
1125 const GLint f = m * filterWidth + n;
1126 GLint is = i + n - halfFilterWidth;
1127 GLint js = j + m - halfFilterHeight;
1128 GLint k;
1129 if (is < 0)
1130 is = 0;
1131 else if (is >= srcWidth)
1132 is = srcWidth - 1;
1133 if (js < 0)
1134 js = 0;
1135 else if (js >= srcHeight)
1136 js = srcHeight - 1;
1137 k = js * srcWidth + is;
1138 sumR += src[k][RCOMP] * filter[f][RCOMP];
1139 sumG += src[k][GCOMP] * filter[f][GCOMP];
1140 sumB += src[k][BCOMP] * filter[f][BCOMP];
1141 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001142 }
1143 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001144 dest[j * srcWidth + i][RCOMP] = sumR;
1145 dest[j * srcWidth + i][GCOMP] = sumG;
1146 dest[j * srcWidth + i][BCOMP] = sumB;
1147 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001148 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001149 }
1150}
1151
1152
Brian Pauld4b799b2000-08-21 14:24:30 +00001153static void
1154convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1155 const GLfloat src[][4],
1156 GLint filterWidth, GLint filterHeight,
1157 const GLfloat rowFilt[][4],
1158 const GLfloat colFilt[][4],
1159 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001160{
Brian Paul7e708742000-08-22 18:54:25 +00001161 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001162 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001163
1164 if (filterWidth >= 1)
1165 dstWidth = srcWidth - (filterWidth - 1);
1166 else
1167 dstWidth = srcWidth;
1168
1169 if (filterHeight >= 1)
1170 dstHeight = srcHeight - (filterHeight - 1);
1171 else
1172 dstHeight = srcHeight;
1173
1174 if (dstWidth <= 0 || dstHeight <= 0)
1175 return;
1176
1177 for (j = 0; j < dstHeight; j++) {
1178 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001179 GLfloat sumR = 0.0;
1180 GLfloat sumG = 0.0;
1181 GLfloat sumB = 0.0;
1182 GLfloat sumA = 0.0;
1183 for (m = 0; m < filterHeight; m++) {
1184 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001185 GLint k = (j + m) * srcWidth + i + n;
1186 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1187 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1188 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1189 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001190 }
1191 }
Brian Paul7e708742000-08-22 18:54:25 +00001192 dest[j * dstWidth + i][RCOMP] = sumR;
1193 dest[j * dstWidth + i][GCOMP] = sumG;
1194 dest[j * dstWidth + i][BCOMP] = sumB;
1195 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001196 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001197 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001198}
1199
1200
Brian Pauld4b799b2000-08-21 14:24:30 +00001201static void
1202convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1203 const GLfloat src[][4],
1204 GLint filterWidth, GLint filterHeight,
1205 const GLfloat rowFilt[][4],
1206 const GLfloat colFilt[][4],
1207 GLfloat dest[][4],
1208 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001209{
1210 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001211 const GLint halfFilterHeight = filterHeight / 2;
1212 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001213
Brian Pauld4b799b2000-08-21 14:24:30 +00001214 for (j = 0; j < srcHeight; j++) {
1215 for (i = 0; i < srcWidth; i++) {
1216 GLfloat sumR = 0.0;
1217 GLfloat sumG = 0.0;
1218 GLfloat sumB = 0.0;
1219 GLfloat sumA = 0.0;
1220 for (m = 0; m < filterHeight; m++) {
1221 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001222 const GLint is = i + n - halfFilterWidth;
1223 const GLint js = j + m - halfFilterHeight;
1224 if (is < 0 || is >= srcWidth ||
1225 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001226 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1227 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1228 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1229 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1230 }
1231 else {
Brian Paul7e708742000-08-22 18:54:25 +00001232 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001233 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1234 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1235 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1236 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1237 }
Brian Paul7e708742000-08-22 18:54:25 +00001238
Brian Paulcc8e37f2000-07-12 13:00:09 +00001239 }
1240 }
Brian Paul7e708742000-08-22 18:54:25 +00001241 dest[j * srcWidth + i][RCOMP] = sumR;
1242 dest[j * srcWidth + i][GCOMP] = sumG;
1243 dest[j * srcWidth + i][BCOMP] = sumB;
1244 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001245 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001246 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001247}
1248
1249
1250static void
1251convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1252 const GLfloat src[][4],
1253 GLint filterWidth, GLint filterHeight,
1254 const GLfloat rowFilt[][4],
1255 const GLfloat colFilt[][4],
1256 GLfloat dest[][4])
1257{
1258 const GLint halfFilterWidth = filterWidth / 2;
1259 const GLint halfFilterHeight = filterHeight / 2;
1260 GLint i, j, n, m;
1261
1262 for (j = 0; j < srcHeight; j++) {
1263 for (i = 0; i < srcWidth; i++) {
1264 GLfloat sumR = 0.0;
1265 GLfloat sumG = 0.0;
1266 GLfloat sumB = 0.0;
1267 GLfloat sumA = 0.0;
1268 for (m = 0; m < filterHeight; m++) {
1269 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001270 GLint is = i + n - halfFilterWidth;
1271 GLint js = j + m - halfFilterHeight;
1272 GLint k;
1273 if (is < 0)
1274 is = 0;
1275 else if (is >= srcWidth)
1276 is = srcWidth - 1;
1277 if (js < 0)
1278 js = 0;
1279 else if (js >= srcHeight)
1280 js = srcHeight - 1;
1281 k = js * srcWidth + is;
1282 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1283 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1284 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1285 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001286 }
1287 }
Brian Paul7e708742000-08-22 18:54:25 +00001288 dest[j * srcWidth + i][RCOMP] = sumR;
1289 dest[j * srcWidth + i][GCOMP] = sumG;
1290 dest[j * srcWidth + i][BCOMP] = sumB;
1291 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001292 }
1293 }
1294}
1295
1296
1297
1298void
1299_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1300 const GLfloat *srcImage, GLfloat *dstImage)
1301{
1302 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1303 case GL_REDUCE:
1304 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1305 ctx->Convolution1D.Width,
1306 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1307 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001308 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001309 break;
1310 case GL_CONSTANT_BORDER:
1311 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1312 ctx->Convolution1D.Width,
1313 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1314 (GLfloat (*)[4]) dstImage,
1315 ctx->Pixel.ConvolutionBorderColor[0]);
1316 break;
1317 case GL_REPLICATE_BORDER:
1318 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1319 ctx->Convolution1D.Width,
1320 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1321 (GLfloat (*)[4]) dstImage);
1322 break;
1323 default:
1324 ;
1325 }
1326}
1327
1328
1329void
1330_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1331 const GLfloat *srcImage, GLfloat *dstImage)
1332{
1333 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1334 case GL_REDUCE:
1335 convolve_2d_reduce(*width, *height,
1336 (const GLfloat (*)[4]) srcImage,
1337 ctx->Convolution2D.Width,
1338 ctx->Convolution2D.Height,
1339 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1340 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001341 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1342 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001343 break;
1344 case GL_CONSTANT_BORDER:
1345 convolve_2d_constant(*width, *height,
1346 (const GLfloat (*)[4]) srcImage,
1347 ctx->Convolution2D.Width,
1348 ctx->Convolution2D.Height,
1349 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1350 (GLfloat (*)[4]) dstImage,
1351 ctx->Pixel.ConvolutionBorderColor[1]);
1352 break;
1353 case GL_REPLICATE_BORDER:
1354 convolve_2d_replicate(*width, *height,
1355 (const GLfloat (*)[4]) srcImage,
1356 ctx->Convolution2D.Width,
1357 ctx->Convolution2D.Height,
1358 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1359 (GLfloat (*)[4]) dstImage);
1360 break;
1361 default:
1362 ;
1363 }
1364}
1365
1366
1367void
1368_mesa_convolve_sep_image(const GLcontext *ctx,
1369 GLsizei *width, GLsizei *height,
1370 const GLfloat *srcImage, GLfloat *dstImage)
1371{
1372 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1373 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1374
1375 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1376 case GL_REDUCE:
1377 convolve_sep_reduce(*width, *height,
1378 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001379 ctx->Separable2D.Width,
1380 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001381 (const GLfloat (*)[4]) rowFilter,
1382 (const GLfloat (*)[4]) colFilter,
1383 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001384 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1385 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001386 break;
1387 case GL_CONSTANT_BORDER:
1388 convolve_sep_constant(*width, *height,
1389 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001390 ctx->Separable2D.Width,
1391 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001392 (const GLfloat (*)[4]) rowFilter,
1393 (const GLfloat (*)[4]) colFilter,
1394 (GLfloat (*)[4]) dstImage,
1395 ctx->Pixel.ConvolutionBorderColor[2]);
1396 break;
1397 case GL_REPLICATE_BORDER:
1398 convolve_sep_replicate(*width, *height,
1399 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001400 ctx->Separable2D.Width,
1401 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001402 (const GLfloat (*)[4]) rowFilter,
1403 (const GLfloat (*)[4]) colFilter,
1404 (GLfloat (*)[4]) dstImage);
1405 break;
1406 default:
1407 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001408 }
1409}
Brian Paul16461f72001-02-06 17:22:16 +00001410
1411
1412
1413/*
1414 * This function computes an image's size after convolution.
1415 * If the convolution border mode is GL_REDUCE, the post-convolution
1416 * image will be smaller than the original.
1417 */
1418void
1419_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1420 GLsizei *width, GLsizei *height)
1421{
1422 if (ctx->Pixel.Convolution1DEnabled
1423 && dimensions == 1
1424 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1425 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1426 }
1427 else if (ctx->Pixel.Convolution2DEnabled
1428 && dimensions > 1
1429 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1430 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1431 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1432 }
1433 else if (ctx->Pixel.Separable2DEnabled
1434 && dimensions > 1
1435 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1436 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1437 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1438 }
1439}
Chia-I Wu5a1e25a2009-09-23 16:56:20 +08001440
1441
1442void
1443_mesa_init_convolve_dispatch(struct _glapi_table *disp)
1444{
1445 SET_ConvolutionFilter1D(disp, _mesa_ConvolutionFilter1D);
1446 SET_ConvolutionFilter2D(disp, _mesa_ConvolutionFilter2D);
1447 SET_ConvolutionParameterf(disp, _mesa_ConvolutionParameterf);
1448 SET_ConvolutionParameterfv(disp, _mesa_ConvolutionParameterfv);
1449 SET_ConvolutionParameteri(disp, _mesa_ConvolutionParameteri);
1450 SET_ConvolutionParameteriv(disp, _mesa_ConvolutionParameteriv);
1451 SET_CopyConvolutionFilter1D(disp, _mesa_CopyConvolutionFilter1D);
1452 SET_CopyConvolutionFilter2D(disp, _mesa_CopyConvolutionFilter2D);
1453 SET_GetConvolutionFilter(disp, _mesa_GetConvolutionFilter);
1454 SET_GetConvolutionParameterfv(disp, _mesa_GetConvolutionParameterfv);
1455 SET_GetConvolutionParameteriv(disp, _mesa_GetConvolutionParameteriv);
1456 SET_SeparableFilter2D(disp, _mesa_SeparableFilter2D);
1457 SET_GetSeparableFilter(disp, _mesa_GetSeparableFilter);
1458}
1459
1460
1461#endif /* FEATURE_convolve */