blob: 6b97c7f56cdbd6a4f506a5d83653348c5c93d0df [file] [log] [blame]
Brian Paulcc8e37f2000-07-12 13:00:09 +00001/*
2 * Mesa 3-D graphics library
Brian Paulbd3b40a2004-10-31 17:36:23 +00003 * Version: 6.3
Brian Paulcc8e37f2000-07-12 13:00:09 +00004 *
Brian Paul4923e192004-02-28 22:30:58 +00005 * Copyright (C) 1999-2004 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 Paulbd3b40a2004-10-31 17:36:23 +0000147 if (ctx->Unpack.BufferObj->Name) {
148 /* unpack filter from PBO */
149 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000150 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000151 format, type, image)) {
152 _mesa_error(ctx, GL_INVALID_OPERATION,
153 "glConvolutionFilter1D(invalid PBO access)");
154 return;
155 }
156 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
157 GL_READ_ONLY_ARB,
158 ctx->Unpack.BufferObj);
159 if (!buf) {
160 /* buffer is already mapped - that's an error */
161 _mesa_error(ctx, GL_INVALID_OPERATION,
162 "glConvolutionFilter1D(PBO is mapped)");
163 return;
164 }
165 image = ADD_POINTERS(buf, image);
166 }
167 else if (!image) {
168 return;
169 }
170
Brian Paul8cfd08b2004-02-28 20:35:57 +0000171 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
Brian Paul147b0832000-08-23 14:31:25 +0000172 ctx->Convolution1D.Filter,
173 format, type, image, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000174 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000175
Brian Paulbd3b40a2004-10-31 17:36:23 +0000176 if (ctx->Unpack.BufferObj->Name) {
177 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
178 ctx->Unpack.BufferObj);
179 }
180
Brian Paul450e9172004-10-31 18:40:55 +0000181 _mesa_scale_and_bias_rgba(width,
182 (GLfloat (*)[4]) ctx->Convolution1D.Filter,
183 ctx->Pixel.ConvolutionFilterScale[0][0],
184 ctx->Pixel.ConvolutionFilterScale[0][1],
185 ctx->Pixel.ConvolutionFilterScale[0][2],
186 ctx->Pixel.ConvolutionFilterScale[0][3],
187 ctx->Pixel.ConvolutionFilterBias[0][0],
188 ctx->Pixel.ConvolutionFilterBias[0][1],
189 ctx->Pixel.ConvolutionFilterBias[0][2],
190 ctx->Pixel.ConvolutionFilterBias[0][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000191
Brian Paulb5012e12000-11-10 18:31:04 +0000192 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000193}
194
195
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000196void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000197_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
198{
Brian Pauld0570642002-03-19 15:22:50 +0000199 GLint baseFormat;
Brian Paulb3050282003-12-04 03:19:46 +0000200 GLint i;
Brian Paul147b0832000-08-23 14:31:25 +0000201 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000202 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000203
204 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000205 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000206 return;
207 }
208
209 baseFormat = base_filter_format(internalFormat);
210 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000211 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000212 return;
213 }
214
215 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000216 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000217 return;
218 }
219 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000220 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000221 return;
222 }
223
Brian Paulf959f6e2004-04-22 00:27:31 +0000224 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000225 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000226 return;
227 }
228 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000229 format == GL_STENCIL_INDEX ||
230 format == GL_DEPTH_COMPONENT ||
231 format == GL_INTENSITY ||
232 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000233 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000234 return;
235 }
236
Brian Paulb3050282003-12-04 03:19:46 +0000237 /* this should have been caught earlier */
238 assert(_mesa_components_in_format(format));
Brian Paul147b0832000-08-23 14:31:25 +0000239
240 ctx->Convolution2D.Format = format;
241 ctx->Convolution2D.InternalFormat = internalFormat;
242 ctx->Convolution2D.Width = width;
243 ctx->Convolution2D.Height = height;
244
Brian Paulbd3b40a2004-10-31 17:36:23 +0000245 if (ctx->Unpack.BufferObj->Name) {
246 /* unpack filter from PBO */
247 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000248 if (!_mesa_validate_pbo_access(2, &ctx->Unpack, width, height, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000249 format, type, image)) {
250 _mesa_error(ctx, GL_INVALID_OPERATION,
251 "glConvolutionFilter2D(invalid PBO access)");
252 return;
253 }
254 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
255 GL_READ_ONLY_ARB,
256 ctx->Unpack.BufferObj);
257 if (!buf) {
258 /* buffer is already mapped - that's an error */
259 _mesa_error(ctx, GL_INVALID_OPERATION,
260 "glConvolutionFilter2D(PBO is mapped)");
261 return;
262 }
263 image = ADD_POINTERS(buf, image);
264 }
265 else if (!image) {
266 return;
267 }
268
Brian Paul147b0832000-08-23 14:31:25 +0000269 /* Unpack filter image. We always store filters in RGBA format. */
270 for (i = 0; i < height; i++) {
Brian Paul60909382004-11-10 15:46:52 +0000271 const GLvoid *src = _mesa_image_address2d(&ctx->Unpack, image, width,
272 height, format, type, i, 0);
Brian Paul147b0832000-08-23 14:31:25 +0000273 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000274 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
Brian Paul147b0832000-08-23 14:31:25 +0000275 format, type, src, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000276 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000277 }
278
Brian Paulbd3b40a2004-10-31 17:36:23 +0000279 if (ctx->Unpack.BufferObj->Name) {
280 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
281 ctx->Unpack.BufferObj);
282 }
283
Brian Paul450e9172004-10-31 18:40:55 +0000284 _mesa_scale_and_bias_rgba(width * height,
285 (GLfloat (*)[4]) ctx->Convolution2D.Filter,
286 ctx->Pixel.ConvolutionFilterScale[1][0],
287 ctx->Pixel.ConvolutionFilterScale[1][1],
288 ctx->Pixel.ConvolutionFilterScale[1][2],
289 ctx->Pixel.ConvolutionFilterScale[1][3],
290 ctx->Pixel.ConvolutionFilterBias[1][0],
291 ctx->Pixel.ConvolutionFilterBias[1][1],
292 ctx->Pixel.ConvolutionFilterBias[1][2],
293 ctx->Pixel.ConvolutionFilterBias[1][3]);
Keith Whitwella96308c2000-10-30 13:31:59 +0000294
Brian Paulb5012e12000-11-10 18:31:04 +0000295 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000296}
297
298
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000299void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000300_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
301{
302 GET_CURRENT_CONTEXT(ctx);
303 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000304 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000305
306 switch (target) {
307 case GL_CONVOLUTION_1D:
308 c = 0;
309 break;
310 case GL_CONVOLUTION_2D:
311 c = 1;
312 break;
313 case GL_SEPARABLE_2D:
314 c = 2;
315 break;
316 default:
Brian Paul08836342001-03-03 20:33:27 +0000317 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000318 return;
319 }
320
321 switch (pname) {
322 case GL_CONVOLUTION_BORDER_MODE:
323 if (param == (GLfloat) GL_REDUCE ||
324 param == (GLfloat) GL_CONSTANT_BORDER ||
325 param == (GLfloat) GL_REPLICATE_BORDER) {
326 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
327 }
328 else {
Brian Paul08836342001-03-03 20:33:27 +0000329 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000330 return;
331 }
332 break;
333 default:
Brian Paul08836342001-03-03 20:33:27 +0000334 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000335 return;
336 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000337
338 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000339}
340
341
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000342void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000343_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
344{
345 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000346 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000347 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000348
349 switch (target) {
350 case GL_CONVOLUTION_1D:
351 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000352 break;
353 case GL_CONVOLUTION_2D:
354 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000355 break;
356 case GL_SEPARABLE_2D:
357 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000358 break;
359 default:
Brian Paul08836342001-03-03 20:33:27 +0000360 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000361 return;
362 }
363
364 switch (pname) {
365 case GL_CONVOLUTION_BORDER_COLOR:
366 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
367 break;
368 case GL_CONVOLUTION_BORDER_MODE:
369 if (params[0] == (GLfloat) GL_REDUCE ||
370 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
371 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
372 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
373 }
374 else {
Brian Paul08836342001-03-03 20:33:27 +0000375 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000376 return;
377 }
378 break;
379 case GL_CONVOLUTION_FILTER_SCALE:
380 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
381 break;
382 case GL_CONVOLUTION_FILTER_BIAS:
383 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
384 break;
385 default:
Brian Paul08836342001-03-03 20:33:27 +0000386 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000387 return;
388 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000389
390 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000391}
392
393
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000394void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000395_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
396{
397 GET_CURRENT_CONTEXT(ctx);
398 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000399 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000400
401 switch (target) {
402 case GL_CONVOLUTION_1D:
403 c = 0;
404 break;
405 case GL_CONVOLUTION_2D:
406 c = 1;
407 break;
408 case GL_SEPARABLE_2D:
409 c = 2;
410 break;
411 default:
Brian Paul08836342001-03-03 20:33:27 +0000412 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000413 return;
414 }
415
416 switch (pname) {
417 case GL_CONVOLUTION_BORDER_MODE:
418 if (param == (GLint) GL_REDUCE ||
419 param == (GLint) GL_CONSTANT_BORDER ||
420 param == (GLint) GL_REPLICATE_BORDER) {
421 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
422 }
423 else {
Brian Paul08836342001-03-03 20:33:27 +0000424 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000425 return;
426 }
427 break;
428 default:
Brian Paul08836342001-03-03 20:33:27 +0000429 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000430 return;
431 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000432
433 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000434}
435
436
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000437void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000438_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
439{
440 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000441 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000442 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000443
444 switch (target) {
445 case GL_CONVOLUTION_1D:
446 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000447 break;
448 case GL_CONVOLUTION_2D:
449 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000450 break;
451 case GL_SEPARABLE_2D:
452 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000453 break;
454 default:
Brian Paul08836342001-03-03 20:33:27 +0000455 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000456 return;
457 }
458
459 switch (pname) {
460 case GL_CONVOLUTION_BORDER_COLOR:
461 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
462 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
463 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
464 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
465 break;
466 case GL_CONVOLUTION_BORDER_MODE:
467 if (params[0] == (GLint) GL_REDUCE ||
468 params[0] == (GLint) GL_CONSTANT_BORDER ||
469 params[0] == (GLint) GL_REPLICATE_BORDER) {
470 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
471 }
472 else {
Brian Paul08836342001-03-03 20:33:27 +0000473 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000474 return;
475 }
476 break;
477 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000478 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
479 /* need cast to prevent compiler warnings */
480 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
481 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
482 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
483 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000484 break;
485 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000486 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
487 /* need cast to prevent compiler warnings */
488 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
489 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
490 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
491 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000492 break;
493 default:
Brian Paul08836342001-03-03 20:33:27 +0000494 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000495 return;
496 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000497
498 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000499}
500
501
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000502void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000503_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
504{
Brian Pauld0570642002-03-19 15:22:50 +0000505 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000506 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000507 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000508
509 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000510 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000511 return;
512 }
513
514 baseFormat = base_filter_format(internalFormat);
515 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000516 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000517 return;
518 }
519
520 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000521 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000522 return;
523 }
524
Keith Whitwell70989242001-03-19 02:25:35 +0000525 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
526 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000527}
528
529
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000530void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000531_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
532{
Brian Pauld0570642002-03-19 15:22:50 +0000533 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000534 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000535 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000536
537 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000538 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000539 return;
540 }
541
542 baseFormat = base_filter_format(internalFormat);
543 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000544 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000545 return;
546 }
547
548 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000549 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000550 return;
551 }
552 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000553 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000554 return;
555 }
556
Keith Whitwell70989242001-03-19 02:25:35 +0000557 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
558 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000559}
560
561
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000562void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000563_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
564{
Brian Paulf75d6972000-09-05 20:28:56 +0000565 const struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000566 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000567 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000568 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000569
Brian Paul0c000ec2000-11-21 23:26:13 +0000570 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000571 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000572 }
573
Brian Paulf959f6e2004-04-22 00:27:31 +0000574 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000575 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000576 return;
577 }
578
579 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000580 format == GL_STENCIL_INDEX ||
581 format == GL_DEPTH_COMPONENT ||
582 format == GL_INTENSITY ||
583 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000584 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000585 return;
586 }
587
Brian Paulf75d6972000-09-05 20:28:56 +0000588 switch (target) {
589 case GL_CONVOLUTION_1D:
590 filter = &(ctx->Convolution1D);
591 break;
592 case GL_CONVOLUTION_2D:
593 filter = &(ctx->Convolution2D);
594 break;
595 default:
Brian Paul08836342001-03-03 20:33:27 +0000596 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000597 return;
598 }
599
Brian Paulbd3b40a2004-10-31 17:36:23 +0000600 if (ctx->Pack.BufferObj->Name) {
601 /* Pack the filter into a PBO */
602 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000603 if (!_mesa_validate_pbo_access(2, &ctx->Pack,
604 filter->Width, filter->Height,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000605 1, format, type, image)) {
606 _mesa_error(ctx, GL_INVALID_OPERATION,
607 "glGetConvolutionFilter(invalid PBO access)");
608 return;
609 }
610 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
611 GL_WRITE_ONLY_ARB,
612 ctx->Pack.BufferObj);
613 if (!buf) {
614 /* buffer is already mapped - that's an error */
615 _mesa_error(ctx, GL_INVALID_OPERATION,
616 "glGetConvolutionFilter(PBO is mapped)");
617 return;
618 }
619 image = ADD_POINTERS(image, buf);
620 }
621
Brian Paulf75d6972000-09-05 20:28:56 +0000622 for (row = 0; row < filter->Height; row++) {
Brian Paul60909382004-11-10 15:46:52 +0000623 GLvoid *dst = _mesa_image_address2d(&ctx->Pack, image, filter->Width,
624 filter->Height, format, type,
625 row, 0);
Brian Paulf75d6972000-09-05 20:28:56 +0000626 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000627 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paulf75d6972000-09-05 20:28:56 +0000628 (const GLfloat (*)[4]) src,
629 format, type, dst, &ctx->Pack, 0);
630 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000631
632 if (ctx->Pack.BufferObj->Name) {
633 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
634 ctx->Pack.BufferObj);
635 }
Brian Paul147b0832000-08-23 14:31:25 +0000636}
637
638
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000639void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000640_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
641{
642 GET_CURRENT_CONTEXT(ctx);
643 const struct gl_convolution_attrib *conv;
644 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000645 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000646
647 switch (target) {
648 case GL_CONVOLUTION_1D:
649 c = 0;
650 conv = &ctx->Convolution1D;
651 break;
652 case GL_CONVOLUTION_2D:
653 c = 1;
654 conv = &ctx->Convolution2D;
655 break;
656 case GL_SEPARABLE_2D:
657 c = 2;
658 conv = &ctx->Separable2D;
659 break;
660 default:
Brian Paul08836342001-03-03 20:33:27 +0000661 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000662 return;
663 }
664
665 switch (pname) {
666 case GL_CONVOLUTION_BORDER_COLOR:
667 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
668 break;
669 case GL_CONVOLUTION_BORDER_MODE:
670 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
671 break;
672 case GL_CONVOLUTION_FILTER_SCALE:
673 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
674 break;
675 case GL_CONVOLUTION_FILTER_BIAS:
676 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
677 break;
678 case GL_CONVOLUTION_FORMAT:
679 *params = (GLfloat) conv->Format;
680 break;
681 case GL_CONVOLUTION_WIDTH:
682 *params = (GLfloat) conv->Width;
683 break;
684 case GL_CONVOLUTION_HEIGHT:
685 *params = (GLfloat) conv->Height;
686 break;
687 case GL_MAX_CONVOLUTION_WIDTH:
688 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
689 break;
690 case GL_MAX_CONVOLUTION_HEIGHT:
691 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
692 break;
693 default:
Brian Paul08836342001-03-03 20:33:27 +0000694 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000695 return;
696 }
697}
698
699
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000700void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000701_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
702{
703 GET_CURRENT_CONTEXT(ctx);
704 const struct gl_convolution_attrib *conv;
705 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000706 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000707
708 switch (target) {
709 case GL_CONVOLUTION_1D:
710 c = 0;
711 conv = &ctx->Convolution1D;
712 break;
713 case GL_CONVOLUTION_2D:
714 c = 1;
715 conv = &ctx->Convolution2D;
716 break;
717 case GL_SEPARABLE_2D:
718 c = 2;
719 conv = &ctx->Separable2D;
720 break;
721 default:
Brian Paul08836342001-03-03 20:33:27 +0000722 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000723 return;
724 }
725
726 switch (pname) {
727 case GL_CONVOLUTION_BORDER_COLOR:
728 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
729 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
730 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
731 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
732 break;
733 case GL_CONVOLUTION_BORDER_MODE:
734 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
735 break;
736 case GL_CONVOLUTION_FILTER_SCALE:
737 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
738 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
739 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
740 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
741 break;
742 case GL_CONVOLUTION_FILTER_BIAS:
743 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
744 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
745 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
746 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
747 break;
748 case GL_CONVOLUTION_FORMAT:
749 *params = (GLint) conv->Format;
750 break;
751 case GL_CONVOLUTION_WIDTH:
752 *params = (GLint) conv->Width;
753 break;
754 case GL_CONVOLUTION_HEIGHT:
755 *params = (GLint) conv->Height;
756 break;
757 case GL_MAX_CONVOLUTION_WIDTH:
758 *params = (GLint) ctx->Const.MaxConvolutionWidth;
759 break;
760 case GL_MAX_CONVOLUTION_HEIGHT:
761 *params = (GLint) ctx->Const.MaxConvolutionHeight;
762 break;
763 default:
Brian Paul08836342001-03-03 20:33:27 +0000764 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000765 return;
766 }
767}
768
769
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000770void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000771_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
772{
Brian Paulf75d6972000-09-05 20:28:56 +0000773 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
774 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000775 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000776 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000777
Brian Paul0c000ec2000-11-21 23:26:13 +0000778 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000779 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000780 }
781
Brian Paul147b0832000-08-23 14:31:25 +0000782 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000783 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000784 return;
785 }
786
Brian Paulf959f6e2004-04-22 00:27:31 +0000787 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000788 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000789 return;
790 }
791
792 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000793 format == GL_STENCIL_INDEX ||
794 format == GL_DEPTH_COMPONENT ||
795 format == GL_INTENSITY ||
796 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000797 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000798 return;
799 }
800
Brian Paulf75d6972000-09-05 20:28:56 +0000801 filter = &ctx->Separable2D;
802
Brian Paulbd3b40a2004-10-31 17:36:23 +0000803 if (ctx->Pack.BufferObj->Name) {
804 /* Pack filter into PBO */
805 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000806 if (!_mesa_validate_pbo_access(1, &ctx->Pack, filter->Width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000807 format, type, row)) {
808 _mesa_error(ctx, GL_INVALID_OPERATION,
809 "glGetSeparableFilter(invalid PBO access, width)");
810 return;
811 }
Brian Paul60909382004-11-10 15:46:52 +0000812 if (!_mesa_validate_pbo_access(1, &ctx->Pack, filter->Height, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000813 format, type, column)) {
814 _mesa_error(ctx, GL_INVALID_OPERATION,
815 "glGetSeparableFilter(invalid PBO access, height)");
816 return;
817 }
818 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
819 GL_WRITE_ONLY_ARB,
820 ctx->Pack.BufferObj);
821 if (!buf) {
822 /* buffer is already mapped - that's an error */
823 _mesa_error(ctx, GL_INVALID_OPERATION,
824 "glGetSeparableFilter(PBO is mapped)");
825 return;
826 }
827 row = ADD_POINTERS(buf, row);
828 column = ADD_POINTERS(buf, column);
829 }
830
Brian Paulf75d6972000-09-05 20:28:56 +0000831 /* Row filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000832 if (row) {
Brian Paul60909382004-11-10 15:46:52 +0000833 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, row, filter->Width,
834 format, type, 0);
Brian Paul8cfd08b2004-02-28 20:35:57 +0000835 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paulf75d6972000-09-05 20:28:56 +0000836 (const GLfloat (*)[4]) filter->Filter,
837 format, type, dst, &ctx->Pack, 0);
838 }
839
840 /* Column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000841 if (column) {
Brian Paul60909382004-11-10 15:46:52 +0000842 GLvoid *dst = _mesa_image_address1d(&ctx->Pack, column, filter->Height,
843 format, type, 0);
Brian Paulf75d6972000-09-05 20:28:56 +0000844 const GLfloat *src = filter->Filter + colStart;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000845 _mesa_pack_rgba_span_float(ctx, filter->Height,
Brian Paulf75d6972000-09-05 20:28:56 +0000846 (const GLfloat (*)[4]) src,
847 format, type, dst, &ctx->Pack, 0);
848 }
849
850 (void) span; /* unused at this time */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000851
852 if (ctx->Pack.BufferObj->Name) {
853 /* Pack filter into PBO */
854 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
855 ctx->Unpack.BufferObj);
856 }
Brian Paul147b0832000-08-23 14:31:25 +0000857}
858
859
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000860void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000861_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
862{
863 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000864 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000865 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000866 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000867
868 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000869 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000870 return;
871 }
872
873 baseFormat = base_filter_format(internalFormat);
874 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000875 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000876 return;
877 }
878
879 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000880 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000881 return;
882 }
883 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000884 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000885 return;
886 }
887
Brian Paulf959f6e2004-04-22 00:27:31 +0000888 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000889 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000890 return;
891 }
892
893 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000894 format == GL_STENCIL_INDEX ||
895 format == GL_DEPTH_COMPONENT ||
896 format == GL_INTENSITY ||
897 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000898 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000899 return;
900 }
901
902 ctx->Separable2D.Format = format;
903 ctx->Separable2D.InternalFormat = internalFormat;
904 ctx->Separable2D.Width = width;
905 ctx->Separable2D.Height = height;
906
Brian Paulbd3b40a2004-10-31 17:36:23 +0000907 if (ctx->Unpack.BufferObj->Name) {
908 /* unpack filter from PBO */
909 GLubyte *buf;
Brian Paul60909382004-11-10 15:46:52 +0000910 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, width, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000911 format, type, row)) {
912 _mesa_error(ctx, GL_INVALID_OPERATION,
913 "glSeparableFilter2D(invalid PBO access, width)");
914 return;
915 }
Brian Paul60909382004-11-10 15:46:52 +0000916 if (!_mesa_validate_pbo_access(1, &ctx->Unpack, height, 1, 1,
Brian Paulbd3b40a2004-10-31 17:36:23 +0000917 format, type, column)) {
918 _mesa_error(ctx, GL_INVALID_OPERATION,
919 "glSeparableFilter2D(invalid PBO access, height)");
920 return;
921 }
922 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
923 GL_READ_ONLY_ARB,
924 ctx->Unpack.BufferObj);
925 if (!buf) {
926 /* buffer is already mapped - that's an error */
927 _mesa_error(ctx, GL_INVALID_OPERATION,
928 "glSeparableFilter2D(PBO is mapped)");
929 return;
930 }
931 row = ADD_POINTERS(buf, row);
932 column = ADD_POINTERS(buf, column);
933 }
Brian Paul147b0832000-08-23 14:31:25 +0000934
Brian Paulbd3b40a2004-10-31 17:36:23 +0000935 /* unpack row filter */
936 if (row) {
937 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
938 ctx->Separable2D.Filter,
939 format, type, row, &ctx->Unpack,
940 0); /* transferOps */
941
Brian Paul450e9172004-10-31 18:40:55 +0000942 _mesa_scale_and_bias_rgba(width,
943 (GLfloat (*)[4]) ctx->Separable2D.Filter,
944 ctx->Pixel.ConvolutionFilterScale[2][0],
945 ctx->Pixel.ConvolutionFilterScale[2][1],
946 ctx->Pixel.ConvolutionFilterScale[2][2],
947 ctx->Pixel.ConvolutionFilterScale[2][3],
948 ctx->Pixel.ConvolutionFilterBias[2][0],
949 ctx->Pixel.ConvolutionFilterBias[2][1],
950 ctx->Pixel.ConvolutionFilterBias[2][2],
951 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paul147b0832000-08-23 14:31:25 +0000952 }
953
954 /* unpack column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000955 if (column) {
Brian Pauleffb7202004-10-31 18:41:38 +0000956 _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
957 &ctx->Separable2D.Filter[colStart],
958 format, type, column, &ctx->Unpack,
959 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000960
Brian Paul450e9172004-10-31 18:40:55 +0000961 _mesa_scale_and_bias_rgba(height,
962 (GLfloat (*)[4]) (ctx->Separable2D.Filter + colStart),
963 ctx->Pixel.ConvolutionFilterScale[2][0],
964 ctx->Pixel.ConvolutionFilterScale[2][1],
965 ctx->Pixel.ConvolutionFilterScale[2][2],
966 ctx->Pixel.ConvolutionFilterScale[2][3],
967 ctx->Pixel.ConvolutionFilterBias[2][0],
968 ctx->Pixel.ConvolutionFilterBias[2][1],
969 ctx->Pixel.ConvolutionFilterBias[2][2],
970 ctx->Pixel.ConvolutionFilterBias[2][3]);
Brian Paulbd3b40a2004-10-31 17:36:23 +0000971 }
972
973 if (ctx->Unpack.BufferObj->Name) {
974 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
975 ctx->Unpack.BufferObj);
Brian Paul147b0832000-08-23 14:31:25 +0000976 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +0000977
Brian Paulb5012e12000-11-10 18:31:04 +0000978 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000979}
980
981
982/**********************************************************************/
983/*** image convolution functions ***/
984/**********************************************************************/
985
Brian Pauld4b799b2000-08-21 14:24:30 +0000986static void
987convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
988 GLint filterWidth, const GLfloat filter[][4],
989 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000990{
Brian Paul7e708742000-08-22 18:54:25 +0000991 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000992 GLint i, n;
993
Brian Paul7e708742000-08-22 18:54:25 +0000994 if (filterWidth >= 1)
995 dstWidth = srcWidth - (filterWidth - 1);
996 else
997 dstWidth = srcWidth;
998
Brian Paulcc8e37f2000-07-12 13:00:09 +0000999 if (dstWidth <= 0)
1000 return; /* null result */
1001
1002 for (i = 0; i < dstWidth; i++) {
1003 GLfloat sumR = 0.0;
1004 GLfloat sumG = 0.0;
1005 GLfloat sumB = 0.0;
1006 GLfloat sumA = 0.0;
1007 for (n = 0; n < filterWidth; n++) {
1008 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
1009 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
1010 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
1011 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
1012 }
1013 dest[i][RCOMP] = sumR;
1014 dest[i][GCOMP] = sumG;
1015 dest[i][BCOMP] = sumB;
1016 dest[i][ACOMP] = sumA;
1017 }
1018}
1019
1020
Brian Pauld4b799b2000-08-21 14:24:30 +00001021static void
1022convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
1023 GLint filterWidth, const GLfloat filter[][4],
1024 GLfloat dest[][4],
1025 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001026{
1027 const GLint halfFilterWidth = filterWidth / 2;
1028 GLint i, n;
1029
1030 for (i = 0; i < srcWidth; i++) {
1031 GLfloat sumR = 0.0;
1032 GLfloat sumG = 0.0;
1033 GLfloat sumB = 0.0;
1034 GLfloat sumA = 0.0;
1035 for (n = 0; n < filterWidth; n++) {
1036 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
1037 sumR += borderColor[RCOMP] * filter[n][RCOMP];
1038 sumG += borderColor[GCOMP] * filter[n][GCOMP];
1039 sumB += borderColor[BCOMP] * filter[n][BCOMP];
1040 sumA += borderColor[ACOMP] * filter[n][ACOMP];
1041 }
1042 else {
1043 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1044 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1045 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1046 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1047 }
1048 }
1049 dest[i][RCOMP] = sumR;
1050 dest[i][GCOMP] = sumG;
1051 dest[i][BCOMP] = sumB;
1052 dest[i][ACOMP] = sumA;
1053 }
1054}
1055
1056
Brian Pauld4b799b2000-08-21 14:24:30 +00001057static void
1058convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
1059 GLint filterWidth, const GLfloat filter[][4],
1060 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001061{
1062 const GLint halfFilterWidth = filterWidth / 2;
1063 GLint i, n;
1064
1065 for (i = 0; i < srcWidth; i++) {
1066 GLfloat sumR = 0.0;
1067 GLfloat sumG = 0.0;
1068 GLfloat sumB = 0.0;
1069 GLfloat sumA = 0.0;
1070 for (n = 0; n < filterWidth; n++) {
1071 if (i + n < halfFilterWidth) {
1072 sumR += src[0][RCOMP] * filter[n][RCOMP];
1073 sumG += src[0][GCOMP] * filter[n][GCOMP];
1074 sumB += src[0][BCOMP] * filter[n][BCOMP];
1075 sumA += src[0][ACOMP] * filter[n][ACOMP];
1076 }
1077 else if (i + n - halfFilterWidth >= srcWidth) {
1078 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
1079 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
1080 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
1081 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
1082 }
1083 else {
1084 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1085 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1086 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1087 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1088 }
1089 }
1090 dest[i][RCOMP] = sumR;
1091 dest[i][GCOMP] = sumG;
1092 dest[i][BCOMP] = sumB;
1093 dest[i][ACOMP] = sumA;
1094 }
1095}
1096
1097
Brian Pauld4b799b2000-08-21 14:24:30 +00001098static void
1099convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1100 const GLfloat src[][4],
1101 GLint filterWidth, GLint filterHeight,
1102 const GLfloat filter[][4],
1103 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001104{
Brian Paul7e708742000-08-22 18:54:25 +00001105 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001106 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001107
Brian Paul7e708742000-08-22 18:54:25 +00001108 if (filterWidth >= 1)
1109 dstWidth = srcWidth - (filterWidth - 1);
1110 else
1111 dstWidth = srcWidth;
1112
1113 if (filterHeight >= 1)
1114 dstHeight = srcHeight - (filterHeight - 1);
1115 else
1116 dstHeight = srcHeight;
1117
Brian Pauld4b799b2000-08-21 14:24:30 +00001118 if (dstWidth <= 0 || dstHeight <= 0)
1119 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001120
Brian Pauld4b799b2000-08-21 14:24:30 +00001121 for (j = 0; j < dstHeight; j++) {
1122 for (i = 0; i < dstWidth; i++) {
1123 GLfloat sumR = 0.0;
1124 GLfloat sumG = 0.0;
1125 GLfloat sumB = 0.0;
1126 GLfloat sumA = 0.0;
1127 for (m = 0; m < filterHeight; m++) {
1128 for (n = 0; n < filterWidth; n++) {
1129 const GLint k = (j + m) * srcWidth + i + n;
1130 const GLint f = m * filterWidth + n;
1131 sumR += src[k][RCOMP] * filter[f][RCOMP];
1132 sumG += src[k][GCOMP] * filter[f][GCOMP];
1133 sumB += src[k][BCOMP] * filter[f][BCOMP];
1134 sumA += src[k][ACOMP] * filter[f][ACOMP];
1135 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001136 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001137 dest[j * dstWidth + i][RCOMP] = sumR;
1138 dest[j * dstWidth + i][GCOMP] = sumG;
1139 dest[j * dstWidth + i][BCOMP] = sumB;
1140 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001141 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001142 }
1143}
1144
1145
Brian Pauld4b799b2000-08-21 14:24:30 +00001146static void
1147convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1148 const GLfloat src[][4],
1149 GLint filterWidth, GLint filterHeight,
1150 const GLfloat filter[][4],
1151 GLfloat dest[][4],
1152 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001153{
1154 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001155 const GLint halfFilterHeight = filterHeight / 2;
1156 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001157
Brian Pauld4b799b2000-08-21 14:24:30 +00001158 for (j = 0; j < srcHeight; j++) {
1159 for (i = 0; i < srcWidth; i++) {
1160 GLfloat sumR = 0.0;
1161 GLfloat sumG = 0.0;
1162 GLfloat sumB = 0.0;
1163 GLfloat sumA = 0.0;
1164 for (m = 0; m < filterHeight; m++) {
1165 for (n = 0; n < filterWidth; n++) {
1166 const GLint f = m * filterWidth + n;
1167 const GLint is = i + n - halfFilterWidth;
1168 const GLint js = j + m - halfFilterHeight;
1169 if (is < 0 || is >= srcWidth ||
1170 js < 0 || js >= srcHeight) {
1171 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1172 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1173 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1174 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1175 }
1176 else {
1177 const GLint k = js * srcWidth + is;
1178 sumR += src[k][RCOMP] * filter[f][RCOMP];
1179 sumG += src[k][GCOMP] * filter[f][GCOMP];
1180 sumB += src[k][BCOMP] * filter[f][BCOMP];
1181 sumA += src[k][ACOMP] * filter[f][ACOMP];
1182 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001183 }
1184 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001185 dest[j * srcWidth + i][RCOMP] = sumR;
1186 dest[j * srcWidth + i][GCOMP] = sumG;
1187 dest[j * srcWidth + i][BCOMP] = sumB;
1188 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001189 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001190 }
1191}
1192
1193
Brian Pauld4b799b2000-08-21 14:24:30 +00001194static void
1195convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1196 const GLfloat src[][4],
1197 GLint filterWidth, GLint filterHeight,
1198 const GLfloat filter[][4],
1199 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001200{
1201 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001202 const GLint halfFilterHeight = filterHeight / 2;
1203 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001204
Brian Pauld4b799b2000-08-21 14:24:30 +00001205 for (j = 0; j < srcHeight; j++) {
1206 for (i = 0; i < srcWidth; i++) {
1207 GLfloat sumR = 0.0;
1208 GLfloat sumG = 0.0;
1209 GLfloat sumB = 0.0;
1210 GLfloat sumA = 0.0;
1211 for (m = 0; m < filterHeight; m++) {
1212 for (n = 0; n < filterWidth; n++) {
1213 const GLint f = m * filterWidth + n;
1214 GLint is = i + n - halfFilterWidth;
1215 GLint js = j + m - halfFilterHeight;
1216 GLint k;
1217 if (is < 0)
1218 is = 0;
1219 else if (is >= srcWidth)
1220 is = srcWidth - 1;
1221 if (js < 0)
1222 js = 0;
1223 else if (js >= srcHeight)
1224 js = srcHeight - 1;
1225 k = js * srcWidth + is;
1226 sumR += src[k][RCOMP] * filter[f][RCOMP];
1227 sumG += src[k][GCOMP] * filter[f][GCOMP];
1228 sumB += src[k][BCOMP] * filter[f][BCOMP];
1229 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001230 }
1231 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001232 dest[j * srcWidth + i][RCOMP] = sumR;
1233 dest[j * srcWidth + i][GCOMP] = sumG;
1234 dest[j * srcWidth + i][BCOMP] = sumB;
1235 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001236 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001237 }
1238}
1239
1240
Brian Pauld4b799b2000-08-21 14:24:30 +00001241static void
1242convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1243 const GLfloat src[][4],
1244 GLint filterWidth, GLint filterHeight,
1245 const GLfloat rowFilt[][4],
1246 const GLfloat colFilt[][4],
1247 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001248{
Brian Paul7e708742000-08-22 18:54:25 +00001249 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001250 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001251
1252 if (filterWidth >= 1)
1253 dstWidth = srcWidth - (filterWidth - 1);
1254 else
1255 dstWidth = srcWidth;
1256
1257 if (filterHeight >= 1)
1258 dstHeight = srcHeight - (filterHeight - 1);
1259 else
1260 dstHeight = srcHeight;
1261
1262 if (dstWidth <= 0 || dstHeight <= 0)
1263 return;
1264
1265 for (j = 0; j < dstHeight; j++) {
1266 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001267 GLfloat sumR = 0.0;
1268 GLfloat sumG = 0.0;
1269 GLfloat sumB = 0.0;
1270 GLfloat sumA = 0.0;
1271 for (m = 0; m < filterHeight; m++) {
1272 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001273 GLint k = (j + m) * srcWidth + i + n;
1274 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1275 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1276 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1277 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001278 }
1279 }
Brian Paul7e708742000-08-22 18:54:25 +00001280 dest[j * dstWidth + i][RCOMP] = sumR;
1281 dest[j * dstWidth + i][GCOMP] = sumG;
1282 dest[j * dstWidth + i][BCOMP] = sumB;
1283 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001284 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001285 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001286}
1287
1288
Brian Pauld4b799b2000-08-21 14:24:30 +00001289static void
1290convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1291 const GLfloat src[][4],
1292 GLint filterWidth, GLint filterHeight,
1293 const GLfloat rowFilt[][4],
1294 const GLfloat colFilt[][4],
1295 GLfloat dest[][4],
1296 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001297{
1298 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001299 const GLint halfFilterHeight = filterHeight / 2;
1300 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001301
Brian Pauld4b799b2000-08-21 14:24:30 +00001302 for (j = 0; j < srcHeight; j++) {
1303 for (i = 0; i < srcWidth; i++) {
1304 GLfloat sumR = 0.0;
1305 GLfloat sumG = 0.0;
1306 GLfloat sumB = 0.0;
1307 GLfloat sumA = 0.0;
1308 for (m = 0; m < filterHeight; m++) {
1309 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001310 const GLint is = i + n - halfFilterWidth;
1311 const GLint js = j + m - halfFilterHeight;
1312 if (is < 0 || is >= srcWidth ||
1313 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001314 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1315 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1316 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1317 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1318 }
1319 else {
Brian Paul7e708742000-08-22 18:54:25 +00001320 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001321 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1322 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1323 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1324 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1325 }
Brian Paul7e708742000-08-22 18:54:25 +00001326
Brian Paulcc8e37f2000-07-12 13:00:09 +00001327 }
1328 }
Brian Paul7e708742000-08-22 18:54:25 +00001329 dest[j * srcWidth + i][RCOMP] = sumR;
1330 dest[j * srcWidth + i][GCOMP] = sumG;
1331 dest[j * srcWidth + i][BCOMP] = sumB;
1332 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001333 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001334 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001335}
1336
1337
1338static void
1339convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1340 const GLfloat src[][4],
1341 GLint filterWidth, GLint filterHeight,
1342 const GLfloat rowFilt[][4],
1343 const GLfloat colFilt[][4],
1344 GLfloat dest[][4])
1345{
1346 const GLint halfFilterWidth = filterWidth / 2;
1347 const GLint halfFilterHeight = filterHeight / 2;
1348 GLint i, j, n, m;
1349
1350 for (j = 0; j < srcHeight; j++) {
1351 for (i = 0; i < srcWidth; i++) {
1352 GLfloat sumR = 0.0;
1353 GLfloat sumG = 0.0;
1354 GLfloat sumB = 0.0;
1355 GLfloat sumA = 0.0;
1356 for (m = 0; m < filterHeight; m++) {
1357 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001358 GLint is = i + n - halfFilterWidth;
1359 GLint js = j + m - halfFilterHeight;
1360 GLint k;
1361 if (is < 0)
1362 is = 0;
1363 else if (is >= srcWidth)
1364 is = srcWidth - 1;
1365 if (js < 0)
1366 js = 0;
1367 else if (js >= srcHeight)
1368 js = srcHeight - 1;
1369 k = js * srcWidth + is;
1370 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1371 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1372 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1373 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001374 }
1375 }
Brian Paul7e708742000-08-22 18:54:25 +00001376 dest[j * srcWidth + i][RCOMP] = sumR;
1377 dest[j * srcWidth + i][GCOMP] = sumG;
1378 dest[j * srcWidth + i][BCOMP] = sumB;
1379 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001380 }
1381 }
1382}
1383
1384
1385
1386void
1387_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1388 const GLfloat *srcImage, GLfloat *dstImage)
1389{
1390 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1391 case GL_REDUCE:
1392 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1393 ctx->Convolution1D.Width,
1394 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1395 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001396 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001397 break;
1398 case GL_CONSTANT_BORDER:
1399 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1400 ctx->Convolution1D.Width,
1401 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1402 (GLfloat (*)[4]) dstImage,
1403 ctx->Pixel.ConvolutionBorderColor[0]);
1404 break;
1405 case GL_REPLICATE_BORDER:
1406 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1407 ctx->Convolution1D.Width,
1408 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1409 (GLfloat (*)[4]) dstImage);
1410 break;
1411 default:
1412 ;
1413 }
1414}
1415
1416
1417void
1418_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1419 const GLfloat *srcImage, GLfloat *dstImage)
1420{
1421 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1422 case GL_REDUCE:
1423 convolve_2d_reduce(*width, *height,
1424 (const GLfloat (*)[4]) srcImage,
1425 ctx->Convolution2D.Width,
1426 ctx->Convolution2D.Height,
1427 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1428 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001429 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1430 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001431 break;
1432 case GL_CONSTANT_BORDER:
1433 convolve_2d_constant(*width, *height,
1434 (const GLfloat (*)[4]) srcImage,
1435 ctx->Convolution2D.Width,
1436 ctx->Convolution2D.Height,
1437 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1438 (GLfloat (*)[4]) dstImage,
1439 ctx->Pixel.ConvolutionBorderColor[1]);
1440 break;
1441 case GL_REPLICATE_BORDER:
1442 convolve_2d_replicate(*width, *height,
1443 (const GLfloat (*)[4]) srcImage,
1444 ctx->Convolution2D.Width,
1445 ctx->Convolution2D.Height,
1446 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1447 (GLfloat (*)[4]) dstImage);
1448 break;
1449 default:
1450 ;
1451 }
1452}
1453
1454
1455void
1456_mesa_convolve_sep_image(const GLcontext *ctx,
1457 GLsizei *width, GLsizei *height,
1458 const GLfloat *srcImage, GLfloat *dstImage)
1459{
1460 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1461 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1462
1463 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1464 case GL_REDUCE:
1465 convolve_sep_reduce(*width, *height,
1466 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001467 ctx->Separable2D.Width,
1468 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001469 (const GLfloat (*)[4]) rowFilter,
1470 (const GLfloat (*)[4]) colFilter,
1471 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001472 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1473 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001474 break;
1475 case GL_CONSTANT_BORDER:
1476 convolve_sep_constant(*width, *height,
1477 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001478 ctx->Separable2D.Width,
1479 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001480 (const GLfloat (*)[4]) rowFilter,
1481 (const GLfloat (*)[4]) colFilter,
1482 (GLfloat (*)[4]) dstImage,
1483 ctx->Pixel.ConvolutionBorderColor[2]);
1484 break;
1485 case GL_REPLICATE_BORDER:
1486 convolve_sep_replicate(*width, *height,
1487 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001488 ctx->Separable2D.Width,
1489 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001490 (const GLfloat (*)[4]) rowFilter,
1491 (const GLfloat (*)[4]) colFilter,
1492 (GLfloat (*)[4]) dstImage);
1493 break;
1494 default:
1495 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001496 }
1497}
Brian Paul16461f72001-02-06 17:22:16 +00001498
1499
1500
1501/*
1502 * This function computes an image's size after convolution.
1503 * If the convolution border mode is GL_REDUCE, the post-convolution
1504 * image will be smaller than the original.
1505 */
1506void
1507_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1508 GLsizei *width, GLsizei *height)
1509{
1510 if (ctx->Pixel.Convolution1DEnabled
1511 && dimensions == 1
1512 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1513 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1514 }
1515 else if (ctx->Pixel.Convolution2DEnabled
1516 && dimensions > 1
1517 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1518 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1519 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1520 }
1521 else if (ctx->Pixel.Separable2DEnabled
1522 && dimensions > 1
1523 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1524 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1525 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1526 }
1527}