blob: 7e0761e68b81715d96e61c799f6e1f539cd375b4 [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 Paul203f3952009-09-03 10:41:14 -0600147 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, width, 1, 1,
148 format, type, image)) {
149 _mesa_error(ctx, GL_INVALID_OPERATION,
150 "glConvolutionFilter1D(invalid PBO access)");
151 return;
152 }
153
154 image = _mesa_map_pbo_source(ctx, &ctx->Unpack, image);
155 if (!image) {
156 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000157 _mesa_error(ctx, GL_INVALID_OPERATION,
158 "glConvolutionFilter1D(PBO is mapped)");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000159 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000160 return;
161 }
162
Brian Paul8cfd08b2004-02-28 20:35:57 +0000163 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
Brian Paul147b0832000-08-23 14:31:25 +0000164 ctx->Convolution1D.Filter,
165 format, type, image, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000166 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000167
Brian Paul203f3952009-09-03 10:41:14 -0600168 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000169
Brian Paul450e9172004-10-31 18:40:55 +0000170 _mesa_scale_and_bias_rgba(width,
171 (GLfloat (*)[4]) ctx->Convolution1D.Filter,
172 ctx->Pixel.ConvolutionFilterScale[0][0],
173 ctx->Pixel.ConvolutionFilterScale[0][1],
174 ctx->Pixel.ConvolutionFilterScale[0][2],
175 ctx->Pixel.ConvolutionFilterScale[0][3],
176 ctx->Pixel.ConvolutionFilterBias[0][0],
177 ctx->Pixel.ConvolutionFilterBias[0][1],
178 ctx->Pixel.ConvolutionFilterBias[0][2],
179 ctx->Pixel.ConvolutionFilterBias[0][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000180
Brian Paulb5012e12000-11-10 18:31:04 +0000181 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000182}
183
184
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000185void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000186_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
187{
Brian Pauld0570642002-03-19 15:22:50 +0000188 GLint baseFormat;
Brian Paulb3050282003-12-04 03:19:46 +0000189 GLint i;
Brian Paul147b0832000-08-23 14:31:25 +0000190 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000191 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000192
193 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000194 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000195 return;
196 }
197
198 baseFormat = base_filter_format(internalFormat);
199 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000200 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000201 return;
202 }
203
204 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000205 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000206 return;
207 }
208 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000209 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000210 return;
211 }
212
Brian Paulf959f6e2004-04-22 00:27:31 +0000213 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000214 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000215 return;
216 }
217 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000218 format == GL_STENCIL_INDEX ||
219 format == GL_DEPTH_COMPONENT ||
220 format == GL_INTENSITY ||
221 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000222 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000223 return;
224 }
225
Brian Paulb3050282003-12-04 03:19:46 +0000226 /* this should have been caught earlier */
227 assert(_mesa_components_in_format(format));
Brian Paul147b0832000-08-23 14:31:25 +0000228
229 ctx->Convolution2D.Format = format;
230 ctx->Convolution2D.InternalFormat = internalFormat;
231 ctx->Convolution2D.Width = width;
232 ctx->Convolution2D.Height = height;
233
Brian Paul203f3952009-09-03 10:41:14 -0600234 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
235 format, type, image)) {
236 _mesa_error(ctx, GL_INVALID_OPERATION,
237 "glConvolutionFilter2D(invalid PBO access)");
238 return;
239 }
240
241 image = _mesa_map_pbo_source(ctx, &ctx->Unpack, image);
242 if (!image) {
243 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000244 _mesa_error(ctx, GL_INVALID_OPERATION,
245 "glConvolutionFilter2D(PBO is mapped)");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000246 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000247 return;
248 }
249
Brian Paul147b0832000-08-23 14:31:25 +0000250 /* Unpack filter image. We always store filters in RGBA format. */
251 for (i = 0; i < height; i++) {
Brian Paul60909382004-11-10 15:46:52 +0000252 const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width,
253 height, format, type, i, 0);
Brian Paul147b0832000-08-23 14:31:25 +0000254 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000255 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
Brian Paul147b0832000-08-23 14:31:25 +0000256 format, type, src, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000257 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000258 }
259
Brian Paul203f3952009-09-03 10:41:14 -0600260 _mesa_unmap_pbo_source(ctx, &ctx->Unpack);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000261
Brian Paul450e9172004-10-31 18:40:55 +0000262 _mesa_scale_and_bias_rgba(width * height,
263 (GLfloat (*)[4]) ctx->Convolution2D.Filter,
264 ctx->Pixel.ConvolutionFilterScale[1][0],
265 ctx->Pixel.ConvolutionFilterScale[1][1],
266 ctx->Pixel.ConvolutionFilterScale[1][2],
267 ctx->Pixel.ConvolutionFilterScale[1][3],
268 ctx->Pixel.ConvolutionFilterBias[1][0],
269 ctx->Pixel.ConvolutionFilterBias[1][1],
270 ctx->Pixel.ConvolutionFilterBias[1][2],
271 ctx->Pixel.ConvolutionFilterBias[1][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000272
Brian Paulb5012e12000-11-10 18:31:04 +0000273 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000274}
275
276
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000277void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000278_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
279{
280 GET_CURRENT_CONTEXT(ctx);
281 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000282 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000283
284 switch (target) {
285 case GL_CONVOLUTION_1D:
286 c = 0;
287 break;
288 case GL_CONVOLUTION_2D:
289 c = 1;
290 break;
291 case GL_SEPARABLE_2D:
292 c = 2;
293 break;
294 default:
Brian Paul08836342001-03-03 20:33:27 +0000295 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000296 return;
297 }
298
299 switch (pname) {
300 case GL_CONVOLUTION_BORDER_MODE:
301 if (param == (GLfloat) GL_REDUCE ||
302 param == (GLfloat) GL_CONSTANT_BORDER ||
303 param == (GLfloat) GL_REPLICATE_BORDER) {
304 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
305 }
306 else {
Brian Paul08836342001-03-03 20:33:27 +0000307 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000308 return;
309 }
310 break;
311 default:
Brian Paul08836342001-03-03 20:33:27 +0000312 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000313 return;
314 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000315
316 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000317}
318
319
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000320void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000321_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
322{
323 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000324 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000325 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000326
327 switch (target) {
328 case GL_CONVOLUTION_1D:
329 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000330 break;
331 case GL_CONVOLUTION_2D:
332 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000333 break;
334 case GL_SEPARABLE_2D:
335 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000336 break;
337 default:
Brian Paul08836342001-03-03 20:33:27 +0000338 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000339 return;
340 }
341
342 switch (pname) {
343 case GL_CONVOLUTION_BORDER_COLOR:
344 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
345 break;
346 case GL_CONVOLUTION_BORDER_MODE:
347 if (params[0] == (GLfloat) GL_REDUCE ||
348 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
349 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
350 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
351 }
352 else {
Brian Paul08836342001-03-03 20:33:27 +0000353 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000354 return;
355 }
356 break;
357 case GL_CONVOLUTION_FILTER_SCALE:
358 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
359 break;
360 case GL_CONVOLUTION_FILTER_BIAS:
361 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
362 break;
363 default:
Brian Paul08836342001-03-03 20:33:27 +0000364 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000365 return;
366 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000367
368 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000369}
370
371
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000372void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000373_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
374{
375 GET_CURRENT_CONTEXT(ctx);
376 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000377 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000378
379 switch (target) {
380 case GL_CONVOLUTION_1D:
381 c = 0;
382 break;
383 case GL_CONVOLUTION_2D:
384 c = 1;
385 break;
386 case GL_SEPARABLE_2D:
387 c = 2;
388 break;
389 default:
Brian Paul08836342001-03-03 20:33:27 +0000390 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000391 return;
392 }
393
394 switch (pname) {
395 case GL_CONVOLUTION_BORDER_MODE:
396 if (param == (GLint) GL_REDUCE ||
397 param == (GLint) GL_CONSTANT_BORDER ||
398 param == (GLint) GL_REPLICATE_BORDER) {
399 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
400 }
401 else {
Brian Paul08836342001-03-03 20:33:27 +0000402 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000403 return;
404 }
405 break;
406 default:
Brian Paul08836342001-03-03 20:33:27 +0000407 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000408 return;
409 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000410
411 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000412}
413
414
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000415void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000416_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
417{
418 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000419 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000420 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000421
422 switch (target) {
423 case GL_CONVOLUTION_1D:
424 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000425 break;
426 case GL_CONVOLUTION_2D:
427 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000428 break;
429 case GL_SEPARABLE_2D:
430 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000431 break;
432 default:
Brian Paul08836342001-03-03 20:33:27 +0000433 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000434 return;
435 }
436
437 switch (pname) {
438 case GL_CONVOLUTION_BORDER_COLOR:
439 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
440 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
441 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
442 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
443 break;
444 case GL_CONVOLUTION_BORDER_MODE:
445 if (params[0] == (GLint) GL_REDUCE ||
446 params[0] == (GLint) GL_CONSTANT_BORDER ||
447 params[0] == (GLint) GL_REPLICATE_BORDER) {
448 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
449 }
450 else {
Brian Paul08836342001-03-03 20:33:27 +0000451 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000452 return;
453 }
454 break;
455 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000456 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
457 /* need cast to prevent compiler warnings */
458 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
459 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
460 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
461 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000462 break;
463 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000464 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
465 /* need cast to prevent compiler warnings */
466 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
467 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
468 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
469 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000470 break;
471 default:
Brian Paul08836342001-03-03 20:33:27 +0000472 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000473 return;
474 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000475
476 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000477}
478
479
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000480void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000481_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
482{
Brian Pauld0570642002-03-19 15:22:50 +0000483 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000484 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000485 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000486
487 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000488 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000489 return;
490 }
491
492 baseFormat = base_filter_format(internalFormat);
493 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000494 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000495 return;
496 }
497
498 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000499 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000500 return;
501 }
502
Keith Whitwell70989242001-03-19 02:25:35 +0000503 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
504 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000505}
506
507
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000508void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000509_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
510{
Brian Pauld0570642002-03-19 15:22:50 +0000511 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000512 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000513 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000514
515 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000516 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000517 return;
518 }
519
520 baseFormat = base_filter_format(internalFormat);
521 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000522 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000523 return;
524 }
525
526 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000527 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000528 return;
529 }
530 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000531 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000532 return;
533 }
534
Keith Whitwell70989242001-03-19 02:25:35 +0000535 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
536 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000537}
538
539
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000540void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000541_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type,
542 GLvoid *image)
Brian Paul147b0832000-08-23 14:31:25 +0000543{
Brian Paul176501d2006-10-13 16:34:25 +0000544 struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000545 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000546 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000547 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000548
Brian Paul0c000ec2000-11-21 23:26:13 +0000549 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000550 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000551 }
552
Brian Paulf959f6e2004-04-22 00:27:31 +0000553 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000554 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000555 return;
556 }
557
558 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000559 format == GL_STENCIL_INDEX ||
560 format == GL_DEPTH_COMPONENT ||
561 format == GL_INTENSITY ||
562 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000563 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000564 return;
565 }
566
Brian Paulf75d6972000-09-05 20:28:56 +0000567 switch (target) {
568 case GL_CONVOLUTION_1D:
569 filter = &(ctx->Convolution1D);
570 break;
571 case GL_CONVOLUTION_2D:
572 filter = &(ctx->Convolution2D);
573 break;
574 default:
Brian Paul08836342001-03-03 20:33:27 +0000575 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000576 return;
577 }
578
Brian Paul203f3952009-09-03 10:41:14 -0600579 if (!_mesa_validate_pbo_access(2, &ctx->Pack,
580 filter->Width, filter->Height,
581 1, format, type, image)) {
582 _mesa_error(ctx, GL_INVALID_OPERATION,
583 "glGetConvolutionFilter(invalid PBO access)");
584 return;
585 }
586
587 image = _mesa_map_pbo_dest(ctx, &ctx->Pack, image);
588 if (!image) {
589 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000590 _mesa_error(ctx, GL_INVALID_OPERATION,
591 "glGetConvolutionFilter(PBO is mapped)");
Brian Paulbd3b40a2004-10-31 17:36:23 +0000592 }
Brian Paul203f3952009-09-03 10:41:14 -0600593 return;
Brian Paulbd3b40a2004-10-31 17:36:23 +0000594 }
595
Brian Paulf75d6972000-09-05 20:28:56 +0000596 for (row = 0; row < filter->Height; row++) {
Brian Paul60909382004-11-10 15:46:52 +0000597 GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width,
598 filter->Height, format, type,
599 row, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000600 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + row * filter->Width * 4);
601 _mesa_pack_rgba_span_float(ctx, filter->Width, src,
602 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000603 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000604
Brian Paul203f3952009-09-03 10:41:14 -0600605 _mesa_unmap_pbo_dest(ctx, &ctx->Pack);
Brian Paul147b0832000-08-23 14:31:25 +0000606}
607
608
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000609void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000610_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
611{
612 GET_CURRENT_CONTEXT(ctx);
613 const struct gl_convolution_attrib *conv;
614 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000615 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000616
617 switch (target) {
618 case GL_CONVOLUTION_1D:
619 c = 0;
620 conv = &ctx->Convolution1D;
621 break;
622 case GL_CONVOLUTION_2D:
623 c = 1;
624 conv = &ctx->Convolution2D;
625 break;
626 case GL_SEPARABLE_2D:
627 c = 2;
628 conv = &ctx->Separable2D;
629 break;
630 default:
Brian Paul08836342001-03-03 20:33:27 +0000631 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000632 return;
633 }
634
635 switch (pname) {
636 case GL_CONVOLUTION_BORDER_COLOR:
637 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
638 break;
639 case GL_CONVOLUTION_BORDER_MODE:
640 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
641 break;
642 case GL_CONVOLUTION_FILTER_SCALE:
643 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
644 break;
645 case GL_CONVOLUTION_FILTER_BIAS:
646 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
647 break;
648 case GL_CONVOLUTION_FORMAT:
649 *params = (GLfloat) conv->Format;
650 break;
651 case GL_CONVOLUTION_WIDTH:
652 *params = (GLfloat) conv->Width;
653 break;
654 case GL_CONVOLUTION_HEIGHT:
655 *params = (GLfloat) conv->Height;
656 break;
657 case GL_MAX_CONVOLUTION_WIDTH:
658 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
659 break;
660 case GL_MAX_CONVOLUTION_HEIGHT:
661 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
662 break;
663 default:
Brian Paul08836342001-03-03 20:33:27 +0000664 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000665 return;
666 }
667}
668
669
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000670void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000671_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
672{
673 GET_CURRENT_CONTEXT(ctx);
674 const struct gl_convolution_attrib *conv;
675 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000676 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000677
678 switch (target) {
679 case GL_CONVOLUTION_1D:
680 c = 0;
681 conv = &ctx->Convolution1D;
682 break;
683 case GL_CONVOLUTION_2D:
684 c = 1;
685 conv = &ctx->Convolution2D;
686 break;
687 case GL_SEPARABLE_2D:
688 c = 2;
689 conv = &ctx->Separable2D;
690 break;
691 default:
Brian Paul08836342001-03-03 20:33:27 +0000692 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000693 return;
694 }
695
696 switch (pname) {
697 case GL_CONVOLUTION_BORDER_COLOR:
698 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
699 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
700 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
701 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
702 break;
703 case GL_CONVOLUTION_BORDER_MODE:
704 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
705 break;
706 case GL_CONVOLUTION_FILTER_SCALE:
707 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
708 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
709 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
710 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
711 break;
712 case GL_CONVOLUTION_FILTER_BIAS:
713 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
714 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
715 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
716 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
717 break;
718 case GL_CONVOLUTION_FORMAT:
719 *params = (GLint) conv->Format;
720 break;
721 case GL_CONVOLUTION_WIDTH:
722 *params = (GLint) conv->Width;
723 break;
724 case GL_CONVOLUTION_HEIGHT:
725 *params = (GLint) conv->Height;
726 break;
727 case GL_MAX_CONVOLUTION_WIDTH:
728 *params = (GLint) ctx->Const.MaxConvolutionWidth;
729 break;
730 case GL_MAX_CONVOLUTION_HEIGHT:
731 *params = (GLint) ctx->Const.MaxConvolutionHeight;
732 break;
733 default:
Brian Paul08836342001-03-03 20:33:27 +0000734 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000735 return;
736 }
737}
738
739
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000740void GLAPIENTRY
Brian Paul176501d2006-10-13 16:34:25 +0000741_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type,
742 GLvoid *row, GLvoid *column, GLvoid *span)
Brian Paul147b0832000-08-23 14:31:25 +0000743{
Brian Paulf75d6972000-09-05 20:28:56 +0000744 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Paul176501d2006-10-13 16:34:25 +0000745 struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000746 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000747 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000748
Brian Paul0c000ec2000-11-21 23:26:13 +0000749 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000750 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000751 }
752
Brian Paul147b0832000-08-23 14:31:25 +0000753 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000754 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000755 return;
756 }
757
Brian Paulf959f6e2004-04-22 00:27:31 +0000758 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul176501d2006-10-13 16:34:25 +0000759 _mesa_error(ctx, GL_INVALID_OPERATION,
760 "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000761 return;
762 }
763
764 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000765 format == GL_STENCIL_INDEX ||
766 format == GL_DEPTH_COMPONENT ||
767 format == GL_INTENSITY ||
768 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000769 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000770 return;
771 }
772
Brian Paulf75d6972000-09-05 20:28:56 +0000773 filter = &ctx->Separable2D;
774
Brian Paul434ec3a2009-08-12 13:46:16 -0600775 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000776 /* Pack filter into PBO */
777 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000778 if (!_mesa_validate_pbo_access(1, &ctx->Pack, filter->Width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000779 format, type, row)) {
780 _mesa_error(ctx, GL_INVALID_OPERATION,
781 "glGetSeparableFilter(invalid PBO access, width)");
782 return;
783 }
Brian Paul60909382004-11-10 15:46:52 +0000784 if (!_mesa_validate_pbo_access(1, &ctx->Pack, filter->Height, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000785 format, type, column)) {
786 _mesa_error(ctx, GL_INVALID_OPERATION,
787 "glGetSeparableFilter(invalid PBO access, height)");
788 return;
789 }
790 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
791 GL_WRITE_ONLY_ARB,
792 ctx->Pack.BufferObj);
793 if (!buf) {
794 /* buffer is already mapped - that's an error */
795 _mesa_error(ctx, GL_INVALID_OPERATION,
796 "glGetSeparableFilter(PBO is mapped)");
797 return;
798 }
799 row = ADD_POINTERS(buf, row);
800 column = ADD_POINTERS(buf, column);
801 }
802
Brian Paulf75d6972000-09-05 20:28:56 +0000803 /* Row filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000804 if (row) {
Brian Paul60909382004-11-10 15:46:52 +0000805 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width,
806 format, type, 0);
Brian Paul8cfd08b2004-02-28 20:35:57 +0000807 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paul176501d2006-10-13 16:34:25 +0000808 (GLfloat (*)[4]) filter->Filter,
809 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000810 }
811
812 /* Column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000813 if (column) {
Brian Paul60909382004-11-10 15:46:52 +0000814 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height,
815 format, type, 0);
Brian Paul176501d2006-10-13 16:34:25 +0000816 GLfloat (*src)[4] = (GLfloat (*)[4]) (filter->Filter + colStart);
817 _mesa_pack_rgba_span_float(ctx, filter->Height, src,
818 format, type, dst, &ctx->Pack, 0x0);
Brian Paulf75d6972000-09-05 20:28:56 +0000819 }
820
821 (void) span; /* unused at this time */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000822
Brian Paul434ec3a2009-08-12 13:46:16 -0600823 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000824 /* Pack filter into PBO */
825 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
826 ctx->Unpack.BufferObj);
827 }
Brian Paul147b0832000-08-23 14:31:25 +0000828}
829
830
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000831void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000832_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
833{
834 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000835 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000836 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000837 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000838
839 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000840 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000841 return;
842 }
843
844 baseFormat = base_filter_format(internalFormat);
845 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000846 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000847 return;
848 }
849
850 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000851 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000852 return;
853 }
854 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000855 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000856 return;
857 }
858
Brian Paulf959f6e2004-04-22 00:27:31 +0000859 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000860 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000861 return;
862 }
863
864 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000865 format == GL_STENCIL_INDEX ||
866 format == GL_DEPTH_COMPONENT ||
867 format == GL_INTENSITY ||
868 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000869 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000870 return;
871 }
872
873 ctx->Separable2D.Format = format;
874 ctx->Separable2D.InternalFormat = internalFormat;
875 ctx->Separable2D.Width = width;
876 ctx->Separable2D.Height = height;
877
Brian Paul434ec3a2009-08-12 13:46:16 -0600878 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000879 /* unpack filter from PBO */
880 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000881 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000882 format, type, row)) {
883 _mesa_error(ctx, GL_INVALID_OPERATION,
884 "glSeparableFilter2D(invalid PBO access, width)");
885 return;
886 }
Brian Paul60909382004-11-10 15:46:52 +0000887 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, height, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000888 format, type, column)) {
889 _mesa_error(ctx, GL_INVALID_OPERATION,
890 "glSeparableFilter2D(invalid PBO access, height)");
891 return;
892 }
893 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
894 GL_READ_ONLY_ARB,
895 ctx->Unpack.BufferObj);
896 if (!buf) {
897 /* buffer is already mapped - that's an error */
898 _mesa_error(ctx, GL_INVALID_OPERATION,
899 "glSeparableFilter2D(PBO is mapped)");
900 return;
901 }
902 row = ADD_POINTERS(buf, row);
903 column = ADD_POINTERS(buf, column);
904 }
Brian Paul147b0832000-08-23 14:31:25 +0000905
Brian Paulbd3b40a2004-10-31 17:36:23 +0000906 /* unpack row filter */
907 if (row) {
908 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
909 ctx->Separable2D.Filter,
910 format, type, row, &ctx->Unpack,
911 0); /* transferOps */
912
Brian Paul450e9172004-10-31 18:40:55 +0000913 _mesa_scale_and_bias_rgba(width,
914 (GLfloat (*)[4]) ctx->Separable2D.Filter,
915 ctx->Pixel.ConvolutionFilterScale[2][0],
916 ctx->Pixel.ConvolutionFilterScale[2][1],
917 ctx->Pixel.ConvolutionFilterScale[2][2],
918 ctx->Pixel.ConvolutionFilterScale[2][3],
919 ctx->Pixel.ConvolutionFilterBias[2][0],
920 ctx->Pixel.ConvolutionFilterBias[2][1],
921 ctx->Pixel.ConvolutionFilterBias[2][2],
922 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul147b0832000-08-23 14:31:25 +0000923 }
924
925 /* unpack column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000926 if (column) {
Brian Pauleffb7202004-10-31 18:41:38 +0000927 _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
928 &ctx->Separable2D.Filter[colStart],
929 format, type, column, &ctx->Unpack,
930 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000931
Brian Paul450e9172004-10-31 18:40:55 +0000932 _mesa_scale_and_bias_rgba(height,
933 (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart),
934 ctx->Pixel.ConvolutionFilterScale[2][0],
935 ctx->Pixel.ConvolutionFilterScale[2][1],
936 ctx->Pixel.ConvolutionFilterScale[2][2],
937 ctx->Pixel.ConvolutionFilterScale[2][3],
938 ctx->Pixel.ConvolutionFilterBias[2][0],
939 ctx->Pixel.ConvolutionFilterBias[2][1],
940 ctx->Pixel.ConvolutionFilterBias[2][2],
941 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000942 }
943
Brian Paul434ec3a2009-08-12 13:46:16 -0600944 if (_mesa_is_bufferobj(ctx->Unpack.BufferObj)) {
Brian Paulbd3b40a2004-10-31 17:36:23 +0000945 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
946 ctx->Unpack.BufferObj);
Brian Paul147b0832000-08-23 14:31:25 +0000947 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000948
Brian Paulb5012e12000-11-10 18:31:04 +0000949 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000950}
951
952
953/**********************************************************************/
954/*** image convolution functions ***/
955/**********************************************************************/
956
Brian Pauld4b799b2000-08-21 14:24:30 +0000957static void
958convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
959 GLint filterWidth, const GLfloat filter[][4],
960 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000961{
Brian Paul7e708742000-08-22 18:54:25 +0000962 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000963 GLint i, n;
964
Brian Paul7e708742000-08-22 18:54:25 +0000965 if (filterWidth >= 1)
966 dstWidth = srcWidth - (filterWidth - 1);
967 else
968 dstWidth = srcWidth;
969
Brian Paulcc8e37f2000-07-12 13:00:09 +0000970 if (dstWidth <= 0)
971 return; /* null result */
972
973 for (i = 0; i < dstWidth; 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 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
980 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
981 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
982 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
983 }
984 dest[i][RCOMP] = sumR;
985 dest[i][GCOMP] = sumG;
986 dest[i][BCOMP] = sumB;
987 dest[i][ACOMP] = sumA;
988 }
989}
990
991
Brian Pauld4b799b2000-08-21 14:24:30 +0000992static void
993convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
994 GLint filterWidth, const GLfloat filter[][4],
995 GLfloat dest[][4],
996 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000997{
998 const GLint halfFilterWidth = filterWidth / 2;
999 GLint i, n;
1000
1001 for (i = 0; i < srcWidth; i++) {
1002 GLfloat sumR = 0.0;
1003 GLfloat sumG = 0.0;
1004 GLfloat sumB = 0.0;
1005 GLfloat sumA = 0.0;
1006 for (n = 0; n < filterWidth; n++) {
1007 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
1008 sumR += borderColor[RCOMP] * filter[n][RCOMP];
1009 sumG += borderColor[GCOMP] * filter[n][GCOMP];
1010 sumB += borderColor[BCOMP] * filter[n][BCOMP];
1011 sumA += borderColor[ACOMP] * filter[n][ACOMP];
1012 }
1013 else {
1014 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1015 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1016 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1017 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1018 }
1019 }
1020 dest[i][RCOMP] = sumR;
1021 dest[i][GCOMP] = sumG;
1022 dest[i][BCOMP] = sumB;
1023 dest[i][ACOMP] = sumA;
1024 }
1025}
1026
1027
Brian Pauld4b799b2000-08-21 14:24:30 +00001028static void
1029convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
1030 GLint filterWidth, const GLfloat filter[][4],
1031 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001032{
1033 const GLint halfFilterWidth = filterWidth / 2;
1034 GLint i, n;
1035
1036 for (i = 0; i < srcWidth; i++) {
1037 GLfloat sumR = 0.0;
1038 GLfloat sumG = 0.0;
1039 GLfloat sumB = 0.0;
1040 GLfloat sumA = 0.0;
1041 for (n = 0; n < filterWidth; n++) {
1042 if (i + n < halfFilterWidth) {
1043 sumR += src[0][RCOMP] * filter[n][RCOMP];
1044 sumG += src[0][GCOMP] * filter[n][GCOMP];
1045 sumB += src[0][BCOMP] * filter[n][BCOMP];
1046 sumA += src[0][ACOMP] * filter[n][ACOMP];
1047 }
1048 else if (i + n - halfFilterWidth >= srcWidth) {
1049 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
1050 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
1051 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
1052 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
1053 }
1054 else {
1055 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1056 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1057 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1058 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1059 }
1060 }
1061 dest[i][RCOMP] = sumR;
1062 dest[i][GCOMP] = sumG;
1063 dest[i][BCOMP] = sumB;
1064 dest[i][ACOMP] = sumA;
1065 }
1066}
1067
1068
Brian Pauld4b799b2000-08-21 14:24:30 +00001069static void
1070convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1071 const GLfloat src[][4],
1072 GLint filterWidth, GLint filterHeight,
1073 const GLfloat filter[][4],
1074 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001075{
Brian Paul7e708742000-08-22 18:54:25 +00001076 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001077 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001078
Brian Paul7e708742000-08-22 18:54:25 +00001079 if (filterWidth >= 1)
1080 dstWidth = srcWidth - (filterWidth - 1);
1081 else
1082 dstWidth = srcWidth;
1083
1084 if (filterHeight >= 1)
1085 dstHeight = srcHeight - (filterHeight - 1);
1086 else
1087 dstHeight = srcHeight;
1088
Brian Pauld4b799b2000-08-21 14:24:30 +00001089 if (dstWidth <= 0 || dstHeight <= 0)
1090 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001091
Brian Pauld4b799b2000-08-21 14:24:30 +00001092 for (j = 0; j < dstHeight; j++) {
1093 for (i = 0; i < dstWidth; i++) {
1094 GLfloat sumR = 0.0;
1095 GLfloat sumG = 0.0;
1096 GLfloat sumB = 0.0;
1097 GLfloat sumA = 0.0;
1098 for (m = 0; m < filterHeight; m++) {
1099 for (n = 0; n < filterWidth; n++) {
1100 const GLint k = (j + m) * srcWidth + i + n;
1101 const GLint f = m * filterWidth + n;
1102 sumR += src[k][RCOMP] * filter[f][RCOMP];
1103 sumG += src[k][GCOMP] * filter[f][GCOMP];
1104 sumB += src[k][BCOMP] * filter[f][BCOMP];
1105 sumA += src[k][ACOMP] * filter[f][ACOMP];
1106 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001107 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001108 dest[j * dstWidth + i][RCOMP] = sumR;
1109 dest[j * dstWidth + i][GCOMP] = sumG;
1110 dest[j * dstWidth + i][BCOMP] = sumB;
1111 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001112 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001113 }
1114}
1115
1116
Brian Pauld4b799b2000-08-21 14:24:30 +00001117static void
1118convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1119 const GLfloat src[][4],
1120 GLint filterWidth, GLint filterHeight,
1121 const GLfloat filter[][4],
1122 GLfloat dest[][4],
1123 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001124{
1125 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001126 const GLint halfFilterHeight = filterHeight / 2;
1127 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001128
Brian Pauld4b799b2000-08-21 14:24:30 +00001129 for (j = 0; j < srcHeight; j++) {
1130 for (i = 0; i < srcWidth; i++) {
1131 GLfloat sumR = 0.0;
1132 GLfloat sumG = 0.0;
1133 GLfloat sumB = 0.0;
1134 GLfloat sumA = 0.0;
1135 for (m = 0; m < filterHeight; m++) {
1136 for (n = 0; n < filterWidth; n++) {
1137 const GLint f = m * filterWidth + n;
1138 const GLint is = i + n - halfFilterWidth;
1139 const GLint js = j + m - halfFilterHeight;
1140 if (is < 0 || is >= srcWidth ||
1141 js < 0 || js >= srcHeight) {
1142 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1143 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1144 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1145 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1146 }
1147 else {
1148 const GLint k = js * srcWidth + is;
1149 sumR += src[k][RCOMP] * filter[f][RCOMP];
1150 sumG += src[k][GCOMP] * filter[f][GCOMP];
1151 sumB += src[k][BCOMP] * filter[f][BCOMP];
1152 sumA += src[k][ACOMP] * filter[f][ACOMP];
1153 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001154 }
1155 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001156 dest[j * srcWidth + i][RCOMP] = sumR;
1157 dest[j * srcWidth + i][GCOMP] = sumG;
1158 dest[j * srcWidth + i][BCOMP] = sumB;
1159 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001160 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001161 }
1162}
1163
1164
Brian Pauld4b799b2000-08-21 14:24:30 +00001165static void
1166convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1167 const GLfloat src[][4],
1168 GLint filterWidth, GLint filterHeight,
1169 const GLfloat filter[][4],
1170 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001171{
1172 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001173 const GLint halfFilterHeight = filterHeight / 2;
1174 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001175
Brian Pauld4b799b2000-08-21 14:24:30 +00001176 for (j = 0; j < srcHeight; j++) {
1177 for (i = 0; i < srcWidth; i++) {
1178 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++) {
1184 const GLint f = m * filterWidth + n;
1185 GLint is = i + n - halfFilterWidth;
1186 GLint js = j + m - halfFilterHeight;
1187 GLint k;
1188 if (is < 0)
1189 is = 0;
1190 else if (is >= srcWidth)
1191 is = srcWidth - 1;
1192 if (js < 0)
1193 js = 0;
1194 else if (js >= srcHeight)
1195 js = srcHeight - 1;
1196 k = js * srcWidth + is;
1197 sumR += src[k][RCOMP] * filter[f][RCOMP];
1198 sumG += src[k][GCOMP] * filter[f][GCOMP];
1199 sumB += src[k][BCOMP] * filter[f][BCOMP];
1200 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001201 }
1202 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001203 dest[j * srcWidth + i][RCOMP] = sumR;
1204 dest[j * srcWidth + i][GCOMP] = sumG;
1205 dest[j * srcWidth + i][BCOMP] = sumB;
1206 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001207 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001208 }
1209}
1210
1211
Brian Pauld4b799b2000-08-21 14:24:30 +00001212static void
1213convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1214 const GLfloat src[][4],
1215 GLint filterWidth, GLint filterHeight,
1216 const GLfloat rowFilt[][4],
1217 const GLfloat colFilt[][4],
1218 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001219{
Brian Paul7e708742000-08-22 18:54:25 +00001220 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001221 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001222
1223 if (filterWidth >= 1)
1224 dstWidth = srcWidth - (filterWidth - 1);
1225 else
1226 dstWidth = srcWidth;
1227
1228 if (filterHeight >= 1)
1229 dstHeight = srcHeight - (filterHeight - 1);
1230 else
1231 dstHeight = srcHeight;
1232
1233 if (dstWidth <= 0 || dstHeight <= 0)
1234 return;
1235
1236 for (j = 0; j < dstHeight; j++) {
1237 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001238 GLfloat sumR = 0.0;
1239 GLfloat sumG = 0.0;
1240 GLfloat sumB = 0.0;
1241 GLfloat sumA = 0.0;
1242 for (m = 0; m < filterHeight; m++) {
1243 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001244 GLint k = (j + m) * srcWidth + i + n;
1245 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1246 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1247 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1248 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001249 }
1250 }
Brian Paul7e708742000-08-22 18:54:25 +00001251 dest[j * dstWidth + i][RCOMP] = sumR;
1252 dest[j * dstWidth + i][GCOMP] = sumG;
1253 dest[j * dstWidth + i][BCOMP] = sumB;
1254 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001255 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001256 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001257}
1258
1259
Brian Pauld4b799b2000-08-21 14:24:30 +00001260static void
1261convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1262 const GLfloat src[][4],
1263 GLint filterWidth, GLint filterHeight,
1264 const GLfloat rowFilt[][4],
1265 const GLfloat colFilt[][4],
1266 GLfloat dest[][4],
1267 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001268{
1269 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001270 const GLint halfFilterHeight = filterHeight / 2;
1271 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001272
Brian Pauld4b799b2000-08-21 14:24:30 +00001273 for (j = 0; j < srcHeight; j++) {
1274 for (i = 0; i < srcWidth; i++) {
1275 GLfloat sumR = 0.0;
1276 GLfloat sumG = 0.0;
1277 GLfloat sumB = 0.0;
1278 GLfloat sumA = 0.0;
1279 for (m = 0; m < filterHeight; m++) {
1280 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001281 const GLint is = i + n - halfFilterWidth;
1282 const GLint js = j + m - halfFilterHeight;
1283 if (is < 0 || is >= srcWidth ||
1284 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001285 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1286 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1287 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1288 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1289 }
1290 else {
Brian Paul7e708742000-08-22 18:54:25 +00001291 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001292 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1293 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1294 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1295 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1296 }
Brian Paul7e708742000-08-22 18:54:25 +00001297
Brian Paulcc8e37f2000-07-12 13:00:09 +00001298 }
1299 }
Brian Paul7e708742000-08-22 18:54:25 +00001300 dest[j * srcWidth + i][RCOMP] = sumR;
1301 dest[j * srcWidth + i][GCOMP] = sumG;
1302 dest[j * srcWidth + i][BCOMP] = sumB;
1303 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001304 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001305 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001306}
1307
1308
1309static void
1310convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1311 const GLfloat src[][4],
1312 GLint filterWidth, GLint filterHeight,
1313 const GLfloat rowFilt[][4],
1314 const GLfloat colFilt[][4],
1315 GLfloat dest[][4])
1316{
1317 const GLint halfFilterWidth = filterWidth / 2;
1318 const GLint halfFilterHeight = filterHeight / 2;
1319 GLint i, j, n, m;
1320
1321 for (j = 0; j < srcHeight; j++) {
1322 for (i = 0; i < srcWidth; i++) {
1323 GLfloat sumR = 0.0;
1324 GLfloat sumG = 0.0;
1325 GLfloat sumB = 0.0;
1326 GLfloat sumA = 0.0;
1327 for (m = 0; m < filterHeight; m++) {
1328 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001329 GLint is = i + n - halfFilterWidth;
1330 GLint js = j + m - halfFilterHeight;
1331 GLint k;
1332 if (is < 0)
1333 is = 0;
1334 else if (is >= srcWidth)
1335 is = srcWidth - 1;
1336 if (js < 0)
1337 js = 0;
1338 else if (js >= srcHeight)
1339 js = srcHeight - 1;
1340 k = js * srcWidth + is;
1341 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1342 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1343 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1344 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001345 }
1346 }
Brian Paul7e708742000-08-22 18:54:25 +00001347 dest[j * srcWidth + i][RCOMP] = sumR;
1348 dest[j * srcWidth + i][GCOMP] = sumG;
1349 dest[j * srcWidth + i][BCOMP] = sumB;
1350 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001351 }
1352 }
1353}
1354
1355
1356
1357void
1358_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1359 const GLfloat *srcImage, GLfloat *dstImage)
1360{
1361 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1362 case GL_REDUCE:
1363 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1364 ctx->Convolution1D.Width,
1365 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1366 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001367 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001368 break;
1369 case GL_CONSTANT_BORDER:
1370 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1371 ctx->Convolution1D.Width,
1372 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1373 (GLfloat (*)[4]) dstImage,
1374 ctx->Pixel.ConvolutionBorderColor[0]);
1375 break;
1376 case GL_REPLICATE_BORDER:
1377 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1378 ctx->Convolution1D.Width,
1379 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1380 (GLfloat (*)[4]) dstImage);
1381 break;
1382 default:
1383 ;
1384 }
1385}
1386
1387
1388void
1389_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1390 const GLfloat *srcImage, GLfloat *dstImage)
1391{
1392 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1393 case GL_REDUCE:
1394 convolve_2d_reduce(*width, *height,
1395 (const GLfloat (*)[4]) srcImage,
1396 ctx->Convolution2D.Width,
1397 ctx->Convolution2D.Height,
1398 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1399 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001400 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1401 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001402 break;
1403 case GL_CONSTANT_BORDER:
1404 convolve_2d_constant(*width, *height,
1405 (const GLfloat (*)[4]) srcImage,
1406 ctx->Convolution2D.Width,
1407 ctx->Convolution2D.Height,
1408 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1409 (GLfloat (*)[4]) dstImage,
1410 ctx->Pixel.ConvolutionBorderColor[1]);
1411 break;
1412 case GL_REPLICATE_BORDER:
1413 convolve_2d_replicate(*width, *height,
1414 (const GLfloat (*)[4]) srcImage,
1415 ctx->Convolution2D.Width,
1416 ctx->Convolution2D.Height,
1417 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1418 (GLfloat (*)[4]) dstImage);
1419 break;
1420 default:
1421 ;
1422 }
1423}
1424
1425
1426void
1427_mesa_convolve_sep_image(const GLcontext *ctx,
1428 GLsizei *width, GLsizei *height,
1429 const GLfloat *srcImage, GLfloat *dstImage)
1430{
1431 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1432 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1433
1434 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1435 case GL_REDUCE:
1436 convolve_sep_reduce(*width, *height,
1437 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001438 ctx->Separable2D.Width,
1439 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001440 (const GLfloat (*)[4]) rowFilter,
1441 (const GLfloat (*)[4]) colFilter,
1442 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001443 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1444 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001445 break;
1446 case GL_CONSTANT_BORDER:
1447 convolve_sep_constant(*width, *height,
1448 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001449 ctx->Separable2D.Width,
1450 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001451 (const GLfloat (*)[4]) rowFilter,
1452 (const GLfloat (*)[4]) colFilter,
1453 (GLfloat (*)[4]) dstImage,
1454 ctx->Pixel.ConvolutionBorderColor[2]);
1455 break;
1456 case GL_REPLICATE_BORDER:
1457 convolve_sep_replicate(*width, *height,
1458 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001459 ctx->Separable2D.Width,
1460 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001461 (const GLfloat (*)[4]) rowFilter,
1462 (const GLfloat (*)[4]) colFilter,
1463 (GLfloat (*)[4]) dstImage);
1464 break;
1465 default:
1466 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001467 }
1468}
Brian Paul16461f72001-02-06 17:22:16 +00001469
1470
1471
1472/*
1473 * This function computes an image's size after convolution.
1474 * If the convolution border mode is GL_REDUCE, the post-convolution
1475 * image will be smaller than the original.
1476 */
1477void
1478_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1479 GLsizei *width, GLsizei *height)
1480{
1481 if (ctx->Pixel.Convolution1DEnabled
1482 && dimensions == 1
1483 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1484 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1485 }
1486 else if (ctx->Pixel.Convolution2DEnabled
1487 && dimensions > 1
1488 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1489 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1490 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1491 }
1492 else if (ctx->Pixel.Separable2DEnabled
1493 && dimensions > 1
1494 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1495 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1496 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1497 }
1498}