blob: 714909f451d15fb1aade161d99177c925b383f9e [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"
Brian Paulcc8e37f2000-07-12 13:00:09 +000043
44
Brian Paul147b0832000-08-23 14:31:25 +000045/*
46 * Given an internalFormat token passed to glConvolutionFilter
47 * or glSeparableFilter, return the corresponding base format.
48 * Return -1 if invalid token.
49 */
50static GLint
51base_filter_format( GLenum format )
52{
53 switch (format) {
54 case GL_ALPHA:
55 case GL_ALPHA4:
56 case GL_ALPHA8:
57 case GL_ALPHA12:
58 case GL_ALPHA16:
59 return GL_ALPHA;
60 case GL_LUMINANCE:
61 case GL_LUMINANCE4:
62 case GL_LUMINANCE8:
63 case GL_LUMINANCE12:
64 case GL_LUMINANCE16:
65 return GL_LUMINANCE;
66 case GL_LUMINANCE_ALPHA:
67 case GL_LUMINANCE4_ALPHA4:
68 case GL_LUMINANCE6_ALPHA2:
69 case GL_LUMINANCE8_ALPHA8:
70 case GL_LUMINANCE12_ALPHA4:
71 case GL_LUMINANCE12_ALPHA12:
72 case GL_LUMINANCE16_ALPHA16:
73 return GL_LUMINANCE_ALPHA;
74 case GL_INTENSITY:
75 case GL_INTENSITY4:
76 case GL_INTENSITY8:
77 case GL_INTENSITY12:
78 case GL_INTENSITY16:
79 return GL_INTENSITY;
80 case GL_RGB:
81 case GL_R3_G3_B2:
82 case GL_RGB4:
83 case GL_RGB5:
84 case GL_RGB8:
85 case GL_RGB10:
86 case GL_RGB12:
87 case GL_RGB16:
88 return GL_RGB;
89 case 4:
90 case GL_RGBA:
91 case GL_RGBA2:
92 case GL_RGBA4:
93 case GL_RGB5_A1:
94 case GL_RGBA8:
95 case GL_RGB10_A2:
96 case GL_RGBA12:
97 case GL_RGBA16:
98 return GL_RGBA;
99 default:
100 return -1; /* error */
101 }
102}
103
104
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000105void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000106_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
107{
Brian Pauld0570642002-03-19 15:22:50 +0000108 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000109 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000110 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000111
112 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000113 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000114 return;
115 }
116
117 baseFormat = base_filter_format(internalFormat);
118 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000119 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000120 return;
121 }
122
123 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000124 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000125 return;
126 }
127
Brian Paulf959f6e2004-04-22 00:27:31 +0000128 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000129 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000130 return;
131 }
132
133 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000134 format == GL_STENCIL_INDEX ||
135 format == GL_DEPTH_COMPONENT ||
136 format == GL_INTENSITY ||
137 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000138 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000139 return;
140 }
141
142 ctx->Convolution1D.Format = format;
143 ctx->Convolution1D.InternalFormat = internalFormat;
144 ctx->Convolution1D.Width = width;
145 ctx->Convolution1D.Height = 1;
146
Brian Paul95027a02009-09-03 11:23:05 -0600147 image = _mesa_map_validate_pbo_source(ctx,
148 1, &ctx->Unpack, width, 1, 1,
149 format, type, image,
150 "glConvolutionFilter1D");
151 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600152 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000153
Brian Paul8cfd08b2004-02-28 20:35:57 +0000154 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
Brian Paul147b0832000-08-23 14:31:25 +0000155 ctx->Convolution1D.Filter,
156 format, type, image, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000157 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000158
Brian Paul203f3952009-09-03 10:41:14 -0600159 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000160
Brian Paul450e9172004-10-31 18:40:55 +0000161 _mesa_scale_and_bias_rgba(width,
162 (GLfloat (*)[4]) ctx->Convolution1D.Filter,
163 ctx->Pixel.ConvolutionFilterScale[0][0],
164 ctx->Pixel.ConvolutionFilterScale[0][1],
165 ctx->Pixel.ConvolutionFilterScale[0][2],
166 ctx->Pixel.ConvolutionFilterScale[0][3],
167 ctx->Pixel.ConvolutionFilterBias[0][0],
168 ctx->Pixel.ConvolutionFilterBias[0][1],
169 ctx->Pixel.ConvolutionFilterBias[0][2],
170 ctx->Pixel.ConvolutionFilterBias[0][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000171
Brian Paulb5012e12000-11-10 18:31:04 +0000172 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000173}
174
175
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000176void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000177_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
178{
Brian Pauld0570642002-03-19 15:22:50 +0000179 GLint baseFormat;
Brian Paulb3050282003-12-04 03:19:46 +0000180 GLint i;
Brian Paul147b0832000-08-23 14:31:25 +0000181 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000182 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000183
184 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000185 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000186 return;
187 }
188
189 baseFormat = base_filter_format(internalFormat);
190 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000191 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000192 return;
193 }
194
195 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000196 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000197 return;
198 }
199 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000200 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000201 return;
202 }
203
Brian Paulf959f6e2004-04-22 00:27:31 +0000204 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000205 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000206 return;
207 }
208 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000209 format == GL_STENCIL_INDEX ||
210 format == GL_DEPTH_COMPONENT ||
211 format == GL_INTENSITY ||
212 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000213 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000214 return;
215 }
216
Brian Paulb3050282003-12-04 03:19:46 +0000217 /* this should have been caught earlier */
218 assert(_mesa_components_in_format(format));
Brian Paul147b0832000-08-23 14:31:25 +0000219
220 ctx->Convolution2D.Format = format;
221 ctx->Convolution2D.InternalFormat = internalFormat;
222 ctx->Convolution2D.Width = width;
223 ctx->Convolution2D.Height = height;
224
Brian Paul95027a02009-09-03 11:23:05 -0600225 image = _mesa_map_validate_pbo_source(ctx,
226 2, &ctx->Unpack, width, height, 1,
227 format, type, image,
228 "glConvolutionFilter2D");
229 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600230 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000231
Brian Paul147b0832000-08-23 14:31:25 +0000232 /* Unpack filter image. We always store filters in RGBA format. */
233 for (i = 0; i < height; i++) {
Brian Paul60909382004-11-10 15:46:52 +0000234 const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width,
235 height, format, type, i, 0);
Brian Paul147b0832000-08-23 14:31:25 +0000236 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000237 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
Brian Paul147b0832000-08-23 14:31:25 +0000238 format, type, src, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000239 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000240 }
241
Brian Paul203f3952009-09-03 10:41:14 -0600242 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000243
Brian Paul450e9172004-10-31 18:40:55 +0000244 _mesa_scale_and_bias_rgba(width * height,
245 (GLfloat (*)[4]) ctx->Convolution2D.Filter,
246 ctx->Pixel.ConvolutionFilterScale[1][0],
247 ctx->Pixel.ConvolutionFilterScale[1][1],
248 ctx->Pixel.ConvolutionFilterScale[1][2],
249 ctx->Pixel.ConvolutionFilterScale[1][3],
250 ctx->Pixel.ConvolutionFilterBias[1][0],
251 ctx->Pixel.ConvolutionFilterBias[1][1],
252 ctx->Pixel.ConvolutionFilterBias[1][2],
253 ctx->Pixel.ConvolutionFilterBias[1][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000254
Brian Paulb5012e12000-11-10 18:31:04 +0000255 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000256}
257
258
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000259void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000260_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
261{
262 GET_CURRENT_CONTEXT(ctx);
263 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000264 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000265
266 switch (target) {
267 case GL_CONVOLUTION_1D:
268 c = 0;
269 break;
270 case GL_CONVOLUTION_2D:
271 c = 1;
272 break;
273 case GL_SEPARABLE_2D:
274 c = 2;
275 break;
276 default:
Brian Paul08836342001-03-03 20:33:27 +0000277 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000278 return;
279 }
280
281 switch (pname) {
282 case GL_CONVOLUTION_BORDER_MODE:
283 if (param == (GLfloat) GL_REDUCE ||
284 param == (GLfloat) GL_CONSTANT_BORDER ||
285 param == (GLfloat) GL_REPLICATE_BORDER) {
286 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
287 }
288 else {
Brian Paul08836342001-03-03 20:33:27 +0000289 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000290 return;
291 }
292 break;
293 default:
Brian Paul08836342001-03-03 20:33:27 +0000294 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000295 return;
296 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000297
298 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000299}
300
301
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000302void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000303_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
304{
305 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000306 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000307 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000308
309 switch (target) {
310 case GL_CONVOLUTION_1D:
311 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000312 break;
313 case GL_CONVOLUTION_2D:
314 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000315 break;
316 case GL_SEPARABLE_2D:
317 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000318 break;
319 default:
Brian Paul08836342001-03-03 20:33:27 +0000320 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000321 return;
322 }
323
324 switch (pname) {
325 case GL_CONVOLUTION_BORDER_COLOR:
326 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
327 break;
328 case GL_CONVOLUTION_BORDER_MODE:
329 if (params[0] == (GLfloat) GL_REDUCE ||
330 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
331 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
332 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
333 }
334 else {
Brian Paul08836342001-03-03 20:33:27 +0000335 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000336 return;
337 }
338 break;
339 case GL_CONVOLUTION_FILTER_SCALE:
340 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
341 break;
342 case GL_CONVOLUTION_FILTER_BIAS:
343 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
344 break;
345 default:
Brian Paul08836342001-03-03 20:33:27 +0000346 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000347 return;
348 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000349
350 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000351}
352
353
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000354void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000355_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
356{
357 GET_CURRENT_CONTEXT(ctx);
358 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000359 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000360
361 switch (target) {
362 case GL_CONVOLUTION_1D:
363 c = 0;
364 break;
365 case GL_CONVOLUTION_2D:
366 c = 1;
367 break;
368 case GL_SEPARABLE_2D:
369 c = 2;
370 break;
371 default:
Brian Paul08836342001-03-03 20:33:27 +0000372 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000373 return;
374 }
375
376 switch (pname) {
377 case GL_CONVOLUTION_BORDER_MODE:
378 if (param == (GLint) GL_REDUCE ||
379 param == (GLint) GL_CONSTANT_BORDER ||
380 param == (GLint) GL_REPLICATE_BORDER) {
381 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
382 }
383 else {
Brian Paul08836342001-03-03 20:33:27 +0000384 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000385 return;
386 }
387 break;
388 default:
Brian Paul08836342001-03-03 20:33:27 +0000389 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000390 return;
391 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000392
393 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000394}
395
396
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000397void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000398_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
399{
400 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000401 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000402 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000403
404 switch (target) {
405 case GL_CONVOLUTION_1D:
406 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000407 break;
408 case GL_CONVOLUTION_2D:
409 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000410 break;
411 case GL_SEPARABLE_2D:
412 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000413 break;
414 default:
Brian Paul08836342001-03-03 20:33:27 +0000415 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000416 return;
417 }
418
419 switch (pname) {
420 case GL_CONVOLUTION_BORDER_COLOR:
421 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
422 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
423 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
424 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
425 break;
426 case GL_CONVOLUTION_BORDER_MODE:
427 if (params[0] == (GLint) GL_REDUCE ||
428 params[0] == (GLint) GL_CONSTANT_BORDER ||
429 params[0] == (GLint) GL_REPLICATE_BORDER) {
430 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
431 }
432 else {
Brian Paul08836342001-03-03 20:33:27 +0000433 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000434 return;
435 }
436 break;
437 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000438 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
439 /* need cast to prevent compiler warnings */
440 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
441 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
442 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
443 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000444 break;
445 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000446 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
447 /* need cast to prevent compiler warnings */
448 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
449 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
450 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
451 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000452 break;
453 default:
Brian Paul08836342001-03-03 20:33:27 +0000454 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000455 return;
456 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000457
458 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000459}
460
461
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000462void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000463_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
464{
Brian Pauld0570642002-03-19 15:22:50 +0000465 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000466 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000467 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000468
469 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000470 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000471 return;
472 }
473
474 baseFormat = base_filter_format(internalFormat);
475 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000476 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000477 return;
478 }
479
480 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000481 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000482 return;
483 }
484
Keith Whitwell70989242001-03-19 02:25:35 +0000485 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
486 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000487}
488
489
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000490void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000491_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
492{
Brian Pauld0570642002-03-19 15:22:50 +0000493 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000494 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000495 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000496
497 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000498 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000499 return;
500 }
501
502 baseFormat = base_filter_format(internalFormat);
503 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000504 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000505 return;
506 }
507
508 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000509 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000510 return;
511 }
512 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000513 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000514 return;
515 }
516
Keith Whitwell70989242001-03-19 02:25:35 +0000517 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
518 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000519}
520
521
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000522void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000523_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type,
524 GLvoid *image)
Brian Paul147b0832000-08-23 14:31:25 +0000525{
Brian Paul176501d2006-10-13 16:34:25 +0000526 struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000527 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000528 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000529 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000530
Brian Paul0c000ec2000-11-21 23:26:13 +0000531 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000532 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000533 }
534
Brian Paulf959f6e2004-04-22 00:27:31 +0000535 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000536 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000537 return;
538 }
539
540 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000541 format == GL_STENCIL_INDEX ||
542 format == GL_DEPTH_COMPONENT ||
543 format == GL_INTENSITY ||
544 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000545 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000546 return;
547 }
548
Brian Paulf75d6972000-09-05 20:28:56 +0000549 switch (target) {
550 case GL_CONVOLUTION_1D:
551 filter = &(ctx->Convolution1D);
552 break;
553 case GL_CONVOLUTION_2D:
554 filter = &(ctx->Convolution2D);
555 break;
556 default:
Brian Paul08836342001-03-03 20:33:27 +0000557 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000558 return;
559 }
560
Brian Paul95027a02009-09-03 11:23:05 -0600561 image = _mesa_map_validate_pbo_dest(ctx, 2, &ctx->Pack,
562 filter->Width, filter->Height, 1,
563 format, type, image,
564 "glGetConvolutionFilter");
565 if (!image)
Brian Paul203f3952009-09-03 10:41:14 -0600566 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000567
Brian Paulf75d6972000-09-05 20:28:56 +0000568 for (row = 0; row < filter->Height; row++) {
Brian Paul60909382004-11-10 15:46:52 +0000569 GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width,
570 filter->Height, format, type,
571 row, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000572 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + row * filter->Width * 4);
573 _mesa_pack_rgba_span_float(ctx, filter->Width, src,
574 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000575 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000576
Brian Paul203f3952009-09-03 10:41:14 -0600577 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paul147b0832000-08-23 14:31:25 +0000578}
579
580
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000581void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000582_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
583{
584 GET_CURRENT_CONTEXT(ctx);
585 const struct gl_convolution_attrib *conv;
586 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000587 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000588
589 switch (target) {
590 case GL_CONVOLUTION_1D:
591 c = 0;
592 conv = &ctx->Convolution1D;
593 break;
594 case GL_CONVOLUTION_2D:
595 c = 1;
596 conv = &ctx->Convolution2D;
597 break;
598 case GL_SEPARABLE_2D:
599 c = 2;
600 conv = &ctx->Separable2D;
601 break;
602 default:
Brian Paul08836342001-03-03 20:33:27 +0000603 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000604 return;
605 }
606
607 switch (pname) {
608 case GL_CONVOLUTION_BORDER_COLOR:
609 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
610 break;
611 case GL_CONVOLUTION_BORDER_MODE:
612 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
613 break;
614 case GL_CONVOLUTION_FILTER_SCALE:
615 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
616 break;
617 case GL_CONVOLUTION_FILTER_BIAS:
618 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
619 break;
620 case GL_CONVOLUTION_FORMAT:
621 *params = (GLfloat) conv->Format;
622 break;
623 case GL_CONVOLUTION_WIDTH:
624 *params = (GLfloat) conv->Width;
625 break;
626 case GL_CONVOLUTION_HEIGHT:
627 *params = (GLfloat) conv->Height;
628 break;
629 case GL_MAX_CONVOLUTION_WIDTH:
630 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
631 break;
632 case GL_MAX_CONVOLUTION_HEIGHT:
633 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
634 break;
635 default:
Brian Paul08836342001-03-03 20:33:27 +0000636 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000637 return;
638 }
639}
640
641
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000642void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000643_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
644{
645 GET_CURRENT_CONTEXT(ctx);
646 const struct gl_convolution_attrib *conv;
647 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000648 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000649
650 switch (target) {
651 case GL_CONVOLUTION_1D:
652 c = 0;
653 conv = &ctx->Convolution1D;
654 break;
655 case GL_CONVOLUTION_2D:
656 c = 1;
657 conv = &ctx->Convolution2D;
658 break;
659 case GL_SEPARABLE_2D:
660 c = 2;
661 conv = &ctx->Separable2D;
662 break;
663 default:
Brian Paul08836342001-03-03 20:33:27 +0000664 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000665 return;
666 }
667
668 switch (pname) {
669 case GL_CONVOLUTION_BORDER_COLOR:
670 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
671 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
672 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
673 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
674 break;
675 case GL_CONVOLUTION_BORDER_MODE:
676 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
677 break;
678 case GL_CONVOLUTION_FILTER_SCALE:
679 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
680 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
681 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
682 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
683 break;
684 case GL_CONVOLUTION_FILTER_BIAS:
685 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
686 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
687 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
688 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
689 break;
690 case GL_CONVOLUTION_FORMAT:
691 *params = (GLint) conv->Format;
692 break;
693 case GL_CONVOLUTION_WIDTH:
694 *params = (GLint) conv->Width;
695 break;
696 case GL_CONVOLUTION_HEIGHT:
697 *params = (GLint) conv->Height;
698 break;
699 case GL_MAX_CONVOLUTION_WIDTH:
700 *params = (GLint) ctx->Const.MaxConvolutionWidth;
701 break;
702 case GL_MAX_CONVOLUTION_HEIGHT:
703 *params = (GLint) ctx->Const.MaxConvolutionHeight;
704 break;
705 default:
Brian Paul08836342001-03-03 20:33:27 +0000706 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000707 return;
708 }
709}
710
711
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000712void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000713_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type,
714 GLvoid *row, GLvoid *column, GLvoid *span)
Brian Paul147b0832000-08-23 14:31:25 +0000715{
Brian Paulf75d6972000-09-05 20:28:56 +0000716 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Paul176501d2006-10-13 16:34:25 +0000717 struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000718 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000719 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000720
Brian Paul0c000ec2000-11-21 23:26:13 +0000721 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000722 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000723 }
724
Brian Paul147b0832000-08-23 14:31:25 +0000725 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000726 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000727 return;
728 }
729
Brian Paulf959f6e2004-04-22 00:27:31 +0000730 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul176501d2006-10-13 16:34:25 +0000731 _mesa_error(ctx, GL_INVALID_OPERATION,
732 "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000733 return;
734 }
735
736 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000737 format == GL_STENCIL_INDEX ||
738 format == GL_DEPTH_COMPONENT ||
739 format == GL_INTENSITY ||
740 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000741 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000742 return;
743 }
744
Brian Paulf75d6972000-09-05 20:28:56 +0000745 filter = &ctx->Separable2D;
746
Brian Paul434ec3a2009-08-12 13:46:16 -0600747 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000748 /* Pack filter into PBO */
749 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000750 if (!_mesa_validate_pbo_access(1, &ctx->Pack, filter->Width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000751 format, type, row)) {
752 _mesa_error(ctx, GL_INVALID_OPERATION,
753 "glGetSeparableFilter(invalid PBO access, width)");
754 return;
755 }
Brian Paul60909382004-11-10 15:46:52 +0000756 if (!_mesa_validate_pbo_access(1, &ctx->Pack, filter->Height, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000757 format, type, column)) {
758 _mesa_error(ctx, GL_INVALID_OPERATION,
759 "glGetSeparableFilter(invalid PBO access, height)");
760 return;
761 }
762 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
763 GL_WRITE_ONLY_ARB,
764 ctx->Pack.BufferObj);
765 if (!buf) {
766 /* buffer is already mapped - that's an error */
767 _mesa_error(ctx, GL_INVALID_OPERATION,
768 "glGetSeparableFilter(PBO is mapped)");
769 return;
770 }
771 row = ADD_POINTERS(buf, row);
772 column = ADD_POINTERS(buf, column);
773 }
774
Brian Paulf75d6972000-09-05 20:28:56 +0000775 /* Row filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000776 if (row) {
Brian Paul60909382004-11-10 15:46:52 +0000777 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width,
778 format, type, 0);
Brian Paul8cfd08b2004-02-28 20:35:57 +0000779 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paul176501d2006-10-13 16:34:25 +0000780 (GLfloat (*)[4]) filter->Filter,
781 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000782 }
783
784 /* Column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000785 if (column) {
Brian Paul60909382004-11-10 15:46:52 +0000786 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height,
787 format, type, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000788 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + colStart);
789 _mesa_pack_rgba_span_float(ctx, filter->Height, src,
790 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000791 }
792
793 (void) span; /* unused at this time */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000794
Brian Paul434ec3a2009-08-12 13:46:16 -0600795 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000796 /* Pack filter into PBO */
797 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
798 ctx->Unpack.BufferObj);
799 }
Brian Paul147b0832000-08-23 14:31:25 +0000800}
801
802
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000803void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000804_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
805{
806 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000807 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000808 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000809 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000810
811 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000812 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000813 return;
814 }
815
816 baseFormat = base_filter_format(internalFormat);
817 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000818 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000819 return;
820 }
821
822 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000823 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000824 return;
825 }
826 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000827 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000828 return;
829 }
830
Brian Paulf959f6e2004-04-22 00:27:31 +0000831 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000832 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000833 return;
834 }
835
836 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000837 format == GL_STENCIL_INDEX ||
838 format == GL_DEPTH_COMPONENT ||
839 format == GL_INTENSITY ||
840 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000841 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000842 return;
843 }
844
845 ctx->Separable2D.Format = format;
846 ctx->Separable2D.InternalFormat = internalFormat;
847 ctx->Separable2D.Width = width;
848 ctx->Separable2D.Height = height;
849
Brian Paul434ec3a2009-08-12 13:46:16 -0600850 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000851 /* unpack filter from PBO */
852 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000853 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000854 format, type, row)) {
855 _mesa_error(ctx, GL_INVALID_OPERATION,
856 "glSeparableFilter2D(invalid PBO access, width)");
857 return;
858 }
Brian Paul60909382004-11-10 15:46:52 +0000859 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, height, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000860 format, type, column)) {
861 _mesa_error(ctx, GL_INVALID_OPERATION,
862 "glSeparableFilter2D(invalid PBO access, height)");
863 return;
864 }
865 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
866 GL_READ_ONLY_ARB,
867 ctx->Unpack.BufferObj);
868 if (!buf) {
869 /* buffer is already mapped - that's an error */
870 _mesa_error(ctx, GL_INVALID_OPERATION,
871 "glSeparableFilter2D(PBO is mapped)");
872 return;
873 }
874 row = ADD_POINTERS(buf, row);
875 column = ADD_POINTERS(buf, column);
876 }
Brian Paul147b0832000-08-23 14:31:25 +0000877
Brian Paulbd3b40a2004-10-31 17:36:23 +0000878 /* unpack row filter */
879 if (row) {
880 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
881 ctx->Separable2D.Filter,
882 format, type, row, &ctx->Unpack,
883 0); /* transferOps */
884
Brian Paul450e9172004-10-31 18:40:55 +0000885 _mesa_scale_and_bias_rgba(width,
886 (GLfloat (*)[4]) ctx->Separable2D.Filter,
887 ctx->Pixel.ConvolutionFilterScale[2][0],
888 ctx->Pixel.ConvolutionFilterScale[2][1],
889 ctx->Pixel.ConvolutionFilterScale[2][2],
890 ctx->Pixel.ConvolutionFilterScale[2][3],
891 ctx->Pixel.ConvolutionFilterBias[2][0],
892 ctx->Pixel.ConvolutionFilterBias[2][1],
893 ctx->Pixel.ConvolutionFilterBias[2][2],
894 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul147b0832000-08-23 14:31:25 +0000895 }
896
897 /* unpack column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000898 if (column) {
Brian Pauleffb7202004-10-31 18:41:38 +0000899 _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
900 &ctx->Separable2D.Filter[colStart],
901 format, type, column, &ctx->Unpack,
902 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000903
Brian Paul450e9172004-10-31 18:40:55 +0000904 _mesa_scale_and_bias_rgba(height,
905 (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart),
906 ctx->Pixel.ConvolutionFilterScale[2][0],
907 ctx->Pixel.ConvolutionFilterScale[2][1],
908 ctx->Pixel.ConvolutionFilterScale[2][2],
909 ctx->Pixel.ConvolutionFilterScale[2][3],
910 ctx->Pixel.ConvolutionFilterBias[2][0],
911 ctx->Pixel.ConvolutionFilterBias[2][1],
912 ctx->Pixel.ConvolutionFilterBias[2][2],
913 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000914 }
915
Brian Paul434ec3a2009-08-12 13:46:16 -0600916 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000917 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
918 ctx->Unpack.BufferObj);
Brian Paul147b0832000-08-23 14:31:25 +0000919 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000920
Brian Paulb5012e12000-11-10 18:31:04 +0000921 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000922}
923
924
925/**********************************************************************/
926/*** image convolution functions ***/
927/**********************************************************************/
928
Brian Pauld4b799b2000-08-21 14:24:30 +0000929static void
930convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
931 GLint filterWidth, const GLfloat filter[][4],
932 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000933{
Brian Paul7e708742000-08-22 18:54:25 +0000934 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000935 GLint i, n;
936
Brian Paul7e708742000-08-22 18:54:25 +0000937 if (filterWidth >= 1)
938 dstWidth = srcWidth - (filterWidth - 1);
939 else
940 dstWidth = srcWidth;
941
Brian Paulcc8e37f2000-07-12 13:00:09 +0000942 if (dstWidth <= 0)
943 return; /* null result */
944
945 for (i = 0; i < dstWidth; i++) {
946 GLfloat sumR = 0.0;
947 GLfloat sumG = 0.0;
948 GLfloat sumB = 0.0;
949 GLfloat sumA = 0.0;
950 for (n = 0; n < filterWidth; n++) {
951 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
952 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
953 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
954 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
955 }
956 dest[i][RCOMP] = sumR;
957 dest[i][GCOMP] = sumG;
958 dest[i][BCOMP] = sumB;
959 dest[i][ACOMP] = sumA;
960 }
961}
962
963
Brian Pauld4b799b2000-08-21 14:24:30 +0000964static void
965convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
966 GLint filterWidth, const GLfloat filter[][4],
967 GLfloat dest[][4],
968 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000969{
970 const GLint halfFilterWidth = filterWidth / 2;
971 GLint i, n;
972
973 for (i = 0; i < srcWidth; i++) {
974 GLfloat sumR = 0.0;
975 GLfloat sumG = 0.0;
976 GLfloat sumB = 0.0;
977 GLfloat sumA = 0.0;
978 for (n = 0; n < filterWidth; n++) {
979 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
980 sumR += borderColor[RCOMP] * filter[n][RCOMP];
981 sumG += borderColor[GCOMP] * filter[n][GCOMP];
982 sumB += borderColor[BCOMP] * filter[n][BCOMP];
983 sumA += borderColor[ACOMP] * filter[n][ACOMP];
984 }
985 else {
986 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
987 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
988 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
989 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
990 }
991 }
992 dest[i][RCOMP] = sumR;
993 dest[i][GCOMP] = sumG;
994 dest[i][BCOMP] = sumB;
995 dest[i][ACOMP] = sumA;
996 }
997}
998
999
Brian Pauld4b799b2000-08-21 14:24:30 +00001000static void
1001convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
1002 GLint filterWidth, const GLfloat filter[][4],
1003 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001004{
1005 const GLint halfFilterWidth = filterWidth / 2;
1006 GLint i, n;
1007
1008 for (i = 0; i < srcWidth; i++) {
1009 GLfloat sumR = 0.0;
1010 GLfloat sumG = 0.0;
1011 GLfloat sumB = 0.0;
1012 GLfloat sumA = 0.0;
1013 for (n = 0; n < filterWidth; n++) {
1014 if (i + n < halfFilterWidth) {
1015 sumR += src[0][RCOMP] * filter[n][RCOMP];
1016 sumG += src[0][GCOMP] * filter[n][GCOMP];
1017 sumB += src[0][BCOMP] * filter[n][BCOMP];
1018 sumA += src[0][ACOMP] * filter[n][ACOMP];
1019 }
1020 else if (i + n - halfFilterWidth >= srcWidth) {
1021 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
1022 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
1023 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
1024 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
1025 }
1026 else {
1027 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1028 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1029 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1030 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1031 }
1032 }
1033 dest[i][RCOMP] = sumR;
1034 dest[i][GCOMP] = sumG;
1035 dest[i][BCOMP] = sumB;
1036 dest[i][ACOMP] = sumA;
1037 }
1038}
1039
1040
Brian Pauld4b799b2000-08-21 14:24:30 +00001041static void
1042convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1043 const GLfloat src[][4],
1044 GLint filterWidth, GLint filterHeight,
1045 const GLfloat filter[][4],
1046 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001047{
Brian Paul7e708742000-08-22 18:54:25 +00001048 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001049 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001050
Brian Paul7e708742000-08-22 18:54:25 +00001051 if (filterWidth >= 1)
1052 dstWidth = srcWidth - (filterWidth - 1);
1053 else
1054 dstWidth = srcWidth;
1055
1056 if (filterHeight >= 1)
1057 dstHeight = srcHeight - (filterHeight - 1);
1058 else
1059 dstHeight = srcHeight;
1060
Brian Pauld4b799b2000-08-21 14:24:30 +00001061 if (dstWidth <= 0 || dstHeight <= 0)
1062 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001063
Brian Pauld4b799b2000-08-21 14:24:30 +00001064 for (j = 0; j < dstHeight; j++) {
1065 for (i = 0; i < dstWidth; i++) {
1066 GLfloat sumR = 0.0;
1067 GLfloat sumG = 0.0;
1068 GLfloat sumB = 0.0;
1069 GLfloat sumA = 0.0;
1070 for (m = 0; m < filterHeight; m++) {
1071 for (n = 0; n < filterWidth; n++) {
1072 const GLint k = (j + m) * srcWidth + i + n;
1073 const GLint f = m * filterWidth + n;
1074 sumR += src[k][RCOMP] * filter[f][RCOMP];
1075 sumG += src[k][GCOMP] * filter[f][GCOMP];
1076 sumB += src[k][BCOMP] * filter[f][BCOMP];
1077 sumA += src[k][ACOMP] * filter[f][ACOMP];
1078 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001079 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001080 dest[j * dstWidth + i][RCOMP] = sumR;
1081 dest[j * dstWidth + i][GCOMP] = sumG;
1082 dest[j * dstWidth + i][BCOMP] = sumB;
1083 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001084 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001085 }
1086}
1087
1088
Brian Pauld4b799b2000-08-21 14:24:30 +00001089static void
1090convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1091 const GLfloat src[][4],
1092 GLint filterWidth, GLint filterHeight,
1093 const GLfloat filter[][4],
1094 GLfloat dest[][4],
1095 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001096{
1097 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001098 const GLint halfFilterHeight = filterHeight / 2;
1099 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001100
Brian Pauld4b799b2000-08-21 14:24:30 +00001101 for (j = 0; j < srcHeight; j++) {
1102 for (i = 0; i < srcWidth; i++) {
1103 GLfloat sumR = 0.0;
1104 GLfloat sumG = 0.0;
1105 GLfloat sumB = 0.0;
1106 GLfloat sumA = 0.0;
1107 for (m = 0; m < filterHeight; m++) {
1108 for (n = 0; n < filterWidth; n++) {
1109 const GLint f = m * filterWidth + n;
1110 const GLint is = i + n - halfFilterWidth;
1111 const GLint js = j + m - halfFilterHeight;
1112 if (is < 0 || is >= srcWidth ||
1113 js < 0 || js >= srcHeight) {
1114 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1115 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1116 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1117 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1118 }
1119 else {
1120 const GLint k = js * srcWidth + is;
1121 sumR += src[k][RCOMP] * filter[f][RCOMP];
1122 sumG += src[k][GCOMP] * filter[f][GCOMP];
1123 sumB += src[k][BCOMP] * filter[f][BCOMP];
1124 sumA += src[k][ACOMP] * filter[f][ACOMP];
1125 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001126 }
1127 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001128 dest[j * srcWidth + i][RCOMP] = sumR;
1129 dest[j * srcWidth + i][GCOMP] = sumG;
1130 dest[j * srcWidth + i][BCOMP] = sumB;
1131 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001132 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001133 }
1134}
1135
1136
Brian Pauld4b799b2000-08-21 14:24:30 +00001137static void
1138convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1139 const GLfloat src[][4],
1140 GLint filterWidth, GLint filterHeight,
1141 const GLfloat filter[][4],
1142 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001143{
1144 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001145 const GLint halfFilterHeight = filterHeight / 2;
1146 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001147
Brian Pauld4b799b2000-08-21 14:24:30 +00001148 for (j = 0; j < srcHeight; j++) {
1149 for (i = 0; i < srcWidth; i++) {
1150 GLfloat sumR = 0.0;
1151 GLfloat sumG = 0.0;
1152 GLfloat sumB = 0.0;
1153 GLfloat sumA = 0.0;
1154 for (m = 0; m < filterHeight; m++) {
1155 for (n = 0; n < filterWidth; n++) {
1156 const GLint f = m * filterWidth + n;
1157 GLint is = i + n - halfFilterWidth;
1158 GLint js = j + m - halfFilterHeight;
1159 GLint k;
1160 if (is < 0)
1161 is = 0;
1162 else if (is >= srcWidth)
1163 is = srcWidth - 1;
1164 if (js < 0)
1165 js = 0;
1166 else if (js >= srcHeight)
1167 js = srcHeight - 1;
1168 k = js * srcWidth + is;
1169 sumR += src[k][RCOMP] * filter[f][RCOMP];
1170 sumG += src[k][GCOMP] * filter[f][GCOMP];
1171 sumB += src[k][BCOMP] * filter[f][BCOMP];
1172 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001173 }
1174 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001175 dest[j * srcWidth + i][RCOMP] = sumR;
1176 dest[j * srcWidth + i][GCOMP] = sumG;
1177 dest[j * srcWidth + i][BCOMP] = sumB;
1178 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001179 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001180 }
1181}
1182
1183
Brian Pauld4b799b2000-08-21 14:24:30 +00001184static void
1185convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1186 const GLfloat src[][4],
1187 GLint filterWidth, GLint filterHeight,
1188 const GLfloat rowFilt[][4],
1189 const GLfloat colFilt[][4],
1190 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001191{
Brian Paul7e708742000-08-22 18:54:25 +00001192 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001193 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001194
1195 if (filterWidth >= 1)
1196 dstWidth = srcWidth - (filterWidth - 1);
1197 else
1198 dstWidth = srcWidth;
1199
1200 if (filterHeight >= 1)
1201 dstHeight = srcHeight - (filterHeight - 1);
1202 else
1203 dstHeight = srcHeight;
1204
1205 if (dstWidth <= 0 || dstHeight <= 0)
1206 return;
1207
1208 for (j = 0; j < dstHeight; j++) {
1209 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001210 GLfloat sumR = 0.0;
1211 GLfloat sumG = 0.0;
1212 GLfloat sumB = 0.0;
1213 GLfloat sumA = 0.0;
1214 for (m = 0; m < filterHeight; m++) {
1215 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001216 GLint k = (j + m) * srcWidth + i + n;
1217 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1218 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1219 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1220 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001221 }
1222 }
Brian Paul7e708742000-08-22 18:54:25 +00001223 dest[j * dstWidth + i][RCOMP] = sumR;
1224 dest[j * dstWidth + i][GCOMP] = sumG;
1225 dest[j * dstWidth + i][BCOMP] = sumB;
1226 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001227 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001228 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001229}
1230
1231
Brian Pauld4b799b2000-08-21 14:24:30 +00001232static void
1233convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1234 const GLfloat src[][4],
1235 GLint filterWidth, GLint filterHeight,
1236 const GLfloat rowFilt[][4],
1237 const GLfloat colFilt[][4],
1238 GLfloat dest[][4],
1239 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001240{
1241 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001242 const GLint halfFilterHeight = filterHeight / 2;
1243 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001244
Brian Pauld4b799b2000-08-21 14:24:30 +00001245 for (j = 0; j < srcHeight; j++) {
1246 for (i = 0; i < srcWidth; i++) {
1247 GLfloat sumR = 0.0;
1248 GLfloat sumG = 0.0;
1249 GLfloat sumB = 0.0;
1250 GLfloat sumA = 0.0;
1251 for (m = 0; m < filterHeight; m++) {
1252 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001253 const GLint is = i + n - halfFilterWidth;
1254 const GLint js = j + m - halfFilterHeight;
1255 if (is < 0 || is >= srcWidth ||
1256 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001257 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1258 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1259 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1260 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1261 }
1262 else {
Brian Paul7e708742000-08-22 18:54:25 +00001263 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001264 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1265 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1266 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1267 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1268 }
Brian Paul7e708742000-08-22 18:54:25 +00001269
Brian Paulcc8e37f2000-07-12 13:00:09 +00001270 }
1271 }
Brian Paul7e708742000-08-22 18:54:25 +00001272 dest[j * srcWidth + i][RCOMP] = sumR;
1273 dest[j * srcWidth + i][GCOMP] = sumG;
1274 dest[j * srcWidth + i][BCOMP] = sumB;
1275 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001276 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001277 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001278}
1279
1280
1281static void
1282convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1283 const GLfloat src[][4],
1284 GLint filterWidth, GLint filterHeight,
1285 const GLfloat rowFilt[][4],
1286 const GLfloat colFilt[][4],
1287 GLfloat dest[][4])
1288{
1289 const GLint halfFilterWidth = filterWidth / 2;
1290 const GLint halfFilterHeight = filterHeight / 2;
1291 GLint i, j, n, m;
1292
1293 for (j = 0; j < srcHeight; j++) {
1294 for (i = 0; i < srcWidth; i++) {
1295 GLfloat sumR = 0.0;
1296 GLfloat sumG = 0.0;
1297 GLfloat sumB = 0.0;
1298 GLfloat sumA = 0.0;
1299 for (m = 0; m < filterHeight; m++) {
1300 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001301 GLint is = i + n - halfFilterWidth;
1302 GLint js = j + m - halfFilterHeight;
1303 GLint k;
1304 if (is < 0)
1305 is = 0;
1306 else if (is >= srcWidth)
1307 is = srcWidth - 1;
1308 if (js < 0)
1309 js = 0;
1310 else if (js >= srcHeight)
1311 js = srcHeight - 1;
1312 k = js * srcWidth + is;
1313 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1314 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1315 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1316 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001317 }
1318 }
Brian Paul7e708742000-08-22 18:54:25 +00001319 dest[j * srcWidth + i][RCOMP] = sumR;
1320 dest[j * srcWidth + i][GCOMP] = sumG;
1321 dest[j * srcWidth + i][BCOMP] = sumB;
1322 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001323 }
1324 }
1325}
1326
1327
1328
1329void
1330_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1331 const GLfloat *srcImage, GLfloat *dstImage)
1332{
1333 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1334 case GL_REDUCE:
1335 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1336 ctx->Convolution1D.Width,
1337 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1338 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001339 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001340 break;
1341 case GL_CONSTANT_BORDER:
1342 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1343 ctx->Convolution1D.Width,
1344 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1345 (GLfloat (*)[4]) dstImage,
1346 ctx->Pixel.ConvolutionBorderColor[0]);
1347 break;
1348 case GL_REPLICATE_BORDER:
1349 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1350 ctx->Convolution1D.Width,
1351 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1352 (GLfloat (*)[4]) dstImage);
1353 break;
1354 default:
1355 ;
1356 }
1357}
1358
1359
1360void
1361_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1362 const GLfloat *srcImage, GLfloat *dstImage)
1363{
1364 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1365 case GL_REDUCE:
1366 convolve_2d_reduce(*width, *height,
1367 (const GLfloat (*)[4]) srcImage,
1368 ctx->Convolution2D.Width,
1369 ctx->Convolution2D.Height,
1370 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1371 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001372 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1373 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001374 break;
1375 case GL_CONSTANT_BORDER:
1376 convolve_2d_constant(*width, *height,
1377 (const GLfloat (*)[4]) srcImage,
1378 ctx->Convolution2D.Width,
1379 ctx->Convolution2D.Height,
1380 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1381 (GLfloat (*)[4]) dstImage,
1382 ctx->Pixel.ConvolutionBorderColor[1]);
1383 break;
1384 case GL_REPLICATE_BORDER:
1385 convolve_2d_replicate(*width, *height,
1386 (const GLfloat (*)[4]) srcImage,
1387 ctx->Convolution2D.Width,
1388 ctx->Convolution2D.Height,
1389 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1390 (GLfloat (*)[4]) dstImage);
1391 break;
1392 default:
1393 ;
1394 }
1395}
1396
1397
1398void
1399_mesa_convolve_sep_image(const GLcontext *ctx,
1400 GLsizei *width, GLsizei *height,
1401 const GLfloat *srcImage, GLfloat *dstImage)
1402{
1403 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1404 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1405
1406 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1407 case GL_REDUCE:
1408 convolve_sep_reduce(*width, *height,
1409 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001410 ctx->Separable2D.Width,
1411 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001412 (const GLfloat (*)[4]) rowFilter,
1413 (const GLfloat (*)[4]) colFilter,
1414 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001415 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1416 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001417 break;
1418 case GL_CONSTANT_BORDER:
1419 convolve_sep_constant(*width, *height,
1420 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001421 ctx->Separable2D.Width,
1422 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001423 (const GLfloat (*)[4]) rowFilter,
1424 (const GLfloat (*)[4]) colFilter,
1425 (GLfloat (*)[4]) dstImage,
1426 ctx->Pixel.ConvolutionBorderColor[2]);
1427 break;
1428 case GL_REPLICATE_BORDER:
1429 convolve_sep_replicate(*width, *height,
1430 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001431 ctx->Separable2D.Width,
1432 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001433 (const GLfloat (*)[4]) rowFilter,
1434 (const GLfloat (*)[4]) colFilter,
1435 (GLfloat (*)[4]) dstImage);
1436 break;
1437 default:
1438 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001439 }
1440}
Brian Paul16461f72001-02-06 17:22:16 +00001441
1442
1443
1444/*
1445 * This function computes an image's size after convolution.
1446 * If the convolution border mode is GL_REDUCE, the post-convolution
1447 * image will be smaller than the original.
1448 */
1449void
1450_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1451 GLsizei *width, GLsizei *height)
1452{
1453 if (ctx->Pixel.Convolution1DEnabled
1454 && dimensions == 1
1455 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1456 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1457 }
1458 else if (ctx->Pixel.Convolution2DEnabled
1459 && dimensions > 1
1460 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1461 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1462 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1463 }
1464 else if (ctx->Pixel.Separable2DEnabled
1465 && dimensions > 1
1466 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1467 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1468 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1469 }
1470}