blob: afa550a4812eec22cd95ac30e1669712795e6557 [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"
Jon Taylorcdfba5d2000-11-23 02:50:56 +000041#include "state.h"
Brian Paulcc8e37f2000-07-12 13:00:09 +000042
43
Brian Paul147b0832000-08-23 14:31:25 +000044/*
45 * Given an internalFormat token passed to glConvolutionFilter
46 * or glSeparableFilter, return the corresponding base format.
47 * Return -1 if invalid token.
48 */
49static GLint
50base_filter_format( GLenum format )
51{
52 switch (format) {
53 case GL_ALPHA:
54 case GL_ALPHA4:
55 case GL_ALPHA8:
56 case GL_ALPHA12:
57 case GL_ALPHA16:
58 return GL_ALPHA;
59 case GL_LUMINANCE:
60 case GL_LUMINANCE4:
61 case GL_LUMINANCE8:
62 case GL_LUMINANCE12:
63 case GL_LUMINANCE16:
64 return GL_LUMINANCE;
65 case GL_LUMINANCE_ALPHA:
66 case GL_LUMINANCE4_ALPHA4:
67 case GL_LUMINANCE6_ALPHA2:
68 case GL_LUMINANCE8_ALPHA8:
69 case GL_LUMINANCE12_ALPHA4:
70 case GL_LUMINANCE12_ALPHA12:
71 case GL_LUMINANCE16_ALPHA16:
72 return GL_LUMINANCE_ALPHA;
73 case GL_INTENSITY:
74 case GL_INTENSITY4:
75 case GL_INTENSITY8:
76 case GL_INTENSITY12:
77 case GL_INTENSITY16:
78 return GL_INTENSITY;
79 case GL_RGB:
80 case GL_R3_G3_B2:
81 case GL_RGB4:
82 case GL_RGB5:
83 case GL_RGB8:
84 case GL_RGB10:
85 case GL_RGB12:
86 case GL_RGB16:
87 return GL_RGB;
88 case 4:
89 case GL_RGBA:
90 case GL_RGBA2:
91 case GL_RGBA4:
92 case GL_RGB5_A1:
93 case GL_RGBA8:
94 case GL_RGB10_A2:
95 case GL_RGBA12:
96 case GL_RGBA16:
97 return GL_RGBA;
98 default:
99 return -1; /* error */
100 }
101}
102
103
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000104void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000105_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
106{
Brian Pauld0570642002-03-19 15:22:50 +0000107 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000108 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000109 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000110
111 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000112 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000113 return;
114 }
115
116 baseFormat = base_filter_format(internalFormat);
117 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000118 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000119 return;
120 }
121
122 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000123 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000124 return;
125 }
126
Brian Paulf959f6e2004-04-22 00:27:31 +0000127 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000128 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000129 return;
130 }
131
132 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000133 format == GL_STENCIL_INDEX ||
134 format == GL_DEPTH_COMPONENT ||
135 format == GL_INTENSITY ||
136 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000137 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000138 return;
139 }
140
141 ctx->Convolution1D.Format = format;
142 ctx->Convolution1D.InternalFormat = internalFormat;
143 ctx->Convolution1D.Width = width;
144 ctx->Convolution1D.Height = 1;
145
Brian Paulbd3b40a2004-10-31 17:36:23 +0000146 if (ctx->Unpack.BufferObj->Name) {
147 /* unpack filter from PBO */
148 GLubyte *buf;
149 if (!_mesa_validate_pbo_access(&ctx->Unpack, width, 1, 1,
150 format, type, image)) {
151 _mesa_error(ctx, GL_INVALID_OPERATION,
152 "glConvolutionFilter1D(invalid PBO access)");
153 return;
154 }
155 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
156 GL_READ_ONLY_ARB,
157 ctx->Unpack.BufferObj);
158 if (!buf) {
159 /* buffer is already mapped - that's an error */
160 _mesa_error(ctx, GL_INVALID_OPERATION,
161 "glConvolutionFilter1D(PBO is mapped)");
162 return;
163 }
164 image = ADD_POINTERS(buf, image);
165 }
166 else if (!image) {
167 return;
168 }
169
Brian Paul8cfd08b2004-02-28 20:35:57 +0000170 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
Brian Paul147b0832000-08-23 14:31:25 +0000171 ctx->Convolution1D.Filter,
172 format, type, image, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000173 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000174
Brian Paulbd3b40a2004-10-31 17:36:23 +0000175 if (ctx->Unpack.BufferObj->Name) {
176 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
177 ctx->Unpack.BufferObj);
178 }
179
Brian Paul147b0832000-08-23 14:31:25 +0000180 /* apply scale and bias */
181 {
182 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
183 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
184 GLint i;
185 for (i = 0; i < width; i++) {
186 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
187 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
188 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
189 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
190 r = r * scale[0] + bias[0];
191 g = g * scale[1] + bias[1];
192 b = b * scale[2] + bias[2];
193 a = a * scale[3] + bias[3];
194 ctx->Convolution1D.Filter[i * 4 + 0] = r;
195 ctx->Convolution1D.Filter[i * 4 + 1] = g;
196 ctx->Convolution1D.Filter[i * 4 + 2] = b;
197 ctx->Convolution1D.Filter[i * 4 + 3] = a;
198 }
199 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000200
Brian Paulb5012e12000-11-10 18:31:04 +0000201 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000202}
203
204
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000205void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000206_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
207{
Brian Pauld0570642002-03-19 15:22:50 +0000208 GLint baseFormat;
Brian Paulb3050282003-12-04 03:19:46 +0000209 GLint i;
Brian Paul147b0832000-08-23 14:31:25 +0000210 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000211 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000212
213 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000214 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000215 return;
216 }
217
218 baseFormat = base_filter_format(internalFormat);
219 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000220 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000221 return;
222 }
223
224 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000225 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000226 return;
227 }
228 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000229 _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000230 return;
231 }
232
Brian Paulf959f6e2004-04-22 00:27:31 +0000233 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000234 _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000235 return;
236 }
237 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000238 format == GL_STENCIL_INDEX ||
239 format == GL_DEPTH_COMPONENT ||
240 format == GL_INTENSITY ||
241 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000242 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000243 return;
244 }
245
Brian Paulb3050282003-12-04 03:19:46 +0000246 /* this should have been caught earlier */
247 assert(_mesa_components_in_format(format));
Brian Paul147b0832000-08-23 14:31:25 +0000248
249 ctx->Convolution2D.Format = format;
250 ctx->Convolution2D.InternalFormat = internalFormat;
251 ctx->Convolution2D.Width = width;
252 ctx->Convolution2D.Height = height;
253
Brian Paulbd3b40a2004-10-31 17:36:23 +0000254 if (ctx->Unpack.BufferObj->Name) {
255 /* unpack filter from PBO */
256 GLubyte *buf;
257 if (!_mesa_validate_pbo_access(&ctx->Unpack, width, height, 1,
258 format, type, image)) {
259 _mesa_error(ctx, GL_INVALID_OPERATION,
260 "glConvolutionFilter2D(invalid PBO access)");
261 return;
262 }
263 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
264 GL_READ_ONLY_ARB,
265 ctx->Unpack.BufferObj);
266 if (!buf) {
267 /* buffer is already mapped - that's an error */
268 _mesa_error(ctx, GL_INVALID_OPERATION,
269 "glConvolutionFilter2D(PBO is mapped)");
270 return;
271 }
272 image = ADD_POINTERS(buf, image);
273 }
274 else if (!image) {
275 return;
276 }
277
Brian Paul147b0832000-08-23 14:31:25 +0000278 /* Unpack filter image. We always store filters in RGBA format. */
279 for (i = 0; i < height; i++) {
280 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
281 height, format, type, 0, i, 0);
282 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000283 _mesa_unpack_color_span_float(ctx, width, GL_RGBA, dst,
Brian Paul147b0832000-08-23 14:31:25 +0000284 format, type, src, &ctx->Unpack,
Brian Paul4923e192004-02-28 22:30:58 +0000285 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000286 }
287
Brian Paulbd3b40a2004-10-31 17:36:23 +0000288 if (ctx->Unpack.BufferObj->Name) {
289 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
290 ctx->Unpack.BufferObj);
291 }
292
Brian Paul147b0832000-08-23 14:31:25 +0000293 /* apply scale and bias */
294 {
295 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
296 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
Brian Paul8acb7e92001-05-09 22:24:22 +0000297 for (i = 0; i < width * height; i++) {
Brian Paul147b0832000-08-23 14:31:25 +0000298 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
299 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
300 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
301 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
302 r = r * scale[0] + bias[0];
303 g = g * scale[1] + bias[1];
304 b = b * scale[2] + bias[2];
305 a = a * scale[3] + bias[3];
306 ctx->Convolution2D.Filter[i * 4 + 0] = r;
307 ctx->Convolution2D.Filter[i * 4 + 1] = g;
308 ctx->Convolution2D.Filter[i * 4 + 2] = b;
309 ctx->Convolution2D.Filter[i * 4 + 3] = a;
310 }
311 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000312
Brian Paulb5012e12000-11-10 18:31:04 +0000313 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000314}
315
316
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000317void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000318_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
319{
320 GET_CURRENT_CONTEXT(ctx);
321 GLuint c;
Keith Whitwell58e99172001-01-05 02:26:48 +0000322 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000323
324 switch (target) {
325 case GL_CONVOLUTION_1D:
326 c = 0;
327 break;
328 case GL_CONVOLUTION_2D:
329 c = 1;
330 break;
331 case GL_SEPARABLE_2D:
332 c = 2;
333 break;
334 default:
Brian Paul08836342001-03-03 20:33:27 +0000335 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000336 return;
337 }
338
339 switch (pname) {
340 case GL_CONVOLUTION_BORDER_MODE:
341 if (param == (GLfloat) GL_REDUCE ||
342 param == (GLfloat) GL_CONSTANT_BORDER ||
343 param == (GLfloat) GL_REPLICATE_BORDER) {
344 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
345 }
346 else {
Brian Paul08836342001-03-03 20:33:27 +0000347 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000348 return;
349 }
350 break;
351 default:
Brian Paul08836342001-03-03 20:33:27 +0000352 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000353 return;
354 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000355
356 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000357}
358
359
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000360void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000361_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
362{
363 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000364 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000365 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000366
367 switch (target) {
368 case GL_CONVOLUTION_1D:
369 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000370 break;
371 case GL_CONVOLUTION_2D:
372 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000373 break;
374 case GL_SEPARABLE_2D:
375 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000376 break;
377 default:
Brian Paul08836342001-03-03 20:33:27 +0000378 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000379 return;
380 }
381
382 switch (pname) {
383 case GL_CONVOLUTION_BORDER_COLOR:
384 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
385 break;
386 case GL_CONVOLUTION_BORDER_MODE:
387 if (params[0] == (GLfloat) GL_REDUCE ||
388 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
389 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
390 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
391 }
392 else {
Brian Paul08836342001-03-03 20:33:27 +0000393 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000394 return;
395 }
396 break;
397 case GL_CONVOLUTION_FILTER_SCALE:
398 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
399 break;
400 case GL_CONVOLUTION_FILTER_BIAS:
401 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
402 break;
403 default:
Brian Paul08836342001-03-03 20:33:27 +0000404 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000405 return;
406 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000407
408 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000409}
410
411
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000412void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000413_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
414{
415 GET_CURRENT_CONTEXT(ctx);
416 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000417 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000418
419 switch (target) {
420 case GL_CONVOLUTION_1D:
421 c = 0;
422 break;
423 case GL_CONVOLUTION_2D:
424 c = 1;
425 break;
426 case GL_SEPARABLE_2D:
427 c = 2;
428 break;
429 default:
Brian Paul08836342001-03-03 20:33:27 +0000430 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000431 return;
432 }
433
434 switch (pname) {
435 case GL_CONVOLUTION_BORDER_MODE:
436 if (param == (GLint) GL_REDUCE ||
437 param == (GLint) GL_CONSTANT_BORDER ||
438 param == (GLint) GL_REPLICATE_BORDER) {
439 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
440 }
441 else {
Brian Paul08836342001-03-03 20:33:27 +0000442 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000443 return;
444 }
445 break;
446 default:
Brian Paul08836342001-03-03 20:33:27 +0000447 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000448 return;
449 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000450
451 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000452}
453
454
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000455void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000456_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
457{
458 GET_CURRENT_CONTEXT(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000459 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000460 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000461
462 switch (target) {
463 case GL_CONVOLUTION_1D:
464 c = 0;
Brian Paul147b0832000-08-23 14:31:25 +0000465 break;
466 case GL_CONVOLUTION_2D:
467 c = 1;
Brian Paul147b0832000-08-23 14:31:25 +0000468 break;
469 case GL_SEPARABLE_2D:
470 c = 2;
Brian Paul147b0832000-08-23 14:31:25 +0000471 break;
472 default:
Brian Paul08836342001-03-03 20:33:27 +0000473 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000474 return;
475 }
476
477 switch (pname) {
478 case GL_CONVOLUTION_BORDER_COLOR:
479 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
480 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
481 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
482 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
483 break;
484 case GL_CONVOLUTION_BORDER_MODE:
485 if (params[0] == (GLint) GL_REDUCE ||
486 params[0] == (GLint) GL_CONSTANT_BORDER ||
487 params[0] == (GLint) GL_REPLICATE_BORDER) {
488 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
489 }
490 else {
Brian Paul08836342001-03-03 20:33:27 +0000491 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
Brian Paul147b0832000-08-23 14:31:25 +0000492 return;
493 }
494 break;
495 case GL_CONVOLUTION_FILTER_SCALE:
Karl Schultz7c426812001-09-19 20:30:44 +0000496 /* COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params); */
497 /* need cast to prevent compiler warnings */
498 ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
499 ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
500 ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
501 ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000502 break;
503 case GL_CONVOLUTION_FILTER_BIAS:
Karl Schultz7c426812001-09-19 20:30:44 +0000504 /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
505 /* need cast to prevent compiler warnings */
506 ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
507 ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
508 ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
509 ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
Brian Paul147b0832000-08-23 14:31:25 +0000510 break;
511 default:
Brian Paul08836342001-03-03 20:33:27 +0000512 _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000513 return;
514 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000515
516 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000517}
518
519
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000520void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000521_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
522{
Brian Pauld0570642002-03-19 15:22:50 +0000523 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000524 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000525 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000526
527 if (target != GL_CONVOLUTION_1D) {
Brian Paul08836342001-03-03 20:33:27 +0000528 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000529 return;
530 }
531
532 baseFormat = base_filter_format(internalFormat);
533 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000534 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000535 return;
536 }
537
538 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000539 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000540 return;
541 }
542
Keith Whitwell70989242001-03-19 02:25:35 +0000543 ctx->Driver.CopyConvolutionFilter1D( ctx, target,
544 internalFormat, x, y, width);
Brian Paul147b0832000-08-23 14:31:25 +0000545}
546
547
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000548void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000549_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
550{
Brian Pauld0570642002-03-19 15:22:50 +0000551 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000552 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000553 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000554
555 if (target != GL_CONVOLUTION_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000556 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000557 return;
558 }
559
560 baseFormat = base_filter_format(internalFormat);
561 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000562 _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000563 return;
564 }
565
566 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000567 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000568 return;
569 }
570 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000571 _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000572 return;
573 }
574
Keith Whitwell70989242001-03-19 02:25:35 +0000575 ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
576 width, height );
Brian Paul147b0832000-08-23 14:31:25 +0000577}
578
579
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000580void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000581_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
582{
Brian Paulf75d6972000-09-05 20:28:56 +0000583 const struct gl_convolution_attrib *filter;
Brian Paulb51b0a82001-03-07 05:06:11 +0000584 GLuint row;
Brian Paul147b0832000-08-23 14:31:25 +0000585 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000586 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000587
Brian Paul0c000ec2000-11-21 23:26:13 +0000588 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000589 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000590 }
591
Brian Paulf959f6e2004-04-22 00:27:31 +0000592 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000593 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000594 return;
595 }
596
597 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000598 format == GL_STENCIL_INDEX ||
599 format == GL_DEPTH_COMPONENT ||
600 format == GL_INTENSITY ||
601 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000602 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000603 return;
604 }
605
Brian Paulf75d6972000-09-05 20:28:56 +0000606 switch (target) {
607 case GL_CONVOLUTION_1D:
608 filter = &(ctx->Convolution1D);
609 break;
610 case GL_CONVOLUTION_2D:
611 filter = &(ctx->Convolution2D);
612 break;
613 default:
Brian Paul08836342001-03-03 20:33:27 +0000614 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
Brian Paulf75d6972000-09-05 20:28:56 +0000615 return;
616 }
617
Brian Paulbd3b40a2004-10-31 17:36:23 +0000618 if (ctx->Pack.BufferObj->Name) {
619 /* Pack the filter into a PBO */
620 GLubyte *buf;
621 if (!_mesa_validate_pbo_access(&ctx->Pack, filter->Width, filter->Height,
622 1, format, type, image)) {
623 _mesa_error(ctx, GL_INVALID_OPERATION,
624 "glGetConvolutionFilter(invalid PBO access)");
625 return;
626 }
627 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
628 GL_WRITE_ONLY_ARB,
629 ctx->Pack.BufferObj);
630 if (!buf) {
631 /* buffer is already mapped - that's an error */
632 _mesa_error(ctx, GL_INVALID_OPERATION,
633 "glGetConvolutionFilter(PBO is mapped)");
634 return;
635 }
636 image = ADD_POINTERS(image, buf);
637 }
638
Brian Paulf75d6972000-09-05 20:28:56 +0000639 for (row = 0; row < filter->Height; row++) {
640 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
641 filter->Height, format, type,
642 0, row, 0);
643 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000644 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paulf75d6972000-09-05 20:28:56 +0000645 (const GLfloat (*)[4]) src,
646 format, type, dst, &ctx->Pack, 0);
647 }
Brian Paulbd3b40a2004-10-31 17:36:23 +0000648
649 if (ctx->Pack.BufferObj->Name) {
650 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
651 ctx->Pack.BufferObj);
652 }
Brian Paul147b0832000-08-23 14:31:25 +0000653}
654
655
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000656void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000657_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
658{
659 GET_CURRENT_CONTEXT(ctx);
660 const struct gl_convolution_attrib *conv;
661 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000662 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000663
664 switch (target) {
665 case GL_CONVOLUTION_1D:
666 c = 0;
667 conv = &ctx->Convolution1D;
668 break;
669 case GL_CONVOLUTION_2D:
670 c = 1;
671 conv = &ctx->Convolution2D;
672 break;
673 case GL_SEPARABLE_2D:
674 c = 2;
675 conv = &ctx->Separable2D;
676 break;
677 default:
Brian Paul08836342001-03-03 20:33:27 +0000678 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000679 return;
680 }
681
682 switch (pname) {
683 case GL_CONVOLUTION_BORDER_COLOR:
684 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
685 break;
686 case GL_CONVOLUTION_BORDER_MODE:
687 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
688 break;
689 case GL_CONVOLUTION_FILTER_SCALE:
690 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
691 break;
692 case GL_CONVOLUTION_FILTER_BIAS:
693 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
694 break;
695 case GL_CONVOLUTION_FORMAT:
696 *params = (GLfloat) conv->Format;
697 break;
698 case GL_CONVOLUTION_WIDTH:
699 *params = (GLfloat) conv->Width;
700 break;
701 case GL_CONVOLUTION_HEIGHT:
702 *params = (GLfloat) conv->Height;
703 break;
704 case GL_MAX_CONVOLUTION_WIDTH:
705 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
706 break;
707 case GL_MAX_CONVOLUTION_HEIGHT:
708 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
709 break;
710 default:
Brian Paul08836342001-03-03 20:33:27 +0000711 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000712 return;
713 }
714}
715
716
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000717void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000718_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
719{
720 GET_CURRENT_CONTEXT(ctx);
721 const struct gl_convolution_attrib *conv;
722 GLuint c;
Keith Whitwellcab974c2000-12-26 05:09:27 +0000723 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000724
725 switch (target) {
726 case GL_CONVOLUTION_1D:
727 c = 0;
728 conv = &ctx->Convolution1D;
729 break;
730 case GL_CONVOLUTION_2D:
731 c = 1;
732 conv = &ctx->Convolution2D;
733 break;
734 case GL_SEPARABLE_2D:
735 c = 2;
736 conv = &ctx->Separable2D;
737 break;
738 default:
Brian Paul08836342001-03-03 20:33:27 +0000739 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000740 return;
741 }
742
743 switch (pname) {
744 case GL_CONVOLUTION_BORDER_COLOR:
745 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
746 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
747 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
748 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
749 break;
750 case GL_CONVOLUTION_BORDER_MODE:
751 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
752 break;
753 case GL_CONVOLUTION_FILTER_SCALE:
754 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
755 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
756 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
757 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
758 break;
759 case GL_CONVOLUTION_FILTER_BIAS:
760 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
761 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
762 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
763 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
764 break;
765 case GL_CONVOLUTION_FORMAT:
766 *params = (GLint) conv->Format;
767 break;
768 case GL_CONVOLUTION_WIDTH:
769 *params = (GLint) conv->Width;
770 break;
771 case GL_CONVOLUTION_HEIGHT:
772 *params = (GLint) conv->Height;
773 break;
774 case GL_MAX_CONVOLUTION_WIDTH:
775 *params = (GLint) ctx->Const.MaxConvolutionWidth;
776 break;
777 case GL_MAX_CONVOLUTION_HEIGHT:
778 *params = (GLint) ctx->Const.MaxConvolutionHeight;
779 break;
780 default:
Brian Paul08836342001-03-03 20:33:27 +0000781 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
Brian Paul147b0832000-08-23 14:31:25 +0000782 return;
783 }
784}
785
786
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000787void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000788_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
789{
Brian Paulf75d6972000-09-05 20:28:56 +0000790 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
791 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000792 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000793 ASSERT_OUTSIDE_BEGIN_END(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000794
Brian Paul0c000ec2000-11-21 23:26:13 +0000795 if (ctx->NewState) {
Brian Paul08836342001-03-03 20:33:27 +0000796 _mesa_update_state(ctx);
Brian Paul0c000ec2000-11-21 23:26:13 +0000797 }
798
Brian Paul147b0832000-08-23 14:31:25 +0000799 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000800 _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000801 return;
802 }
803
Brian Paulf959f6e2004-04-22 00:27:31 +0000804 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000805 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000806 return;
807 }
808
809 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000810 format == GL_STENCIL_INDEX ||
811 format == GL_DEPTH_COMPONENT ||
812 format == GL_INTENSITY ||
813 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000814 _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000815 return;
816 }
817
Brian Paulf75d6972000-09-05 20:28:56 +0000818 filter = &ctx->Separable2D;
819
Brian Paulbd3b40a2004-10-31 17:36:23 +0000820 if (ctx->Pack.BufferObj->Name) {
821 /* Pack filter into PBO */
822 GLubyte *buf;
823 if (!_mesa_validate_pbo_access(&ctx->Pack, filter->Width, 1, 1,
824 format, type, row)) {
825 _mesa_error(ctx, GL_INVALID_OPERATION,
826 "glGetSeparableFilter(invalid PBO access, width)");
827 return;
828 }
829 if (!_mesa_validate_pbo_access(&ctx->Pack, filter->Height, 1, 1,
830 format, type, column)) {
831 _mesa_error(ctx, GL_INVALID_OPERATION,
832 "glGetSeparableFilter(invalid PBO access, height)");
833 return;
834 }
835 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
836 GL_WRITE_ONLY_ARB,
837 ctx->Pack.BufferObj);
838 if (!buf) {
839 /* buffer is already mapped - that's an error */
840 _mesa_error(ctx, GL_INVALID_OPERATION,
841 "glGetSeparableFilter(PBO is mapped)");
842 return;
843 }
844 row = ADD_POINTERS(buf, row);
845 column = ADD_POINTERS(buf, column);
846 }
847
Brian Paulf75d6972000-09-05 20:28:56 +0000848 /* Row filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000849 if (row) {
Brian Paulf75d6972000-09-05 20:28:56 +0000850 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
851 filter->Height, format, type,
852 0, 0, 0);
Brian Paul8cfd08b2004-02-28 20:35:57 +0000853 _mesa_pack_rgba_span_float(ctx, filter->Width,
Brian Paulf75d6972000-09-05 20:28:56 +0000854 (const GLfloat (*)[4]) filter->Filter,
855 format, type, dst, &ctx->Pack, 0);
856 }
857
858 /* Column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000859 if (column) {
Brian Paulf75d6972000-09-05 20:28:56 +0000860 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
861 1, format, type,
862 0, 0, 0);
863 const GLfloat *src = filter->Filter + colStart;
Brian Paul8cfd08b2004-02-28 20:35:57 +0000864 _mesa_pack_rgba_span_float(ctx, filter->Height,
Brian Paulf75d6972000-09-05 20:28:56 +0000865 (const GLfloat (*)[4]) src,
866 format, type, dst, &ctx->Pack, 0);
867 }
868
869 (void) span; /* unused at this time */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000870
871 if (ctx->Pack.BufferObj->Name) {
872 /* Pack filter into PBO */
873 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
874 ctx->Unpack.BufferObj);
875 }
Brian Paul147b0832000-08-23 14:31:25 +0000876}
877
878
Kendall Bennettc40d1dd2003-10-21 22:22:17 +0000879void GLAPIENTRY
Brian Paul147b0832000-08-23 14:31:25 +0000880_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
881{
882 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
Brian Pauld0570642002-03-19 15:22:50 +0000883 GLint baseFormat;
Brian Paul147b0832000-08-23 14:31:25 +0000884 GET_CURRENT_CONTEXT(ctx);
Keith Whitwellcab974c2000-12-26 05:09:27 +0000885 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000886
887 if (target != GL_SEPARABLE_2D) {
Brian Paul08836342001-03-03 20:33:27 +0000888 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
Brian Paul147b0832000-08-23 14:31:25 +0000889 return;
890 }
891
892 baseFormat = base_filter_format(internalFormat);
893 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
Brian Paul08836342001-03-03 20:33:27 +0000894 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
Brian Paul147b0832000-08-23 14:31:25 +0000895 return;
896 }
897
898 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
Brian Paul08836342001-03-03 20:33:27 +0000899 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
Brian Paul147b0832000-08-23 14:31:25 +0000900 return;
901 }
902 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
Brian Paul08836342001-03-03 20:33:27 +0000903 _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
Brian Paul147b0832000-08-23 14:31:25 +0000904 return;
905 }
906
Brian Paulf959f6e2004-04-22 00:27:31 +0000907 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
Brian Paul08836342001-03-03 20:33:27 +0000908 _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
Brian Paul90f042a2000-12-10 19:23:19 +0000909 return;
910 }
911
912 if (format == GL_COLOR_INDEX ||
Brian Paul147b0832000-08-23 14:31:25 +0000913 format == GL_STENCIL_INDEX ||
914 format == GL_DEPTH_COMPONENT ||
915 format == GL_INTENSITY ||
916 type == GL_BITMAP) {
Brian Paul08836342001-03-03 20:33:27 +0000917 _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
Brian Paul147b0832000-08-23 14:31:25 +0000918 return;
919 }
920
921 ctx->Separable2D.Format = format;
922 ctx->Separable2D.InternalFormat = internalFormat;
923 ctx->Separable2D.Width = width;
924 ctx->Separable2D.Height = height;
925
Brian Paulbd3b40a2004-10-31 17:36:23 +0000926 if (ctx->Unpack.BufferObj->Name) {
927 /* unpack filter from PBO */
928 GLubyte *buf;
929 if (!_mesa_validate_pbo_access(&ctx->Unpack, width, 1, 1,
930 format, type, row)) {
931 _mesa_error(ctx, GL_INVALID_OPERATION,
932 "glSeparableFilter2D(invalid PBO access, width)");
933 return;
934 }
935 if (!_mesa_validate_pbo_access(&ctx->Unpack, height, 1, 1,
936 format, type, column)) {
937 _mesa_error(ctx, GL_INVALID_OPERATION,
938 "glSeparableFilter2D(invalid PBO access, height)");
939 return;
940 }
941 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
942 GL_READ_ONLY_ARB,
943 ctx->Unpack.BufferObj);
944 if (!buf) {
945 /* buffer is already mapped - that's an error */
946 _mesa_error(ctx, GL_INVALID_OPERATION,
947 "glSeparableFilter2D(PBO is mapped)");
948 return;
949 }
950 row = ADD_POINTERS(buf, row);
951 column = ADD_POINTERS(buf, column);
952 }
Brian Paul147b0832000-08-23 14:31:25 +0000953
Brian Paulbd3b40a2004-10-31 17:36:23 +0000954 /* unpack row filter */
955 if (row) {
956 _mesa_unpack_color_span_float(ctx, width, GL_RGBA,
957 ctx->Separable2D.Filter,
958 format, type, row, &ctx->Unpack,
959 0); /* transferOps */
960
961 /* apply scale and bias */
962 {
963 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
964 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
965 GLint i;
966 for (i = 0; i < width; i++) {
967 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
968 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
969 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
970 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
971 r = r * scale[0] + bias[0];
972 g = g * scale[1] + bias[1];
973 b = b * scale[2] + bias[2];
974 a = a * scale[3] + bias[3];
975 ctx->Separable2D.Filter[i * 4 + 0] = r;
976 ctx->Separable2D.Filter[i * 4 + 1] = g;
977 ctx->Separable2D.Filter[i * 4 + 2] = b;
978 ctx->Separable2D.Filter[i * 4 + 3] = a;
979 }
Brian Paul147b0832000-08-23 14:31:25 +0000980 }
981 }
982
983 /* unpack column filter */
Brian Paulbd3b40a2004-10-31 17:36:23 +0000984 if (column) {
985 _mesa_unpack_color_span_float(ctx, height, GL_RGBA,
986 &ctx->Separable2D.Filter[colStart],
987 format, type, column, &ctx->Unpack,
988 0); /* transferOps */
Brian Paul147b0832000-08-23 14:31:25 +0000989
Brian Paulbd3b40a2004-10-31 17:36:23 +0000990 /* apply scale and bias */
991 {
992 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
993 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
994 GLint i;
995 for (i = 0; i < height; i++) {
996 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
997 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
998 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
999 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
1000 r = r * scale[0] + bias[0];
1001 g = g * scale[1] + bias[1];
1002 b = b * scale[2] + bias[2];
1003 a = a * scale[3] + bias[3];
1004 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
1005 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
1006 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
1007 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
1008 }
1009 }
1010 }
1011
1012 if (ctx->Unpack.BufferObj->Name) {
1013 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
1014 ctx->Unpack.BufferObj);
Brian Paul147b0832000-08-23 14:31:25 +00001015 }
Jouk Jansen5e3bc0c2000-11-22 07:32:16 +00001016
Brian Paulb5012e12000-11-10 18:31:04 +00001017 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +00001018}
1019
1020
1021/**********************************************************************/
1022/*** image convolution functions ***/
1023/**********************************************************************/
1024
Brian Pauld4b799b2000-08-21 14:24:30 +00001025static void
1026convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
1027 GLint filterWidth, const GLfloat filter[][4],
1028 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001029{
Brian Paul7e708742000-08-22 18:54:25 +00001030 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001031 GLint i, n;
1032
Brian Paul7e708742000-08-22 18:54:25 +00001033 if (filterWidth >= 1)
1034 dstWidth = srcWidth - (filterWidth - 1);
1035 else
1036 dstWidth = srcWidth;
1037
Brian Paulcc8e37f2000-07-12 13:00:09 +00001038 if (dstWidth <= 0)
1039 return; /* null result */
1040
1041 for (i = 0; i < dstWidth; i++) {
1042 GLfloat sumR = 0.0;
1043 GLfloat sumG = 0.0;
1044 GLfloat sumB = 0.0;
1045 GLfloat sumA = 0.0;
1046 for (n = 0; n < filterWidth; n++) {
1047 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
1048 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
1049 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
1050 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
1051 }
1052 dest[i][RCOMP] = sumR;
1053 dest[i][GCOMP] = sumG;
1054 dest[i][BCOMP] = sumB;
1055 dest[i][ACOMP] = sumA;
1056 }
1057}
1058
1059
Brian Pauld4b799b2000-08-21 14:24:30 +00001060static void
1061convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
1062 GLint filterWidth, const GLfloat filter[][4],
1063 GLfloat dest[][4],
1064 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001065{
1066 const GLint halfFilterWidth = filterWidth / 2;
1067 GLint i, n;
1068
1069 for (i = 0; i < srcWidth; i++) {
1070 GLfloat sumR = 0.0;
1071 GLfloat sumG = 0.0;
1072 GLfloat sumB = 0.0;
1073 GLfloat sumA = 0.0;
1074 for (n = 0; n < filterWidth; n++) {
1075 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
1076 sumR += borderColor[RCOMP] * filter[n][RCOMP];
1077 sumG += borderColor[GCOMP] * filter[n][GCOMP];
1078 sumB += borderColor[BCOMP] * filter[n][BCOMP];
1079 sumA += borderColor[ACOMP] * filter[n][ACOMP];
1080 }
1081 else {
1082 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1083 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1084 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1085 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1086 }
1087 }
1088 dest[i][RCOMP] = sumR;
1089 dest[i][GCOMP] = sumG;
1090 dest[i][BCOMP] = sumB;
1091 dest[i][ACOMP] = sumA;
1092 }
1093}
1094
1095
Brian Pauld4b799b2000-08-21 14:24:30 +00001096static void
1097convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
1098 GLint filterWidth, const GLfloat filter[][4],
1099 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001100{
1101 const GLint halfFilterWidth = filterWidth / 2;
1102 GLint i, n;
1103
1104 for (i = 0; i < srcWidth; i++) {
1105 GLfloat sumR = 0.0;
1106 GLfloat sumG = 0.0;
1107 GLfloat sumB = 0.0;
1108 GLfloat sumA = 0.0;
1109 for (n = 0; n < filterWidth; n++) {
1110 if (i + n < halfFilterWidth) {
1111 sumR += src[0][RCOMP] * filter[n][RCOMP];
1112 sumG += src[0][GCOMP] * filter[n][GCOMP];
1113 sumB += src[0][BCOMP] * filter[n][BCOMP];
1114 sumA += src[0][ACOMP] * filter[n][ACOMP];
1115 }
1116 else if (i + n - halfFilterWidth >= srcWidth) {
1117 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
1118 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
1119 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
1120 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
1121 }
1122 else {
1123 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
1124 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
1125 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
1126 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1127 }
1128 }
1129 dest[i][RCOMP] = sumR;
1130 dest[i][GCOMP] = sumG;
1131 dest[i][BCOMP] = sumB;
1132 dest[i][ACOMP] = sumA;
1133 }
1134}
1135
1136
Brian Pauld4b799b2000-08-21 14:24:30 +00001137static void
1138convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1139 const GLfloat src[][4],
1140 GLint filterWidth, GLint filterHeight,
1141 const GLfloat filter[][4],
1142 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001143{
Brian Paul7e708742000-08-22 18:54:25 +00001144 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001145 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001146
Brian Paul7e708742000-08-22 18:54:25 +00001147 if (filterWidth >= 1)
1148 dstWidth = srcWidth - (filterWidth - 1);
1149 else
1150 dstWidth = srcWidth;
1151
1152 if (filterHeight >= 1)
1153 dstHeight = srcHeight - (filterHeight - 1);
1154 else
1155 dstHeight = srcHeight;
1156
Brian Pauld4b799b2000-08-21 14:24:30 +00001157 if (dstWidth <= 0 || dstHeight <= 0)
1158 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001159
Brian Pauld4b799b2000-08-21 14:24:30 +00001160 for (j = 0; j < dstHeight; j++) {
1161 for (i = 0; i < dstWidth; i++) {
1162 GLfloat sumR = 0.0;
1163 GLfloat sumG = 0.0;
1164 GLfloat sumB = 0.0;
1165 GLfloat sumA = 0.0;
1166 for (m = 0; m < filterHeight; m++) {
1167 for (n = 0; n < filterWidth; n++) {
1168 const GLint k = (j + m) * srcWidth + i + n;
1169 const GLint f = m * filterWidth + n;
1170 sumR += src[k][RCOMP] * filter[f][RCOMP];
1171 sumG += src[k][GCOMP] * filter[f][GCOMP];
1172 sumB += src[k][BCOMP] * filter[f][BCOMP];
1173 sumA += src[k][ACOMP] * filter[f][ACOMP];
1174 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001175 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001176 dest[j * dstWidth + i][RCOMP] = sumR;
1177 dest[j * dstWidth + i][GCOMP] = sumG;
1178 dest[j * dstWidth + i][BCOMP] = sumB;
1179 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001180 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001181 }
1182}
1183
1184
Brian Pauld4b799b2000-08-21 14:24:30 +00001185static void
1186convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1187 const GLfloat src[][4],
1188 GLint filterWidth, GLint filterHeight,
1189 const GLfloat filter[][4],
1190 GLfloat dest[][4],
1191 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001192{
1193 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001194 const GLint halfFilterHeight = filterHeight / 2;
1195 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001196
Brian Pauld4b799b2000-08-21 14:24:30 +00001197 for (j = 0; j < srcHeight; j++) {
1198 for (i = 0; i < srcWidth; i++) {
1199 GLfloat sumR = 0.0;
1200 GLfloat sumG = 0.0;
1201 GLfloat sumB = 0.0;
1202 GLfloat sumA = 0.0;
1203 for (m = 0; m < filterHeight; m++) {
1204 for (n = 0; n < filterWidth; n++) {
1205 const GLint f = m * filterWidth + n;
1206 const GLint is = i + n - halfFilterWidth;
1207 const GLint js = j + m - halfFilterHeight;
1208 if (is < 0 || is >= srcWidth ||
1209 js < 0 || js >= srcHeight) {
1210 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1211 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1212 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1213 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1214 }
1215 else {
1216 const GLint k = js * srcWidth + is;
1217 sumR += src[k][RCOMP] * filter[f][RCOMP];
1218 sumG += src[k][GCOMP] * filter[f][GCOMP];
1219 sumB += src[k][BCOMP] * filter[f][BCOMP];
1220 sumA += src[k][ACOMP] * filter[f][ACOMP];
1221 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001222 }
1223 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001224 dest[j * srcWidth + i][RCOMP] = sumR;
1225 dest[j * srcWidth + i][GCOMP] = sumG;
1226 dest[j * srcWidth + i][BCOMP] = sumB;
1227 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001228 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001229 }
1230}
1231
1232
Brian Pauld4b799b2000-08-21 14:24:30 +00001233static void
1234convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1235 const GLfloat src[][4],
1236 GLint filterWidth, GLint filterHeight,
1237 const GLfloat filter[][4],
1238 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001239{
1240 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001241 const GLint halfFilterHeight = filterHeight / 2;
1242 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001243
Brian Pauld4b799b2000-08-21 14:24:30 +00001244 for (j = 0; j < srcHeight; j++) {
1245 for (i = 0; i < srcWidth; i++) {
1246 GLfloat sumR = 0.0;
1247 GLfloat sumG = 0.0;
1248 GLfloat sumB = 0.0;
1249 GLfloat sumA = 0.0;
1250 for (m = 0; m < filterHeight; m++) {
1251 for (n = 0; n < filterWidth; n++) {
1252 const GLint f = m * filterWidth + n;
1253 GLint is = i + n - halfFilterWidth;
1254 GLint js = j + m - halfFilterHeight;
1255 GLint k;
1256 if (is < 0)
1257 is = 0;
1258 else if (is >= srcWidth)
1259 is = srcWidth - 1;
1260 if (js < 0)
1261 js = 0;
1262 else if (js >= srcHeight)
1263 js = srcHeight - 1;
1264 k = js * srcWidth + is;
1265 sumR += src[k][RCOMP] * filter[f][RCOMP];
1266 sumG += src[k][GCOMP] * filter[f][GCOMP];
1267 sumB += src[k][BCOMP] * filter[f][BCOMP];
1268 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001269 }
1270 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001271 dest[j * srcWidth + i][RCOMP] = sumR;
1272 dest[j * srcWidth + i][GCOMP] = sumG;
1273 dest[j * srcWidth + i][BCOMP] = sumB;
1274 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001275 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001276 }
1277}
1278
1279
Brian Pauld4b799b2000-08-21 14:24:30 +00001280static void
1281convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1282 const GLfloat src[][4],
1283 GLint filterWidth, GLint filterHeight,
1284 const GLfloat rowFilt[][4],
1285 const GLfloat colFilt[][4],
1286 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001287{
Brian Paul7e708742000-08-22 18:54:25 +00001288 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001289 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001290
1291 if (filterWidth >= 1)
1292 dstWidth = srcWidth - (filterWidth - 1);
1293 else
1294 dstWidth = srcWidth;
1295
1296 if (filterHeight >= 1)
1297 dstHeight = srcHeight - (filterHeight - 1);
1298 else
1299 dstHeight = srcHeight;
1300
1301 if (dstWidth <= 0 || dstHeight <= 0)
1302 return;
1303
1304 for (j = 0; j < dstHeight; j++) {
1305 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001306 GLfloat sumR = 0.0;
1307 GLfloat sumG = 0.0;
1308 GLfloat sumB = 0.0;
1309 GLfloat sumA = 0.0;
1310 for (m = 0; m < filterHeight; m++) {
1311 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001312 GLint k = (j + m) * srcWidth + i + n;
1313 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1314 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1315 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1316 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001317 }
1318 }
Brian Paul7e708742000-08-22 18:54:25 +00001319 dest[j * dstWidth + i][RCOMP] = sumR;
1320 dest[j * dstWidth + i][GCOMP] = sumG;
1321 dest[j * dstWidth + i][BCOMP] = sumB;
1322 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001323 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001324 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001325}
1326
1327
Brian Pauld4b799b2000-08-21 14:24:30 +00001328static void
1329convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1330 const GLfloat src[][4],
1331 GLint filterWidth, GLint filterHeight,
1332 const GLfloat rowFilt[][4],
1333 const GLfloat colFilt[][4],
1334 GLfloat dest[][4],
1335 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001336{
1337 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001338 const GLint halfFilterHeight = filterHeight / 2;
1339 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001340
Brian Pauld4b799b2000-08-21 14:24:30 +00001341 for (j = 0; j < srcHeight; j++) {
1342 for (i = 0; i < srcWidth; i++) {
1343 GLfloat sumR = 0.0;
1344 GLfloat sumG = 0.0;
1345 GLfloat sumB = 0.0;
1346 GLfloat sumA = 0.0;
1347 for (m = 0; m < filterHeight; m++) {
1348 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001349 const GLint is = i + n - halfFilterWidth;
1350 const GLint js = j + m - halfFilterHeight;
1351 if (is < 0 || is >= srcWidth ||
1352 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001353 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1354 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1355 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1356 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1357 }
1358 else {
Brian Paul7e708742000-08-22 18:54:25 +00001359 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001360 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1361 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1362 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1363 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1364 }
Brian Paul7e708742000-08-22 18:54:25 +00001365
Brian Paulcc8e37f2000-07-12 13:00:09 +00001366 }
1367 }
Brian Paul7e708742000-08-22 18:54:25 +00001368 dest[j * srcWidth + i][RCOMP] = sumR;
1369 dest[j * srcWidth + i][GCOMP] = sumG;
1370 dest[j * srcWidth + i][BCOMP] = sumB;
1371 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001372 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001373 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001374}
1375
1376
1377static void
1378convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1379 const GLfloat src[][4],
1380 GLint filterWidth, GLint filterHeight,
1381 const GLfloat rowFilt[][4],
1382 const GLfloat colFilt[][4],
1383 GLfloat dest[][4])
1384{
1385 const GLint halfFilterWidth = filterWidth / 2;
1386 const GLint halfFilterHeight = filterHeight / 2;
1387 GLint i, j, n, m;
1388
1389 for (j = 0; j < srcHeight; j++) {
1390 for (i = 0; i < srcWidth; i++) {
1391 GLfloat sumR = 0.0;
1392 GLfloat sumG = 0.0;
1393 GLfloat sumB = 0.0;
1394 GLfloat sumA = 0.0;
1395 for (m = 0; m < filterHeight; m++) {
1396 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001397 GLint is = i + n - halfFilterWidth;
1398 GLint js = j + m - halfFilterHeight;
1399 GLint k;
1400 if (is < 0)
1401 is = 0;
1402 else if (is >= srcWidth)
1403 is = srcWidth - 1;
1404 if (js < 0)
1405 js = 0;
1406 else if (js >= srcHeight)
1407 js = srcHeight - 1;
1408 k = js * srcWidth + is;
1409 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1410 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1411 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1412 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001413 }
1414 }
Brian Paul7e708742000-08-22 18:54:25 +00001415 dest[j * srcWidth + i][RCOMP] = sumR;
1416 dest[j * srcWidth + i][GCOMP] = sumG;
1417 dest[j * srcWidth + i][BCOMP] = sumB;
1418 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001419 }
1420 }
1421}
1422
1423
1424
1425void
1426_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1427 const GLfloat *srcImage, GLfloat *dstImage)
1428{
1429 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1430 case GL_REDUCE:
1431 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1432 ctx->Convolution1D.Width,
1433 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1434 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001435 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001436 break;
1437 case GL_CONSTANT_BORDER:
1438 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1439 ctx->Convolution1D.Width,
1440 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1441 (GLfloat (*)[4]) dstImage,
1442 ctx->Pixel.ConvolutionBorderColor[0]);
1443 break;
1444 case GL_REPLICATE_BORDER:
1445 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1446 ctx->Convolution1D.Width,
1447 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1448 (GLfloat (*)[4]) dstImage);
1449 break;
1450 default:
1451 ;
1452 }
1453}
1454
1455
1456void
1457_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1458 const GLfloat *srcImage, GLfloat *dstImage)
1459{
1460 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1461 case GL_REDUCE:
1462 convolve_2d_reduce(*width, *height,
1463 (const GLfloat (*)[4]) srcImage,
1464 ctx->Convolution2D.Width,
1465 ctx->Convolution2D.Height,
1466 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1467 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001468 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1469 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001470 break;
1471 case GL_CONSTANT_BORDER:
1472 convolve_2d_constant(*width, *height,
1473 (const GLfloat (*)[4]) srcImage,
1474 ctx->Convolution2D.Width,
1475 ctx->Convolution2D.Height,
1476 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1477 (GLfloat (*)[4]) dstImage,
1478 ctx->Pixel.ConvolutionBorderColor[1]);
1479 break;
1480 case GL_REPLICATE_BORDER:
1481 convolve_2d_replicate(*width, *height,
1482 (const GLfloat (*)[4]) srcImage,
1483 ctx->Convolution2D.Width,
1484 ctx->Convolution2D.Height,
1485 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1486 (GLfloat (*)[4]) dstImage);
1487 break;
1488 default:
1489 ;
1490 }
1491}
1492
1493
1494void
1495_mesa_convolve_sep_image(const GLcontext *ctx,
1496 GLsizei *width, GLsizei *height,
1497 const GLfloat *srcImage, GLfloat *dstImage)
1498{
1499 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1500 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1501
1502 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1503 case GL_REDUCE:
1504 convolve_sep_reduce(*width, *height,
1505 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001506 ctx->Separable2D.Width,
1507 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001508 (const GLfloat (*)[4]) rowFilter,
1509 (const GLfloat (*)[4]) colFilter,
1510 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001511 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1512 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001513 break;
1514 case GL_CONSTANT_BORDER:
1515 convolve_sep_constant(*width, *height,
1516 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001517 ctx->Separable2D.Width,
1518 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001519 (const GLfloat (*)[4]) rowFilter,
1520 (const GLfloat (*)[4]) colFilter,
1521 (GLfloat (*)[4]) dstImage,
1522 ctx->Pixel.ConvolutionBorderColor[2]);
1523 break;
1524 case GL_REPLICATE_BORDER:
1525 convolve_sep_replicate(*width, *height,
1526 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001527 ctx->Separable2D.Width,
1528 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001529 (const GLfloat (*)[4]) rowFilter,
1530 (const GLfloat (*)[4]) colFilter,
1531 (GLfloat (*)[4]) dstImage);
1532 break;
1533 default:
1534 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001535 }
1536}
Brian Paul16461f72001-02-06 17:22:16 +00001537
1538
1539
1540/*
1541 * This function computes an image's size after convolution.
1542 * If the convolution border mode is GL_REDUCE, the post-convolution
1543 * image will be smaller than the original.
1544 */
1545void
1546_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1547 GLsizei *width, GLsizei *height)
1548{
1549 if (ctx->Pixel.Convolution1DEnabled
1550 && dimensions == 1
1551 && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1552 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1553 }
1554 else if (ctx->Pixel.Convolution2DEnabled
1555 && dimensions > 1
1556 && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1557 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1558 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1559 }
1560 else if (ctx->Pixel.Separable2DEnabled
1561 && dimensions > 1
1562 && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1563 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1564 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1565 }
1566}