blob: 5ed93e0c600459623014a192b797d5ad4d69aa5e [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"
Jon Taylorcdfba5d2000-11-23 02:50:56 +000041#include "state.h"
Chia-I Wu5a1e25a2009-09-23 16:56:20 +080042#include "glapi/dispatch.h"
43
44
45#if FEATURE_convolve
Brian Paulcc8e37f2000-07-12 13:00:09 +000046
47
Brian Paul147b0832000-08-23 14:31:25 +000048/*
49 * Given an internalFormat token passed to glConvolutionFilter
50 * or glSeparableFilter, return the corresponding base format.
51 * Return -1 if invalid token.
52 */
53static GLint
54base_filter_format( GLenum format )
55{
56 switch (format) {
57 case GL_ALPHA:
58 case GL_ALPHA4:
59 case GL_ALPHA8:
60 case GL_ALPHA12:
61 case GL_ALPHA16:
62 return GL_ALPHA;
63 case GL_LUMINANCE:
64 case GL_LUMINANCE4:
65 case GL_LUMINANCE8:
66 case GL_LUMINANCE12:
67 case GL_LUMINANCE16:
68 return GL_LUMINANCE;
69 case GL_LUMINANCE_ALPHA:
70 case GL_LUMINANCE4_ALPHA4:
71 case GL_LUMINANCE6_ALPHA2:
72 case GL_LUMINANCE8_ALPHA8:
73 case GL_LUMINANCE12_ALPHA4:
74 case GL_LUMINANCE12_ALPHA12:
75 case GL_LUMINANCE16_ALPHA16:
76 return GL_LUMINANCE_ALPHA;
77 case GL_INTENSITY:
78 case GL_INTENSITY4:
79 case GL_INTENSITY8:
80 case GL_INTENSITY12:
81 case GL_INTENSITY16:
82 return GL_INTENSITY;
83 case GL_RGB:
84 case GL_R3_G3_B2:
85 case GL_RGB4:
86 case GL_RGB5:
87 case GL_RGB8:
88 case GL_RGB10:
89 case GL_RGB12:
90 case GL_RGB16:
91 return GL_RGB;
92 case 4:
93 case GL_RGBA:
94 case GL_RGBA2:
95 case GL_RGBA4:
96 case GL_RGB5_A1:
97 case GL_RGBA8:
98 case GL_RGB10_A2:
99 case GL_RGBA12:
100 case GL_RGBA16:
101 return GL_RGBA;
102 default:
103 return -1; /* error */
104 }
105}
106
107
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000108void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000109_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
110{
Brian Pauld0570642002-03-19 15:22:50 +0000111 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000112 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000113 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000114
115 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000116 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000117 return;
118 }
119
120 baseFormat = base_filter_format(internalFormat);
121 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000122 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000123 return;
124 }
125
126 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000127 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000128 return;
129 }
130
Brian Paulf959f6e2004-04-22 00:27:31 +0000131 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000132 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000133 return;
134 }
135
136 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000137 format == GL_STENCIL_INDEX ||
138 format == GL_DEPTH_COMPONENT ||
139 format == GL_INTENSITY ||
140 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000141 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000142 return;
143 }
144
145 ctx->Convolution1D.Format = format;
146 ctx->Convolution1D.InternalFormat = internalFormat;
147 ctx->Convolution1D.Width = width;
148 ctx->Convolution1D.Height = 1;
149
Brian Paul95027a02009-09-03 11:23:05 -0600150 image = _mesa_map_validate_pbo_source(ctx,
151 1, &ctx->Unpack, width, 1, 1,
152 format, type, image,
153 "glConvolutionFilter1D");
154 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600155 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000156
Brian Paul8cfd08b2004-02-28 20:35:57 +0000157 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
Brian Paul147b0832000-08-23 14:31:25 +0000158 ctx->Convolution1D.Filter,
159 format, type, image, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000160 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000161
Brian Paul203f3952009-09-03 10:41:14 -0600162 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000163
Brian Paul450e9172004-10-31 18:40:55 +0000164 _mesa_scale_and_bias_rgba(width,
165 (GLfloat (*)[4]) ctx->Convolution1D.Filter,
166 ctx->Pixel.ConvolutionFilterScale[0][0],
167 ctx->Pixel.ConvolutionFilterScale[0][1],
168 ctx->Pixel.ConvolutionFilterScale[0][2],
169 ctx->Pixel.ConvolutionFilterScale[0][3],
170 ctx->Pixel.ConvolutionFilterBias[0][0],
171 ctx->Pixel.ConvolutionFilterBias[0][1],
172 ctx->Pixel.ConvolutionFilterBias[0][2],
173 ctx->Pixel.ConvolutionFilterBias[0][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000174
Brian Paulb5012e12000-11-10 18:31:04 +0000175 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000176}
177
178
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000179void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000180_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
181{
Brian Pauld0570642002-03-19 15:22:50 +0000182 GLint baseFormat;
Brian Paulb3050282003-12-04 03:19:46 +0000183 GLint i;
Brian Paul147b0832000-08-23 14:31:25 +0000184 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000185 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000186
187 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000188 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000189 return;
190 }
191
192 baseFormat = base_filter_format(internalFormat);
193 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000194 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000195 return;
196 }
197
198 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000199 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000200 return;
201 }
202 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000203 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000204 return;
205 }
206
Brian Paulf959f6e2004-04-22 00:27:31 +0000207 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000208 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000209 return;
210 }
211 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000212 format == GL_STENCIL_INDEX ||
213 format == GL_DEPTH_COMPONENT ||
214 format == GL_INTENSITY ||
215 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000216 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000217 return;
218 }
219
Brian Paulb3050282003-12-04 03:19:46 +0000220 /* this should have been caught earlier */
221 assert(_mesa_components_in_format(format));
Brian Paul147b0832000-08-23 14:31:25 +0000222
223 ctx->Convolution2D.Format = format;
224 ctx->Convolution2D.InternalFormat = internalFormat;
225 ctx->Convolution2D.Width = width;
226 ctx->Convolution2D.Height = height;
227
Brian Paul95027a02009-09-03 11:23:05 -0600228 image = _mesa_map_validate_pbo_source(ctx,
229 2, &ctx->Unpack, width, height, 1,
230 format, type, image,
231 "glConvolutionFilter2D");
232 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600233 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000234
Brian Paul147b0832000-08-23 14:31:25 +0000235 /* Unpack filter image. We always store filters in RGBA format. */
236 for (i = 0; i < height; i++) {
Brian Paul60909382004-11-10 15:46:52 +0000237 const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width,
238 height, format, type, i, 0);
Brian Paul147b0832000-08-23 14:31:25 +0000239 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000240 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
Brian Paul147b0832000-08-23 14:31:25 +0000241 format, type, src, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000242 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000243 }
244
Brian Paul203f3952009-09-03 10:41:14 -0600245 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000246
Brian Paul450e9172004-10-31 18:40:55 +0000247 _mesa_scale_and_bias_rgba(width * height,
248 (GLfloat (*)[4]) ctx->Convolution2D.Filter,
249 ctx->Pixel.ConvolutionFilterScale[1][0],
250 ctx->Pixel.ConvolutionFilterScale[1][1],
251 ctx->Pixel.ConvolutionFilterScale[1][2],
252 ctx->Pixel.ConvolutionFilterScale[1][3],
253 ctx->Pixel.ConvolutionFilterBias[1][0],
254 ctx->Pixel.ConvolutionFilterBias[1][1],
255 ctx->Pixel.ConvolutionFilterBias[1][2],
256 ctx->Pixel.ConvolutionFilterBias[1][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000257
Brian Paulb5012e12000-11-10 18:31:04 +0000258 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000259}
260
261
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800262static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000263_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
264{
265 GET_CURRENT_CONTEXT(ctx);
266 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000267 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000268
269 switch (target) {
270 case GL_CONVOLUTION_1D:
271 c = 0;
272 break;
273 case GL_CONVOLUTION_2D:
274 c = 1;
275 break;
276 case GL_SEPARABLE_2D:
277 c = 2;
278 break;
279 default:
Brian Paul08836342001-03-03 20:33:27 +0000280 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000281 return;
282 }
283
284 switch (pname) {
285 case GL_CONVOLUTION_BORDER_MODE:
286 if (param == (GLfloat) GL_REDUCE ||
287 param == (GLfloat) GL_CONSTANT_BORDER ||
288 param == (GLfloat) GL_REPLICATE_BORDER) {
289 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
290 }
291 else {
Brian Paul08836342001-03-03 20:33:27 +0000292 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000293 return;
294 }
295 break;
296 default:
Brian Paul08836342001-03-03 20:33:27 +0000297 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000298 return;
299 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000300
301 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000302}
303
304
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800305static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000306_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
307{
308 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000309 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000310 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000311
312 switch (target) {
313 case GL_CONVOLUTION_1D:
314 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000315 break;
316 case GL_CONVOLUTION_2D:
317 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000318 break;
319 case GL_SEPARABLE_2D:
320 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000321 break;
322 default:
Brian Paul08836342001-03-03 20:33:27 +0000323 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000324 return;
325 }
326
327 switch (pname) {
328 case GL_CONVOLUTION_BORDER_COLOR:
329 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
330 break;
331 case GL_CONVOLUTION_BORDER_MODE:
332 if (params[0] == (GLfloat) GL_REDUCE ||
333 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
334 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
335 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
336 }
337 else {
Brian Paul08836342001-03-03 20:33:27 +0000338 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000339 return;
340 }
341 break;
342 case GL_CONVOLUTION_FILTER_SCALE:
343 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
344 break;
345 case GL_CONVOLUTION_FILTER_BIAS:
346 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
347 break;
348 default:
Brian Paul08836342001-03-03 20:33:27 +0000349 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000350 return;
351 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000352
353 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000354}
355
356
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800357static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000358_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
359{
360 GET_CURRENT_CONTEXT(ctx);
361 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000362 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000363
364 switch (target) {
365 case GL_CONVOLUTION_1D:
366 c = 0;
367 break;
368 case GL_CONVOLUTION_2D:
369 c = 1;
370 break;
371 case GL_SEPARABLE_2D:
372 c = 2;
373 break;
374 default:
Brian Paul08836342001-03-03 20:33:27 +0000375 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000376 return;
377 }
378
379 switch (pname) {
380 case GL_CONVOLUTION_BORDER_MODE:
381 if (param == (GLint) GL_REDUCE ||
382 param == (GLint) GL_CONSTANT_BORDER ||
383 param == (GLint) GL_REPLICATE_BORDER) {
384 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
385 }
386 else {
Brian Paul08836342001-03-03 20:33:27 +0000387 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000388 return;
389 }
390 break;
391 default:
Brian Paul08836342001-03-03 20:33:27 +0000392 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000393 return;
394 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000395
396 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000397}
398
399
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800400static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000401_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
402{
403 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000404 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000405 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000406
407 switch (target) {
408 case GL_CONVOLUTION_1D:
409 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000410 break;
411 case GL_CONVOLUTION_2D:
412 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000413 break;
414 case GL_SEPARABLE_2D:
415 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000416 break;
417 default:
Brian Paul08836342001-03-03 20:33:27 +0000418 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000419 return;
420 }
421
422 switch (pname) {
423 case GL_CONVOLUTION_BORDER_COLOR:
424 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
425 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
426 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
427 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
428 break;
429 case GL_CONVOLUTION_BORDER_MODE:
430 if (params[0] == (GLint) GL_REDUCE ||
431 params[0] == (GLint) GL_CONSTANT_BORDER ||
432 params[0] == (GLint) GL_REPLICATE_BORDER) {
433 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
434 }
435 else {
Brian Paul08836342001-03-03 20:33:27 +0000436 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000437 return;
438 }
439 break;
440 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000441 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
442 /* need cast to prevent compiler warnings */
443 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
444 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
445 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
446 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000447 break;
448 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000449 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
450 /* need cast to prevent compiler warnings */
451 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
452 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
453 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
454 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000455 break;
456 default:
Brian Paul08836342001-03-03 20:33:27 +0000457 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000458 return;
459 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000460
461 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000462}
463
464
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800465static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000466_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
467{
Brian Pauld0570642002-03-19 15:22:50 +0000468 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000469 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000470 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000471
472 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000473 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000474 return;
475 }
476
477 baseFormat = base_filter_format(internalFormat);
478 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000479 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000480 return;
481 }
482
483 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000484 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000485 return;
486 }
487
Brian Pauldc3839e2009-09-19 16:27:59 -0600488 if (!ctx->ReadBuffer->_ColorReadBuffer) {
489 return; /* no readbuffer - OK */
490 }
491
Keith Whitwell70989242001-03-19 02:25:35 +0000492 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
493 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000494}
495
496
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800497static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000498_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
499{
Brian Pauld0570642002-03-19 15:22:50 +0000500 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000501 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000502 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000503
504 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000505 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000506 return;
507 }
508
509 baseFormat = base_filter_format(internalFormat);
510 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000511 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000512 return;
513 }
514
515 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000516 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000517 return;
518 }
519 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000520 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000521 return;
522 }
523
Brian Pauldc3839e2009-09-19 16:27:59 -0600524 if (!ctx->ReadBuffer->_ColorReadBuffer) {
525 return; /* no readbuffer - OK */
526 }
527
Keith Whitwell70989242001-03-19 02:25:35 +0000528 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
529 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000530}
531
532
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800533static void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000534_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type,
535 GLvoid *image)
Brian Paul147b0832000-08-23 14:31:25 +0000536{
Brian Paul176501d2006-10-13 16:34:25 +0000537 struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000538 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000539 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000540 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000541
Brian Paul0c000ec2000-11-21 23:26:13 +0000542 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000543 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000544 }
545
Brian Paulf959f6e2004-04-22 00:27:31 +0000546 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000547 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000548 return;
549 }
550
551 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000552 format == GL_STENCIL_INDEX ||
553 format == GL_DEPTH_COMPONENT ||
554 format == GL_INTENSITY ||
555 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000556 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000557 return;
558 }
559
Brian Paulf75d6972000-09-05 20:28:56 +0000560 switch (target) {
561 case GL_CONVOLUTION_1D:
562 filter = &(ctx->Convolution1D);
563 break;
564 case GL_CONVOLUTION_2D:
565 filter = &(ctx->Convolution2D);
566 break;
567 default:
Brian Paul08836342001-03-03 20:33:27 +0000568 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000569 return;
570 }
571
Brian Paul95027a02009-09-03 11:23:05 -0600572 image = _mesa_map_validate_pbo_dest(ctx, 2, &ctx->Pack,
573 filter->Width, filter->Height, 1,
574 format, type, image,
575 "glGetConvolutionFilter");
576 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600577 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000578
Brian Paulf75d6972000-09-05 20:28:56 +0000579 for (row = 0; row < filter->Height; row++) {
Brian Paul60909382004-11-10 15:46:52 +0000580 GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width,
581 filter->Height, format, type,
582 row, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000583 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + row * filter->Width * 4);
584 _mesa_pack_rgba_span_float(ctx, filter->Width, src,
585 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000586 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000587
Brian Paul203f3952009-09-03 10:41:14 -0600588 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paul147b0832000-08-23 14:31:25 +0000589}
590
591
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800592static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000593_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
594{
595 GET_CURRENT_CONTEXT(ctx);
596 const struct gl_convolution_attrib *conv;
597 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000598 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000599
600 switch (target) {
601 case GL_CONVOLUTION_1D:
602 c = 0;
603 conv = &ctx->Convolution1D;
604 break;
605 case GL_CONVOLUTION_2D:
606 c = 1;
607 conv = &ctx->Convolution2D;
608 break;
609 case GL_SEPARABLE_2D:
610 c = 2;
611 conv = &ctx->Separable2D;
612 break;
613 default:
Brian Paul08836342001-03-03 20:33:27 +0000614 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000615 return;
616 }
617
618 switch (pname) {
619 case GL_CONVOLUTION_BORDER_COLOR:
620 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
621 break;
622 case GL_CONVOLUTION_BORDER_MODE:
623 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
624 break;
625 case GL_CONVOLUTION_FILTER_SCALE:
626 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
627 break;
628 case GL_CONVOLUTION_FILTER_BIAS:
629 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
630 break;
631 case GL_CONVOLUTION_FORMAT:
632 *params = (GLfloat) conv->Format;
633 break;
634 case GL_CONVOLUTION_WIDTH:
635 *params = (GLfloat) conv->Width;
636 break;
637 case GL_CONVOLUTION_HEIGHT:
638 *params = (GLfloat) conv->Height;
639 break;
640 case GL_MAX_CONVOLUTION_WIDTH:
641 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
642 break;
643 case GL_MAX_CONVOLUTION_HEIGHT:
644 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
645 break;
646 default:
Brian Paul08836342001-03-03 20:33:27 +0000647 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000648 return;
649 }
650}
651
652
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800653static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000654_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
655{
656 GET_CURRENT_CONTEXT(ctx);
657 const struct gl_convolution_attrib *conv;
658 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000659 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000660
661 switch (target) {
662 case GL_CONVOLUTION_1D:
663 c = 0;
664 conv = &ctx->Convolution1D;
665 break;
666 case GL_CONVOLUTION_2D:
667 c = 1;
668 conv = &ctx->Convolution2D;
669 break;
670 case GL_SEPARABLE_2D:
671 c = 2;
672 conv = &ctx->Separable2D;
673 break;
674 default:
Brian Paul08836342001-03-03 20:33:27 +0000675 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000676 return;
677 }
678
679 switch (pname) {
680 case GL_CONVOLUTION_BORDER_COLOR:
681 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
682 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
683 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
684 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
685 break;
686 case GL_CONVOLUTION_BORDER_MODE:
687 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
688 break;
689 case GL_CONVOLUTION_FILTER_SCALE:
690 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
691 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
692 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
693 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
694 break;
695 case GL_CONVOLUTION_FILTER_BIAS:
696 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
697 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
698 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
699 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
700 break;
701 case GL_CONVOLUTION_FORMAT:
702 *params = (GLint) conv->Format;
703 break;
704 case GL_CONVOLUTION_WIDTH:
705 *params = (GLint) conv->Width;
706 break;
707 case GL_CONVOLUTION_HEIGHT:
708 *params = (GLint) conv->Height;
709 break;
710 case GL_MAX_CONVOLUTION_WIDTH:
711 *params = (GLint) ctx->Const.MaxConvolutionWidth;
712 break;
713 case GL_MAX_CONVOLUTION_HEIGHT:
714 *params = (GLint) ctx->Const.MaxConvolutionHeight;
715 break;
716 default:
Brian Paul08836342001-03-03 20:33:27 +0000717 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000718 return;
719 }
720}
721
722
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800723static void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000724_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type,
725 GLvoid *row, GLvoid *column, GLvoid *span)
Brian Paul147b0832000-08-23 14:31:25 +0000726{
Brian Paulf75d6972000-09-05 20:28:56 +0000727 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Paul176501d2006-10-13 16:34:25 +0000728 struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000729 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000730 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000731
Brian Paul0c000ec2000-11-21 23:26:13 +0000732 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000733 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000734 }
735
Brian Paul147b0832000-08-23 14:31:25 +0000736 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000737 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000738 return;
739 }
740
Brian Paulf959f6e2004-04-22 00:27:31 +0000741 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul176501d2006-10-13 16:34:25 +0000742 _mesa_error(ctx, GL_INVALID_OPERATION,
743 "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000744 return;
745 }
746
747 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000748 format == GL_STENCIL_INDEX ||
749 format == GL_DEPTH_COMPONENT ||
750 format == GL_INTENSITY ||
751 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000752 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000753 return;
754 }
755
Brian Paulf75d6972000-09-05 20:28:56 +0000756 filter = &ctx->Separable2D;
757
Brian Paul2db37ef2009-09-03 11:41:29 -0600758 /* Get row filter */
759 row = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack,
760 filter->Width, 1, 1,
761 format, type, row,
762 "glGetConvolutionFilter");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000763 if (row) {
Brian Paul60909382004-11-10 15:46:52 +0000764 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width,
765 format, type, 0);
Brian Paul8cfd08b2004-02-28 20:35:57 +0000766 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paul176501d2006-10-13 16:34:25 +0000767 (GLfloat (*)[4]) filter->Filter,
768 format, type, dst, &ctx->Pack, 0x0);
Brian Paul2db37ef2009-09-03 11:41:29 -0600769 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paulf75d6972000-09-05 20:28:56 +0000770 }
771
Brian Paul2db37ef2009-09-03 11:41:29 -0600772 /* get column filter */
773 column = _mesa_map_validate_pbo_dest(ctx, 1, &ctx->Pack,
774 filter->Height, 1, 1,
Brian Pauld75a99e2009-09-03 12:10:53 -0600775 format, type, column,
Brian Paul2db37ef2009-09-03 11:41:29 -0600776 "glGetConvolutionFilter");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000777 if (column) {
Brian Paul60909382004-11-10 15:46:52 +0000778 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height,
779 format, type, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000780 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + colStart);
781 _mesa_pack_rgba_span_float(ctx, filter->Height, src,
782 format, type, dst, &ctx->Pack, 0x0);
Brian Paul2db37ef2009-09-03 11:41:29 -0600783 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paulf75d6972000-09-05 20:28:56 +0000784 }
785
786 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000787}
788
789
Chia-I Wu5a1e25a2009-09-23 16:56:20 +0800790static void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000791_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
792{
793 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000794 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000795 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000796 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000797
798 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000799 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000800 return;
801 }
802
803 baseFormat = base_filter_format(internalFormat);
804 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000805 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000806 return;
807 }
808
809 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000810 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000811 return;
812 }
813 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000814 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000815 return;
816 }
817
Brian Paulf959f6e2004-04-22 00:27:31 +0000818 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000819 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000820 return;
821 }
822
823 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000824 format == GL_STENCIL_INDEX ||
825 format == GL_DEPTH_COMPONENT ||
826 format == GL_INTENSITY ||
827 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000828 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000829 return;
830 }
831
832 ctx->Separable2D.Format = format;
833 ctx->Separable2D.InternalFormat = internalFormat;
834 ctx->Separable2D.Width = width;
835 ctx->Separable2D.Height = height;
836
Brian Paulbd3b40a2004-10-31 17:36:23 +0000837 /* unpack row filter */
Brian Paul2db37ef2009-09-03 11:41:29 -0600838 row = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack,
839 width, 1, 1,
840 format, type, row,
Brian Pauld75a99e2009-09-03 12:10:53 -0600841 "glSeparableFilter2D");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000842 if (row) {
843 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
844 ctx->Separable2D.Filter,
845 format, type, row, &ctx->Unpack,
Brian Paul2db37ef2009-09-03 11:41:29 -0600846 0x0); /* transferOps */
Brian Paul450e9172004-10-31 18:40:55 +0000847 _mesa_scale_and_bias_rgba(width,
848 (GLfloat (*)[4]) ctx->Separable2D.Filter,
849 ctx->Pixel.ConvolutionFilterScale[2][0],
850 ctx->Pixel.ConvolutionFilterScale[2][1],
851 ctx->Pixel.ConvolutionFilterScale[2][2],
852 ctx->Pixel.ConvolutionFilterScale[2][3],
853 ctx->Pixel.ConvolutionFilterBias[2][0],
854 ctx->Pixel.ConvolutionFilterBias[2][1],
855 ctx->Pixel.ConvolutionFilterBias[2][2],
856 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul2db37ef2009-09-03 11:41:29 -0600857 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paul147b0832000-08-23 14:31:25 +0000858 }
859
860 /* unpack column filter */
Brian Paul2db37ef2009-09-03 11:41:29 -0600861 column = _mesa_map_validate_pbo_source(ctx, 1, &ctx->Unpack,
862 height, 1, 1,
Brian Pauld75a99e2009-09-03 12:10:53 -0600863 format, type, column,
864 "glSeparableFilter2D");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000865 if (column) {
Brian Pauleffb7202004-10-31 18:41:38 +0000866 _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
867 &ctx->Separable2D.Filter[colStart],
868 format, type, column, &ctx->Unpack,
869 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000870
Brian Paul450e9172004-10-31 18:40:55 +0000871 _mesa_scale_and_bias_rgba(height,
872 (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart),
873 ctx->Pixel.ConvolutionFilterScale[2][0],
874 ctx->Pixel.ConvolutionFilterScale[2][1],
875 ctx->Pixel.ConvolutionFilterScale[2][2],
876 ctx->Pixel.ConvolutionFilterScale[2][3],
877 ctx->Pixel.ConvolutionFilterBias[2][0],
878 ctx->Pixel.ConvolutionFilterBias[2][1],
879 ctx->Pixel.ConvolutionFilterBias[2][2],
880 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul2db37ef2009-09-03 11:41:29 -0600881 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000882 }
883
Brian Paul434ec3a2009-08-12 13:46:16 -0600884 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000885 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
886 ctx->Unpack.BufferObj);
Brian Paul147b0832000-08-23 14:31:25 +0000887 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000888
Brian Paulb5012e12000-11-10 18:31:04 +0000889 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000890}
891
892
893/**********************************************************************/
894/*** image convolution functions ***/
895/**********************************************************************/
896
Brian Pauld4b799b2000-08-21 14:24:30 +0000897static void
898convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
899 GLint filterWidth, const GLfloat filter[][4],
900 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000901{
Brian Paul7e708742000-08-22 18:54:25 +0000902 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000903 GLint i, n;
904
Brian Paul7e708742000-08-22 18:54:25 +0000905 if (filterWidth >= 1)
906 dstWidth = srcWidth - (filterWidth - 1);
907 else
908 dstWidth = srcWidth;
909
Brian Paulcc8e37f2000-07-12 13:00:09 +0000910 if (dstWidth <= 0)
911 return; /* null result */
912
913 for (i = 0; i < dstWidth; i++) {
914 GLfloat sumR = 0.0;
915 GLfloat sumG = 0.0;
916 GLfloat sumB = 0.0;
917 GLfloat sumA = 0.0;
918 for (n = 0; n < filterWidth; n++) {
919 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
920 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
921 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
922 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
923 }
924 dest[i][RCOMP] = sumR;
925 dest[i][GCOMP] = sumG;
926 dest[i][BCOMP] = sumB;
927 dest[i][ACOMP] = sumA;
928 }
929}
930
931
Brian Pauld4b799b2000-08-21 14:24:30 +0000932static void
933convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
934 GLint filterWidth, const GLfloat filter[][4],
935 GLfloat dest[][4],
936 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000937{
938 const GLint halfFilterWidth = filterWidth / 2;
939 GLint i, n;
940
941 for (i = 0; i < srcWidth; i++) {
942 GLfloat sumR = 0.0;
943 GLfloat sumG = 0.0;
944 GLfloat sumB = 0.0;
945 GLfloat sumA = 0.0;
946 for (n = 0; n < filterWidth; n++) {
947 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
948 sumR += borderColor[RCOMP] * filter[n][RCOMP];
949 sumG += borderColor[GCOMP] * filter[n][GCOMP];
950 sumB += borderColor[BCOMP] * filter[n][BCOMP];
951 sumA += borderColor[ACOMP] * filter[n][ACOMP];
952 }
953 else {
954 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
955 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
956 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
957 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
958 }
959 }
960 dest[i][RCOMP] = sumR;
961 dest[i][GCOMP] = sumG;
962 dest[i][BCOMP] = sumB;
963 dest[i][ACOMP] = sumA;
964 }
965}
966
967
Brian Pauld4b799b2000-08-21 14:24:30 +0000968static void
969convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
970 GLint filterWidth, const GLfloat filter[][4],
971 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000972{
973 const GLint halfFilterWidth = filterWidth / 2;
974 GLint i, n;
975
976 for (i = 0; i < srcWidth; i++) {
977 GLfloat sumR = 0.0;
978 GLfloat sumG = 0.0;
979 GLfloat sumB = 0.0;
980 GLfloat sumA = 0.0;
981 for (n = 0; n < filterWidth; n++) {
982 if (i + n < halfFilterWidth) {
983 sumR += src[0][RCOMP] * filter[n][RCOMP];
984 sumG += src[0][GCOMP] * filter[n][GCOMP];
985 sumB += src[0][BCOMP] * filter[n][BCOMP];
986 sumA += src[0][ACOMP] * filter[n][ACOMP];
987 }
988 else if (i + n - halfFilterWidth >= srcWidth) {
989 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
990 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
991 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
992 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
993 }
994 else {
995 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
996 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
997 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
998 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
999 }
1000 }
1001 dest[i][RCOMP] = sumR;
1002 dest[i][GCOMP] = sumG;
1003 dest[i][BCOMP] = sumB;
1004 dest[i][ACOMP] = sumA;
1005 }
1006}
1007
1008
Brian Pauld4b799b2000-08-21 14:24:30 +00001009static void
1010convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1011 const GLfloat src[][4],
1012 GLint filterWidth, GLint filterHeight,
1013 const GLfloat filter[][4],
1014 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001015{
Brian Paul7e708742000-08-22 18:54:25 +00001016 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001017 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001018
Brian Paul7e708742000-08-22 18:54:25 +00001019 if (filterWidth >= 1)
1020 dstWidth = srcWidth - (filterWidth - 1);
1021 else
1022 dstWidth = srcWidth;
1023
1024 if (filterHeight >= 1)
1025 dstHeight = srcHeight - (filterHeight - 1);
1026 else
1027 dstHeight = srcHeight;
1028
Brian Pauld4b799b2000-08-21 14:24:30 +00001029 if (dstWidth <= 0 || dstHeight <= 0)
1030 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001031
Brian Pauld4b799b2000-08-21 14:24:30 +00001032 for (j = 0; j < dstHeight; j++) {
1033 for (i = 0; i < dstWidth; i++) {
1034 GLfloat sumR = 0.0;
1035 GLfloat sumG = 0.0;
1036 GLfloat sumB = 0.0;
1037 GLfloat sumA = 0.0;
1038 for (m = 0; m < filterHeight; m++) {
1039 for (n = 0; n < filterWidth; n++) {
1040 const GLint k = (j + m) * srcWidth + i + n;
1041 const GLint f = m * filterWidth + n;
1042 sumR += src[k][RCOMP] * filter[f][RCOMP];
1043 sumG += src[k][GCOMP] * filter[f][GCOMP];
1044 sumB += src[k][BCOMP] * filter[f][BCOMP];
1045 sumA += src[k][ACOMP] * filter[f][ACOMP];
1046 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001047 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001048 dest[j * dstWidth + i][RCOMP] = sumR;
1049 dest[j * dstWidth + i][GCOMP] = sumG;
1050 dest[j * dstWidth + i][BCOMP] = sumB;
1051 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001052 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001053 }
1054}
1055
1056
Brian Pauld4b799b2000-08-21 14:24:30 +00001057static void
1058convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1059 const GLfloat src[][4],
1060 GLint filterWidth, GLint filterHeight,
1061 const GLfloat filter[][4],
1062 GLfloat dest[][4],
1063 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001064{
1065 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001066 const GLint halfFilterHeight = filterHeight / 2;
1067 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001068
Brian Pauld4b799b2000-08-21 14:24:30 +00001069 for (j = 0; j < srcHeight; j++) {
1070 for (i = 0; i < srcWidth; i++) {
1071 GLfloat sumR = 0.0;
1072 GLfloat sumG = 0.0;
1073 GLfloat sumB = 0.0;
1074 GLfloat sumA = 0.0;
1075 for (m = 0; m < filterHeight; m++) {
1076 for (n = 0; n < filterWidth; n++) {
1077 const GLint f = m * filterWidth + n;
1078 const GLint is = i + n - halfFilterWidth;
1079 const GLint js = j + m - halfFilterHeight;
1080 if (is < 0 || is >= srcWidth ||
1081 js < 0 || js >= srcHeight) {
1082 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1083 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1084 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1085 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1086 }
1087 else {
1088 const GLint k = js * srcWidth + is;
1089 sumR += src[k][RCOMP] * filter[f][RCOMP];
1090 sumG += src[k][GCOMP] * filter[f][GCOMP];
1091 sumB += src[k][BCOMP] * filter[f][BCOMP];
1092 sumA += src[k][ACOMP] * filter[f][ACOMP];
1093 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001094 }
1095 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001096 dest[j * srcWidth + i][RCOMP] = sumR;
1097 dest[j * srcWidth + i][GCOMP] = sumG;
1098 dest[j * srcWidth + i][BCOMP] = sumB;
1099 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001100 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001101 }
1102}
1103
1104
Brian Pauld4b799b2000-08-21 14:24:30 +00001105static void
1106convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1107 const GLfloat src[][4],
1108 GLint filterWidth, GLint filterHeight,
1109 const GLfloat filter[][4],
1110 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001111{
1112 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001113 const GLint halfFilterHeight = filterHeight / 2;
1114 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001115
Brian Pauld4b799b2000-08-21 14:24:30 +00001116 for (j = 0; j < srcHeight; j++) {
1117 for (i = 0; i < srcWidth; i++) {
1118 GLfloat sumR = 0.0;
1119 GLfloat sumG = 0.0;
1120 GLfloat sumB = 0.0;
1121 GLfloat sumA = 0.0;
1122 for (m = 0; m < filterHeight; m++) {
1123 for (n = 0; n < filterWidth; n++) {
1124 const GLint f = m * filterWidth + n;
1125 GLint is = i + n - halfFilterWidth;
1126 GLint js = j + m - halfFilterHeight;
1127 GLint k;
1128 if (is < 0)
1129 is = 0;
1130 else if (is >= srcWidth)
1131 is = srcWidth - 1;
1132 if (js < 0)
1133 js = 0;
1134 else if (js >= srcHeight)
1135 js = srcHeight - 1;
1136 k = js * srcWidth + is;
1137 sumR += src[k][RCOMP] * filter[f][RCOMP];
1138 sumG += src[k][GCOMP] * filter[f][GCOMP];
1139 sumB += src[k][BCOMP] * filter[f][BCOMP];
1140 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001141 }
1142 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001143 dest[j * srcWidth + i][RCOMP] = sumR;
1144 dest[j * srcWidth + i][GCOMP] = sumG;
1145 dest[j * srcWidth + i][BCOMP] = sumB;
1146 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001147 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001148 }
1149}
1150
1151
Brian Pauld4b799b2000-08-21 14:24:30 +00001152static void
1153convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1154 const GLfloat src[][4],
1155 GLint filterWidth, GLint filterHeight,
1156 const GLfloat rowFilt[][4],
1157 const GLfloat colFilt[][4],
1158 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001159{
Brian Paul7e708742000-08-22 18:54:25 +00001160 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001161 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001162
1163 if (filterWidth >= 1)
1164 dstWidth = srcWidth - (filterWidth - 1);
1165 else
1166 dstWidth = srcWidth;
1167
1168 if (filterHeight >= 1)
1169 dstHeight = srcHeight - (filterHeight - 1);
1170 else
1171 dstHeight = srcHeight;
1172
1173 if (dstWidth <= 0 || dstHeight <= 0)
1174 return;
1175
1176 for (j = 0; j < dstHeight; j++) {
1177 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001178 GLfloat sumR = 0.0;
1179 GLfloat sumG = 0.0;
1180 GLfloat sumB = 0.0;
1181 GLfloat sumA = 0.0;
1182 for (m = 0; m < filterHeight; m++) {
1183 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001184 GLint k = (j + m) * srcWidth + i + n;
1185 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1186 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1187 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1188 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001189 }
1190 }
Brian Paul7e708742000-08-22 18:54:25 +00001191 dest[j * dstWidth + i][RCOMP] = sumR;
1192 dest[j * dstWidth + i][GCOMP] = sumG;
1193 dest[j * dstWidth + i][BCOMP] = sumB;
1194 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001195 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001196 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001197}
1198
1199
Brian Pauld4b799b2000-08-21 14:24:30 +00001200static void
1201convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1202 const GLfloat src[][4],
1203 GLint filterWidth, GLint filterHeight,
1204 const GLfloat rowFilt[][4],
1205 const GLfloat colFilt[][4],
1206 GLfloat dest[][4],
1207 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001208{
1209 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001210 const GLint halfFilterHeight = filterHeight / 2;
1211 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001212
Brian Pauld4b799b2000-08-21 14:24:30 +00001213 for (j = 0; j < srcHeight; j++) {
1214 for (i = 0; i < srcWidth; i++) {
1215 GLfloat sumR = 0.0;
1216 GLfloat sumG = 0.0;
1217 GLfloat sumB = 0.0;
1218 GLfloat sumA = 0.0;
1219 for (m = 0; m < filterHeight; m++) {
1220 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001221 const GLint is = i + n - halfFilterWidth;
1222 const GLint js = j + m - halfFilterHeight;
1223 if (is < 0 || is >= srcWidth ||
1224 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001225 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1226 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1227 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1228 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1229 }
1230 else {
Brian Paul7e708742000-08-22 18:54:25 +00001231 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001232 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1233 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1234 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1235 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1236 }
Brian Paul7e708742000-08-22 18:54:25 +00001237
Brian Paulcc8e37f2000-07-12 13:00:09 +00001238 }
1239 }
Brian Paul7e708742000-08-22 18:54:25 +00001240 dest[j * srcWidth + i][RCOMP] = sumR;
1241 dest[j * srcWidth + i][GCOMP] = sumG;
1242 dest[j * srcWidth + i][BCOMP] = sumB;
1243 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001244 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001245 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001246}
1247
1248
1249static void
1250convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1251 const GLfloat src[][4],
1252 GLint filterWidth, GLint filterHeight,
1253 const GLfloat rowFilt[][4],
1254 const GLfloat colFilt[][4],
1255 GLfloat dest[][4])
1256{
1257 const GLint halfFilterWidth = filterWidth / 2;
1258 const GLint halfFilterHeight = filterHeight / 2;
1259 GLint i, j, n, m;
1260
1261 for (j = 0; j < srcHeight; j++) {
1262 for (i = 0; i < srcWidth; i++) {
1263 GLfloat sumR = 0.0;
1264 GLfloat sumG = 0.0;
1265 GLfloat sumB = 0.0;
1266 GLfloat sumA = 0.0;
1267 for (m = 0; m < filterHeight; m++) {
1268 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001269 GLint is = i + n - halfFilterWidth;
1270 GLint js = j + m - halfFilterHeight;
1271 GLint k;
1272 if (is < 0)
1273 is = 0;
1274 else if (is >= srcWidth)
1275 is = srcWidth - 1;
1276 if (js < 0)
1277 js = 0;
1278 else if (js >= srcHeight)
1279 js = srcHeight - 1;
1280 k = js * srcWidth + is;
1281 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1282 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1283 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1284 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001285 }
1286 }
Brian Paul7e708742000-08-22 18:54:25 +00001287 dest[j * srcWidth + i][RCOMP] = sumR;
1288 dest[j * srcWidth + i][GCOMP] = sumG;
1289 dest[j * srcWidth + i][BCOMP] = sumB;
1290 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001291 }
1292 }
1293}
1294
1295
1296
1297void
1298_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1299 const GLfloat *srcImage, GLfloat *dstImage)
1300{
1301 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1302 case GL_REDUCE:
1303 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1304 ctx->Convolution1D.Width,
1305 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1306 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001307 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001308 break;
1309 case GL_CONSTANT_BORDER:
1310 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1311 ctx->Convolution1D.Width,
1312 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1313 (GLfloat (*)[4]) dstImage,
1314 ctx->Pixel.ConvolutionBorderColor[0]);
1315 break;
1316 case GL_REPLICATE_BORDER:
1317 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1318 ctx->Convolution1D.Width,
1319 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1320 (GLfloat (*)[4]) dstImage);
1321 break;
1322 default:
1323 ;
1324 }
1325}
1326
1327
1328void
1329_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1330 const GLfloat *srcImage, GLfloat *dstImage)
1331{
1332 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1333 case GL_REDUCE:
1334 convolve_2d_reduce(*width, *height,
1335 (const GLfloat (*)[4]) srcImage,
1336 ctx->Convolution2D.Width,
1337 ctx->Convolution2D.Height,
1338 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1339 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001340 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1341 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001342 break;
1343 case GL_CONSTANT_BORDER:
1344 convolve_2d_constant(*width, *height,
1345 (const GLfloat (*)[4]) srcImage,
1346 ctx->Convolution2D.Width,
1347 ctx->Convolution2D.Height,
1348 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1349 (GLfloat (*)[4]) dstImage,
1350 ctx->Pixel.ConvolutionBorderColor[1]);
1351 break;
1352 case GL_REPLICATE_BORDER:
1353 convolve_2d_replicate(*width, *height,
1354 (const GLfloat (*)[4]) srcImage,
1355 ctx->Convolution2D.Width,
1356 ctx->Convolution2D.Height,
1357 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1358 (GLfloat (*)[4]) dstImage);
1359 break;
1360 default:
1361 ;
1362 }
1363}
1364
1365
1366void
1367_mesa_convolve_sep_image(const GLcontext *ctx,
1368 GLsizei *width, GLsizei *height,
1369 const GLfloat *srcImage, GLfloat *dstImage)
1370{
1371 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1372 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1373
1374 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1375 case GL_REDUCE:
1376 convolve_sep_reduce(*width, *height,
1377 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001378 ctx->Separable2D.Width,
1379 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001380 (const GLfloat (*)[4]) rowFilter,
1381 (const GLfloat (*)[4]) colFilter,
1382 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001383 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1384 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001385 break;
1386 case GL_CONSTANT_BORDER:
1387 convolve_sep_constant(*width, *height,
1388 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001389 ctx->Separable2D.Width,
1390 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001391 (const GLfloat (*)[4]) rowFilter,
1392 (const GLfloat (*)[4]) colFilter,
1393 (GLfloat (*)[4]) dstImage,
1394 ctx->Pixel.ConvolutionBorderColor[2]);
1395 break;
1396 case GL_REPLICATE_BORDER:
1397 convolve_sep_replicate(*width, *height,
1398 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001399 ctx->Separable2D.Width,
1400 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001401 (const GLfloat (*)[4]) rowFilter,
1402 (const GLfloat (*)[4]) colFilter,
1403 (GLfloat (*)[4]) dstImage);
1404 break;
1405 default:
1406 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001407 }
1408}
Brian Paul16461f72001-02-06 17:22:16 +00001409
1410
1411
1412/*
1413 * This function computes an image's size after convolution.
1414 * If the convolution border mode is GL_REDUCE, the post-convolution
1415 * image will be smaller than the original.
1416 */
1417void
1418_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1419 GLsizei *width, GLsizei *height)
1420{
1421 if (ctx->Pixel.Convolution1DEnabled
1422 && dimensions == 1
1423 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1424 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1425 }
1426 else if (ctx->Pixel.Convolution2DEnabled
1427 && dimensions > 1
1428 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1429 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1430 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1431 }
1432 else if (ctx->Pixel.Separable2DEnabled
1433 && dimensions > 1
1434 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1435 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1436 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1437 }
1438}
Chia-I Wu5a1e25a2009-09-23 16:56:20 +08001439
1440
1441void
1442_mesa_init_convolve_dispatch(struct _glapi_table *disp)
1443{
1444 SET_ConvolutionFilter1D(disp, _mesa_ConvolutionFilter1D);
1445 SET_ConvolutionFilter2D(disp, _mesa_ConvolutionFilter2D);
1446 SET_ConvolutionParameterf(disp, _mesa_ConvolutionParameterf);
1447 SET_ConvolutionParameterfv(disp, _mesa_ConvolutionParameterfv);
1448 SET_ConvolutionParameteri(disp, _mesa_ConvolutionParameteri);
1449 SET_ConvolutionParameteriv(disp, _mesa_ConvolutionParameteriv);
1450 SET_CopyConvolutionFilter1D(disp, _mesa_CopyConvolutionFilter1D);
1451 SET_CopyConvolutionFilter2D(disp, _mesa_CopyConvolutionFilter2D);
1452 SET_GetConvolutionFilter(disp, _mesa_GetConvolutionFilter);
1453 SET_GetConvolutionParameterfv(disp, _mesa_GetConvolutionParameterfv);
1454 SET_GetConvolutionParameteriv(disp, _mesa_GetConvolutionParameteriv);
1455 SET_SeparableFilter2D(disp, _mesa_SeparableFilter2D);
1456 SET_GetSeparableFilter(disp, _mesa_GetSeparableFilter);
1457}
1458
1459
1460#endif /* FEATURE_convolve */