blob: 1641f497d873d46f4b678346f1ba004f6f0990a6 [file] [log] [blame]
Brian Paulbaf3e772000-11-21 23:01:22 +00001/* $Id: convolve.c,v 1.12 2000/11/21 23:01:22 brianp Exp $ */
Brian Paulcc8e37f2000-07-12 13:00:09 +00002
3/*
4 * Mesa 3-D graphics library
Brian Pauld4b799b2000-08-21 14:24:30 +00005 * Version: 3.5
Brian Paulcc8e37f2000-07-12 13:00:09 +00006 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28/*
29 * Image convolution functions.
30 *
31 * Notes: filter kernel elements are indexed by <n> and <m> as in
32 * the GL spec.
33 */
34
35
36#ifdef PC_HEADER
37#include "all.h"
38#else
39#include "glheader.h"
Brian Paulc893a012000-10-28 20:41:13 +000040#include "colormac.h"
Brian Pauld4b799b2000-08-21 14:24:30 +000041#include "convolve.h"
42#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000043#include "image.h"
Brian Paulcc8e37f2000-07-12 13:00:09 +000044#include "types.h"
Brian Paulba41b8a2000-11-10 17:45:15 +000045#include "swrast/s_span.h" /* XXX SWRAST hack */
Brian Paulcc8e37f2000-07-12 13:00:09 +000046#endif
47
48
Brian Paul147b0832000-08-23 14:31:25 +000049/*
50 * Given an internalFormat token passed to glConvolutionFilter
51 * or glSeparableFilter, return the corresponding base format.
52 * Return -1 if invalid token.
53 */
54static GLint
55base_filter_format( GLenum format )
56{
57 switch (format) {
58 case GL_ALPHA:
59 case GL_ALPHA4:
60 case GL_ALPHA8:
61 case GL_ALPHA12:
62 case GL_ALPHA16:
63 return GL_ALPHA;
64 case GL_LUMINANCE:
65 case GL_LUMINANCE4:
66 case GL_LUMINANCE8:
67 case GL_LUMINANCE12:
68 case GL_LUMINANCE16:
69 return GL_LUMINANCE;
70 case GL_LUMINANCE_ALPHA:
71 case GL_LUMINANCE4_ALPHA4:
72 case GL_LUMINANCE6_ALPHA2:
73 case GL_LUMINANCE8_ALPHA8:
74 case GL_LUMINANCE12_ALPHA4:
75 case GL_LUMINANCE12_ALPHA12:
76 case GL_LUMINANCE16_ALPHA16:
77 return GL_LUMINANCE_ALPHA;
78 case GL_INTENSITY:
79 case GL_INTENSITY4:
80 case GL_INTENSITY8:
81 case GL_INTENSITY12:
82 case GL_INTENSITY16:
83 return GL_INTENSITY;
84 case GL_RGB:
85 case GL_R3_G3_B2:
86 case GL_RGB4:
87 case GL_RGB5:
88 case GL_RGB8:
89 case GL_RGB10:
90 case GL_RGB12:
91 case GL_RGB16:
92 return GL_RGB;
93 case 4:
94 case GL_RGBA:
95 case GL_RGBA2:
96 case GL_RGBA4:
97 case GL_RGB5_A1:
98 case GL_RGBA8:
99 case GL_RGB10_A2:
100 case GL_RGBA12:
101 case GL_RGBA16:
102 return GL_RGBA;
103 default:
104 return -1; /* error */
105 }
106}
107
108
109void
110_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
111{
112 GLenum baseFormat;
113 GET_CURRENT_CONTEXT(ctx);
114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter1D");
115
116 if (target != GL_CONVOLUTION_1D) {
117 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
118 return;
119 }
120
121 baseFormat = base_filter_format(internalFormat);
122 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
123 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
124 return;
125 }
126
127 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
128 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
129 return;
130 }
131
132 if (!_mesa_is_legal_format_and_type(format, type) ||
133 format == GL_COLOR_INDEX ||
134 format == GL_STENCIL_INDEX ||
135 format == GL_DEPTH_COMPONENT ||
136 format == GL_INTENSITY ||
137 type == GL_BITMAP) {
138 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
139 return;
140 }
141
142 ctx->Convolution1D.Format = format;
143 ctx->Convolution1D.InternalFormat = internalFormat;
144 ctx->Convolution1D.Width = width;
145 ctx->Convolution1D.Height = 1;
146
147 /* unpack filter image */
148 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
149 ctx->Convolution1D.Filter,
150 format, type, image, &ctx->Unpack,
151 0, GL_FALSE);
152
153 /* apply scale and bias */
154 {
155 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
156 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
157 GLint i;
158 for (i = 0; i < width; i++) {
159 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
160 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
161 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
162 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
163 r = r * scale[0] + bias[0];
164 g = g * scale[1] + bias[1];
165 b = b * scale[2] + bias[2];
166 a = a * scale[3] + bias[3];
167 ctx->Convolution1D.Filter[i * 4 + 0] = r;
168 ctx->Convolution1D.Filter[i * 4 + 1] = g;
169 ctx->Convolution1D.Filter[i * 4 + 2] = b;
170 ctx->Convolution1D.Filter[i * 4 + 3] = a;
171 }
172 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000173
Brian Paulb5012e12000-11-10 18:31:04 +0000174 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000175}
176
177
178void
179_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
180{
181 GLenum baseFormat;
182 GLint i, components;
183 GET_CURRENT_CONTEXT(ctx);
184 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter2D");
185
186 if (target != GL_CONVOLUTION_2D) {
187 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
188 return;
189 }
190
191 baseFormat = base_filter_format(internalFormat);
192 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
193 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
194 return;
195 }
196
197 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
198 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
199 return;
200 }
201 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
202 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
203 return;
204 }
205
206 if (!_mesa_is_legal_format_and_type(format, type) ||
207 format == GL_COLOR_INDEX ||
208 format == GL_STENCIL_INDEX ||
209 format == GL_DEPTH_COMPONENT ||
210 format == GL_INTENSITY ||
211 type == GL_BITMAP) {
212 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
213 return;
214 }
215
216 components = _mesa_components_in_format(format);
217 assert(components > 0); /* this should have been caught earlier */
218
219 ctx->Convolution2D.Format = format;
220 ctx->Convolution2D.InternalFormat = internalFormat;
221 ctx->Convolution2D.Width = width;
222 ctx->Convolution2D.Height = height;
223
224 /* Unpack filter image. We always store filters in RGBA format. */
225 for (i = 0; i < height; i++) {
226 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
227 height, format, type, 0, i, 0);
228 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
229 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
230 format, type, src, &ctx->Unpack,
231 0, GL_FALSE);
232 }
233
234 /* apply scale and bias */
235 {
236 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
237 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
238 for (i = 0; i < width * height * 4; i++) {
239 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
240 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
241 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
242 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
243 r = r * scale[0] + bias[0];
244 g = g * scale[1] + bias[1];
245 b = b * scale[2] + bias[2];
246 a = a * scale[3] + bias[3];
247 ctx->Convolution2D.Filter[i * 4 + 0] = r;
248 ctx->Convolution2D.Filter[i * 4 + 1] = g;
249 ctx->Convolution2D.Filter[i * 4 + 2] = b;
250 ctx->Convolution2D.Filter[i * 4 + 3] = a;
251 }
252 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000253
Brian Paulb5012e12000-11-10 18:31:04 +0000254 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000255}
256
257
258void
259_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
260{
261 GET_CURRENT_CONTEXT(ctx);
262 GLuint c;
263
264 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterf");
265
266 switch (target) {
267 case GL_CONVOLUTION_1D:
268 c = 0;
269 break;
270 case GL_CONVOLUTION_2D:
271 c = 1;
272 break;
273 case GL_SEPARABLE_2D:
274 c = 2;
275 break;
276 default:
277 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
278 return;
279 }
280
281 switch (pname) {
282 case GL_CONVOLUTION_BORDER_MODE:
283 if (param == (GLfloat) GL_REDUCE ||
284 param == (GLfloat) GL_CONSTANT_BORDER ||
285 param == (GLfloat) GL_REPLICATE_BORDER) {
286 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
287 }
288 else {
289 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
290 return;
291 }
292 break;
293 default:
294 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
295 return;
296 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000297
298 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000299}
300
301
302void
303_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
304{
305 GET_CURRENT_CONTEXT(ctx);
306 struct gl_convolution_attrib *conv;
307 GLuint c;
308
309 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterfv");
310
311 switch (target) {
312 case GL_CONVOLUTION_1D:
313 c = 0;
314 conv = &ctx->Convolution1D;
315 break;
316 case GL_CONVOLUTION_2D:
317 c = 1;
318 conv = &ctx->Convolution2D;
319 break;
320 case GL_SEPARABLE_2D:
321 c = 2;
322 conv = &ctx->Separable2D;
323 break;
324 default:
325 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
326 return;
327 }
328
329 switch (pname) {
330 case GL_CONVOLUTION_BORDER_COLOR:
331 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
332 break;
333 case GL_CONVOLUTION_BORDER_MODE:
334 if (params[0] == (GLfloat) GL_REDUCE ||
335 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
336 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
337 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
338 }
339 else {
340 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
341 return;
342 }
343 break;
344 case GL_CONVOLUTION_FILTER_SCALE:
345 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
346 break;
347 case GL_CONVOLUTION_FILTER_BIAS:
348 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
349 break;
350 default:
351 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
352 return;
353 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000354
355 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000356}
357
358
359void
360_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
361{
362 GET_CURRENT_CONTEXT(ctx);
363 GLuint c;
364
365 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteri");
366
367 switch (target) {
368 case GL_CONVOLUTION_1D:
369 c = 0;
370 break;
371 case GL_CONVOLUTION_2D:
372 c = 1;
373 break;
374 case GL_SEPARABLE_2D:
375 c = 2;
376 break;
377 default:
378 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
379 return;
380 }
381
382 switch (pname) {
383 case GL_CONVOLUTION_BORDER_MODE:
384 if (param == (GLint) GL_REDUCE ||
385 param == (GLint) GL_CONSTANT_BORDER ||
386 param == (GLint) GL_REPLICATE_BORDER) {
387 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
388 }
389 else {
390 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
391 return;
392 }
393 break;
394 default:
395 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
396 return;
397 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000398
399 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000400}
401
402
403void
404_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
405{
406 GET_CURRENT_CONTEXT(ctx);
407 struct gl_convolution_attrib *conv;
408 GLuint c;
409
410 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteriv");
411
412 switch (target) {
413 case GL_CONVOLUTION_1D:
414 c = 0;
415 conv = &ctx->Convolution1D;
416 break;
417 case GL_CONVOLUTION_2D:
418 c = 1;
419 conv = &ctx->Convolution2D;
420 break;
421 case GL_SEPARABLE_2D:
422 c = 2;
423 conv = &ctx->Separable2D;
424 break;
425 default:
426 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
427 return;
428 }
429
430 switch (pname) {
431 case GL_CONVOLUTION_BORDER_COLOR:
432 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
433 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
434 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
435 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
436 break;
437 case GL_CONVOLUTION_BORDER_MODE:
438 if (params[0] == (GLint) GL_REDUCE ||
439 params[0] == (GLint) GL_CONSTANT_BORDER ||
440 params[0] == (GLint) GL_REPLICATE_BORDER) {
441 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
442 }
443 else {
444 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
445 return;
446 }
447 break;
448 case GL_CONVOLUTION_FILTER_SCALE:
449 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
450 break;
451 case GL_CONVOLUTION_FILTER_BIAS:
452 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
453 break;
454 default:
455 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
456 return;
457 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000458
459 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000460}
461
462
463void
464_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
465{
466 GLenum baseFormat;
Brian Paulbaf3e772000-11-21 23:01:22 +0000467 GLchan rgba[MAX_CONVOLUTION_WIDTH][4];
Brian Paul147b0832000-08-23 14:31:25 +0000468 GET_CURRENT_CONTEXT(ctx);
469 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter1D");
470
471 if (target != GL_CONVOLUTION_1D) {
472 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
473 return;
474 }
475
476 baseFormat = base_filter_format(internalFormat);
477 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
478 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
479 return;
480 }
481
482 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
483 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
484 return;
485 }
486
487 /* read pixels from framebuffer */
Brian Paulbaf3e772000-11-21 23:01:22 +0000488 RENDER_START(ctx);
Brian Paulba643a22000-10-28 18:34:48 +0000489 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
Brian Paulbaf3e772000-11-21 23:01:22 +0000490 RENDER_FINISH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000491
492 /* store as convolution filter */
493 _mesa_ConvolutionFilter1D(target, internalFormat, width,
Brian Paulbaf3e772000-11-21 23:01:22 +0000494 GL_RGBA, CHAN_TYPE, rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000495}
496
497
498void
499_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
500{
501 GLenum baseFormat;
502 GLint i;
503 struct gl_pixelstore_attrib packSave;
Brian Paulbaf3e772000-11-21 23:01:22 +0000504 GLchan rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
Brian Paul147b0832000-08-23 14:31:25 +0000505 GET_CURRENT_CONTEXT(ctx);
506 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter2D");
507
508 if (target != GL_CONVOLUTION_2D) {
509 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
510 return;
511 }
512
513 baseFormat = base_filter_format(internalFormat);
514 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
515 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
516 return;
517 }
518
519 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
520 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
521 return;
522 }
523 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
524 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
525 return;
526 }
527
528 /* read pixels from framebuffer */
Brian Paulbaf3e772000-11-21 23:01:22 +0000529 RENDER_START(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000530 for (i = 0; i < height; i++) {
531 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
Brian Paulba643a22000-10-28 18:34:48 +0000532 (GLchan (*)[4]) rgba[i]);
Brian Paul147b0832000-08-23 14:31:25 +0000533 }
Brian Paulbaf3e772000-11-21 23:01:22 +0000534 RENDER_FINISH(ctx);
Brian Paul147b0832000-08-23 14:31:25 +0000535
536 /*
537 * store as convolution filter
538 */
539 packSave = ctx->Unpack; /* save pixel packing params */
540
541 ctx->Unpack.Alignment = 1;
542 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
543 ctx->Unpack.SkipPixels = 0;
544 ctx->Unpack.SkipRows = 0;
545 ctx->Unpack.ImageHeight = 0;
546 ctx->Unpack.SkipImages = 0;
547 ctx->Unpack.SwapBytes = GL_FALSE;
548 ctx->Unpack.LsbFirst = GL_FALSE;
Keith Whitwella96308c2000-10-30 13:31:59 +0000549 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000550
551 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
Brian Paulbaf3e772000-11-21 23:01:22 +0000552 GL_RGBA, CHAN_TYPE, rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000553
554 ctx->Unpack = packSave; /* restore pixel packing params */
Keith Whitwella96308c2000-10-30 13:31:59 +0000555 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000556}
557
558
559void
560_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
561{
Brian Paulf75d6972000-09-05 20:28:56 +0000562 const struct gl_convolution_attrib *filter;
563 GLint row;
Brian Paul147b0832000-08-23 14:31:25 +0000564 GET_CURRENT_CONTEXT(ctx);
565 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
566
Brian Paul147b0832000-08-23 14:31:25 +0000567 if (!_mesa_is_legal_format_and_type(format, type) ||
568 format == GL_COLOR_INDEX ||
569 format == GL_STENCIL_INDEX ||
570 format == GL_DEPTH_COMPONENT ||
571 format == GL_INTENSITY ||
572 type == GL_BITMAP) {
573 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
574 return;
575 }
576
Brian Paulf75d6972000-09-05 20:28:56 +0000577 switch (target) {
578 case GL_CONVOLUTION_1D:
579 filter = &(ctx->Convolution1D);
580 break;
581 case GL_CONVOLUTION_2D:
582 filter = &(ctx->Convolution2D);
583 break;
584 default:
585 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
586 return;
587 }
588
589 for (row = 0; row < filter->Height; row++) {
590 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
591 filter->Height, format, type,
592 0, row, 0);
593 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paulf75d6972000-09-05 20:28:56 +0000594 _mesa_pack_float_rgba_span(ctx, filter->Width,
595 (const GLfloat (*)[4]) src,
596 format, type, dst, &ctx->Pack, 0);
597 }
Brian Paul147b0832000-08-23 14:31:25 +0000598}
599
600
601void
602_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
603{
604 GET_CURRENT_CONTEXT(ctx);
605 const struct gl_convolution_attrib *conv;
606 GLuint c;
607
608 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
609
610 switch (target) {
611 case GL_CONVOLUTION_1D:
612 c = 0;
613 conv = &ctx->Convolution1D;
614 break;
615 case GL_CONVOLUTION_2D:
616 c = 1;
617 conv = &ctx->Convolution2D;
618 break;
619 case GL_SEPARABLE_2D:
620 c = 2;
621 conv = &ctx->Separable2D;
622 break;
623 default:
624 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
625 return;
626 }
627
628 switch (pname) {
629 case GL_CONVOLUTION_BORDER_COLOR:
630 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
631 break;
632 case GL_CONVOLUTION_BORDER_MODE:
633 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
634 break;
635 case GL_CONVOLUTION_FILTER_SCALE:
636 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
637 break;
638 case GL_CONVOLUTION_FILTER_BIAS:
639 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
640 break;
641 case GL_CONVOLUTION_FORMAT:
642 *params = (GLfloat) conv->Format;
643 break;
644 case GL_CONVOLUTION_WIDTH:
645 *params = (GLfloat) conv->Width;
646 break;
647 case GL_CONVOLUTION_HEIGHT:
648 *params = (GLfloat) conv->Height;
649 break;
650 case GL_MAX_CONVOLUTION_WIDTH:
651 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
652 break;
653 case GL_MAX_CONVOLUTION_HEIGHT:
654 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
655 break;
656 default:
657 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
658 return;
659 }
660}
661
662
663void
664_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
665{
666 GET_CURRENT_CONTEXT(ctx);
667 const struct gl_convolution_attrib *conv;
668 GLuint c;
669
670 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
671
672 switch (target) {
673 case GL_CONVOLUTION_1D:
674 c = 0;
675 conv = &ctx->Convolution1D;
676 break;
677 case GL_CONVOLUTION_2D:
678 c = 1;
679 conv = &ctx->Convolution2D;
680 break;
681 case GL_SEPARABLE_2D:
682 c = 2;
683 conv = &ctx->Separable2D;
684 break;
685 default:
686 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
687 return;
688 }
689
690 switch (pname) {
691 case GL_CONVOLUTION_BORDER_COLOR:
692 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
693 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
694 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
695 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
696 break;
697 case GL_CONVOLUTION_BORDER_MODE:
698 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
699 break;
700 case GL_CONVOLUTION_FILTER_SCALE:
701 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
702 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
703 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
704 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
705 break;
706 case GL_CONVOLUTION_FILTER_BIAS:
707 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
708 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
709 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
710 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
711 break;
712 case GL_CONVOLUTION_FORMAT:
713 *params = (GLint) conv->Format;
714 break;
715 case GL_CONVOLUTION_WIDTH:
716 *params = (GLint) conv->Width;
717 break;
718 case GL_CONVOLUTION_HEIGHT:
719 *params = (GLint) conv->Height;
720 break;
721 case GL_MAX_CONVOLUTION_WIDTH:
722 *params = (GLint) ctx->Const.MaxConvolutionWidth;
723 break;
724 case GL_MAX_CONVOLUTION_HEIGHT:
725 *params = (GLint) ctx->Const.MaxConvolutionHeight;
726 break;
727 default:
728 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
729 return;
730 }
731}
732
733
734void
735_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
736{
Brian Paulf75d6972000-09-05 20:28:56 +0000737 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
738 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000739 GET_CURRENT_CONTEXT(ctx);
740 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
741
742 if (target != GL_SEPARABLE_2D) {
743 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
744 return;
745 }
746
747 if (!_mesa_is_legal_format_and_type(format, type) ||
748 format == GL_COLOR_INDEX ||
749 format == GL_STENCIL_INDEX ||
750 format == GL_DEPTH_COMPONENT ||
751 format == GL_INTENSITY ||
752 type == GL_BITMAP) {
753 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
754 return;
755 }
756
Brian Paulf75d6972000-09-05 20:28:56 +0000757 filter = &ctx->Separable2D;
758
759 /* Row filter */
760 {
761 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
762 filter->Height, format, type,
763 0, 0, 0);
764 _mesa_pack_float_rgba_span(ctx, filter->Width,
765 (const GLfloat (*)[4]) filter->Filter,
766 format, type, dst, &ctx->Pack, 0);
767 }
768
769 /* Column filter */
770 {
771 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
772 1, format, type,
773 0, 0, 0);
774 const GLfloat *src = filter->Filter + colStart;
775 _mesa_pack_float_rgba_span(ctx, filter->Height,
776 (const GLfloat (*)[4]) src,
777 format, type, dst, &ctx->Pack, 0);
778 }
779
780 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000781}
782
783
784void
785_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
786{
787 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
788 GLenum baseFormat;
789 GET_CURRENT_CONTEXT(ctx);
790 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
791
792 if (target != GL_SEPARABLE_2D) {
793 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
794 return;
795 }
796
797 baseFormat = base_filter_format(internalFormat);
798 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
799 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
800 return;
801 }
802
803 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
804 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
805 return;
806 }
807 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
808 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
809 return;
810 }
811
812 if (!_mesa_is_legal_format_and_type(format, type) ||
813 format == GL_COLOR_INDEX ||
814 format == GL_STENCIL_INDEX ||
815 format == GL_DEPTH_COMPONENT ||
816 format == GL_INTENSITY ||
817 type == GL_BITMAP) {
818 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
819 return;
820 }
821
822 ctx->Separable2D.Format = format;
823 ctx->Separable2D.InternalFormat = internalFormat;
824 ctx->Separable2D.Width = width;
825 ctx->Separable2D.Height = height;
826
827 /* unpack row filter */
828 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
829 ctx->Separable2D.Filter,
830 format, type, row, &ctx->Unpack,
831 0, GL_FALSE);
832
833 /* apply scale and bias */
834 {
835 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
836 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
837 GLint i;
838 for (i = 0; i < width; i++) {
839 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
840 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
841 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
842 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
843 r = r * scale[0] + bias[0];
844 g = g * scale[1] + bias[1];
845 b = b * scale[2] + bias[2];
846 a = a * scale[3] + bias[3];
847 ctx->Separable2D.Filter[i * 4 + 0] = r;
848 ctx->Separable2D.Filter[i * 4 + 1] = g;
849 ctx->Separable2D.Filter[i * 4 + 2] = b;
850 ctx->Separable2D.Filter[i * 4 + 3] = a;
851 }
852 }
853
854 /* unpack column filter */
855 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
856 &ctx->Separable2D.Filter[colStart],
857 format, type, column, &ctx->Unpack,
858 0, GL_FALSE);
859
860 /* apply scale and bias */
861 {
862 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
863 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
864 GLint i;
865 for (i = 0; i < width; i++) {
866 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
867 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
868 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
869 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
870 r = r * scale[0] + bias[0];
871 g = g * scale[1] + bias[1];
872 b = b * scale[2] + bias[2];
873 a = a * scale[3] + bias[3];
874 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
875 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
876 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
877 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
878 }
879 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000880
Brian Paulb5012e12000-11-10 18:31:04 +0000881 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000882}
883
884
885/**********************************************************************/
886/*** image convolution functions ***/
887/**********************************************************************/
888
Brian Pauld4b799b2000-08-21 14:24:30 +0000889static void
890convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
891 GLint filterWidth, const GLfloat filter[][4],
892 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000893{
Brian Paul7e708742000-08-22 18:54:25 +0000894 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000895 GLint i, n;
896
Brian Paul7e708742000-08-22 18:54:25 +0000897 if (filterWidth >= 1)
898 dstWidth = srcWidth - (filterWidth - 1);
899 else
900 dstWidth = srcWidth;
901
Brian Paulcc8e37f2000-07-12 13:00:09 +0000902 if (dstWidth <= 0)
903 return; /* null result */
904
905 for (i = 0; i < dstWidth; i++) {
906 GLfloat sumR = 0.0;
907 GLfloat sumG = 0.0;
908 GLfloat sumB = 0.0;
909 GLfloat sumA = 0.0;
910 for (n = 0; n < filterWidth; n++) {
911 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
912 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
913 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
914 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
915 }
916 dest[i][RCOMP] = sumR;
917 dest[i][GCOMP] = sumG;
918 dest[i][BCOMP] = sumB;
919 dest[i][ACOMP] = sumA;
920 }
921}
922
923
Brian Pauld4b799b2000-08-21 14:24:30 +0000924static void
925convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
926 GLint filterWidth, const GLfloat filter[][4],
927 GLfloat dest[][4],
928 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000929{
930 const GLint halfFilterWidth = filterWidth / 2;
931 GLint i, n;
932
933 for (i = 0; i < srcWidth; i++) {
934 GLfloat sumR = 0.0;
935 GLfloat sumG = 0.0;
936 GLfloat sumB = 0.0;
937 GLfloat sumA = 0.0;
938 for (n = 0; n < filterWidth; n++) {
939 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
940 sumR += borderColor[RCOMP] * filter[n][RCOMP];
941 sumG += borderColor[GCOMP] * filter[n][GCOMP];
942 sumB += borderColor[BCOMP] * filter[n][BCOMP];
943 sumA += borderColor[ACOMP] * filter[n][ACOMP];
944 }
945 else {
946 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
947 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
948 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
949 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
950 }
951 }
952 dest[i][RCOMP] = sumR;
953 dest[i][GCOMP] = sumG;
954 dest[i][BCOMP] = sumB;
955 dest[i][ACOMP] = sumA;
956 }
957}
958
959
Brian Pauld4b799b2000-08-21 14:24:30 +0000960static void
961convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
962 GLint filterWidth, const GLfloat filter[][4],
963 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000964{
965 const GLint halfFilterWidth = filterWidth / 2;
966 GLint i, n;
967
968 for (i = 0; i < srcWidth; i++) {
969 GLfloat sumR = 0.0;
970 GLfloat sumG = 0.0;
971 GLfloat sumB = 0.0;
972 GLfloat sumA = 0.0;
973 for (n = 0; n < filterWidth; n++) {
974 if (i + n < halfFilterWidth) {
975 sumR += src[0][RCOMP] * filter[n][RCOMP];
976 sumG += src[0][GCOMP] * filter[n][GCOMP];
977 sumB += src[0][BCOMP] * filter[n][BCOMP];
978 sumA += src[0][ACOMP] * filter[n][ACOMP];
979 }
980 else if (i + n - halfFilterWidth >= srcWidth) {
981 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
982 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
983 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
984 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
985 }
986 else {
987 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
988 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
989 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
990 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
991 }
992 }
993 dest[i][RCOMP] = sumR;
994 dest[i][GCOMP] = sumG;
995 dest[i][BCOMP] = sumB;
996 dest[i][ACOMP] = sumA;
997 }
998}
999
1000
Brian Pauld4b799b2000-08-21 14:24:30 +00001001static void
1002convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1003 const GLfloat src[][4],
1004 GLint filterWidth, GLint filterHeight,
1005 const GLfloat filter[][4],
1006 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001007{
Brian Paul7e708742000-08-22 18:54:25 +00001008 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001009 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001010
Brian Paul7e708742000-08-22 18:54:25 +00001011 if (filterWidth >= 1)
1012 dstWidth = srcWidth - (filterWidth - 1);
1013 else
1014 dstWidth = srcWidth;
1015
1016 if (filterHeight >= 1)
1017 dstHeight = srcHeight - (filterHeight - 1);
1018 else
1019 dstHeight = srcHeight;
1020
Brian Pauld4b799b2000-08-21 14:24:30 +00001021 if (dstWidth <= 0 || dstHeight <= 0)
1022 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001023
Brian Pauld4b799b2000-08-21 14:24:30 +00001024 for (j = 0; j < dstHeight; j++) {
1025 for (i = 0; i < dstWidth; i++) {
1026 GLfloat sumR = 0.0;
1027 GLfloat sumG = 0.0;
1028 GLfloat sumB = 0.0;
1029 GLfloat sumA = 0.0;
1030 for (m = 0; m < filterHeight; m++) {
1031 for (n = 0; n < filterWidth; n++) {
1032 const GLint k = (j + m) * srcWidth + i + n;
1033 const GLint f = m * filterWidth + n;
1034 sumR += src[k][RCOMP] * filter[f][RCOMP];
1035 sumG += src[k][GCOMP] * filter[f][GCOMP];
1036 sumB += src[k][BCOMP] * filter[f][BCOMP];
1037 sumA += src[k][ACOMP] * filter[f][ACOMP];
1038 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001039 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001040 dest[j * dstWidth + i][RCOMP] = sumR;
1041 dest[j * dstWidth + i][GCOMP] = sumG;
1042 dest[j * dstWidth + i][BCOMP] = sumB;
1043 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001044 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001045 }
1046}
1047
1048
Brian Pauld4b799b2000-08-21 14:24:30 +00001049static void
1050convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1051 const GLfloat src[][4],
1052 GLint filterWidth, GLint filterHeight,
1053 const GLfloat filter[][4],
1054 GLfloat dest[][4],
1055 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001056{
1057 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001058 const GLint halfFilterHeight = filterHeight / 2;
1059 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001060
Brian Pauld4b799b2000-08-21 14:24:30 +00001061 for (j = 0; j < srcHeight; j++) {
1062 for (i = 0; i < srcWidth; i++) {
1063 GLfloat sumR = 0.0;
1064 GLfloat sumG = 0.0;
1065 GLfloat sumB = 0.0;
1066 GLfloat sumA = 0.0;
1067 for (m = 0; m < filterHeight; m++) {
1068 for (n = 0; n < filterWidth; n++) {
1069 const GLint f = m * filterWidth + n;
1070 const GLint is = i + n - halfFilterWidth;
1071 const GLint js = j + m - halfFilterHeight;
1072 if (is < 0 || is >= srcWidth ||
1073 js < 0 || js >= srcHeight) {
1074 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1075 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1076 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1077 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1078 }
1079 else {
1080 const GLint k = js * srcWidth + is;
1081 sumR += src[k][RCOMP] * filter[f][RCOMP];
1082 sumG += src[k][GCOMP] * filter[f][GCOMP];
1083 sumB += src[k][BCOMP] * filter[f][BCOMP];
1084 sumA += src[k][ACOMP] * filter[f][ACOMP];
1085 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001086 }
1087 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001088 dest[j * srcWidth + i][RCOMP] = sumR;
1089 dest[j * srcWidth + i][GCOMP] = sumG;
1090 dest[j * srcWidth + i][BCOMP] = sumB;
1091 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001092 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001093 }
1094}
1095
1096
Brian Pauld4b799b2000-08-21 14:24:30 +00001097static void
1098convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1099 const GLfloat src[][4],
1100 GLint filterWidth, GLint filterHeight,
1101 const GLfloat filter[][4],
1102 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001103{
1104 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001105 const GLint halfFilterHeight = filterHeight / 2;
1106 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001107
Brian Pauld4b799b2000-08-21 14:24:30 +00001108 for (j = 0; j < srcHeight; j++) {
1109 for (i = 0; i < srcWidth; i++) {
1110 GLfloat sumR = 0.0;
1111 GLfloat sumG = 0.0;
1112 GLfloat sumB = 0.0;
1113 GLfloat sumA = 0.0;
1114 for (m = 0; m < filterHeight; m++) {
1115 for (n = 0; n < filterWidth; n++) {
1116 const GLint f = m * filterWidth + n;
1117 GLint is = i + n - halfFilterWidth;
1118 GLint js = j + m - halfFilterHeight;
1119 GLint k;
1120 if (is < 0)
1121 is = 0;
1122 else if (is >= srcWidth)
1123 is = srcWidth - 1;
1124 if (js < 0)
1125 js = 0;
1126 else if (js >= srcHeight)
1127 js = srcHeight - 1;
1128 k = js * srcWidth + is;
1129 sumR += src[k][RCOMP] * filter[f][RCOMP];
1130 sumG += src[k][GCOMP] * filter[f][GCOMP];
1131 sumB += src[k][BCOMP] * filter[f][BCOMP];
1132 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001133 }
1134 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001135 dest[j * srcWidth + i][RCOMP] = sumR;
1136 dest[j * srcWidth + i][GCOMP] = sumG;
1137 dest[j * srcWidth + i][BCOMP] = sumB;
1138 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001139 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001140 }
1141}
1142
1143
Brian Pauld4b799b2000-08-21 14:24:30 +00001144static void
1145convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1146 const GLfloat src[][4],
1147 GLint filterWidth, GLint filterHeight,
1148 const GLfloat rowFilt[][4],
1149 const GLfloat colFilt[][4],
1150 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001151{
Brian Paul7e708742000-08-22 18:54:25 +00001152 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001153 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001154
1155 if (filterWidth >= 1)
1156 dstWidth = srcWidth - (filterWidth - 1);
1157 else
1158 dstWidth = srcWidth;
1159
1160 if (filterHeight >= 1)
1161 dstHeight = srcHeight - (filterHeight - 1);
1162 else
1163 dstHeight = srcHeight;
1164
1165 if (dstWidth <= 0 || dstHeight <= 0)
1166 return;
1167
1168 for (j = 0; j < dstHeight; j++) {
1169 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001170 GLfloat sumR = 0.0;
1171 GLfloat sumG = 0.0;
1172 GLfloat sumB = 0.0;
1173 GLfloat sumA = 0.0;
1174 for (m = 0; m < filterHeight; m++) {
1175 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001176 GLint k = (j + m) * srcWidth + i + n;
1177 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1178 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1179 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1180 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001181 }
1182 }
Brian Paul7e708742000-08-22 18:54:25 +00001183 dest[j * dstWidth + i][RCOMP] = sumR;
1184 dest[j * dstWidth + i][GCOMP] = sumG;
1185 dest[j * dstWidth + i][BCOMP] = sumB;
1186 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001187 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001188 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001189}
1190
1191
Brian Pauld4b799b2000-08-21 14:24:30 +00001192static void
1193convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1194 const GLfloat src[][4],
1195 GLint filterWidth, GLint filterHeight,
1196 const GLfloat rowFilt[][4],
1197 const GLfloat colFilt[][4],
1198 GLfloat dest[][4],
1199 const GLfloat borderColor[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 Paul7e708742000-08-22 18:54:25 +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++) {
Brian Paul7e708742000-08-22 18:54:25 +00001213 const GLint is = i + n - halfFilterWidth;
1214 const GLint js = j + m - halfFilterHeight;
1215 if (is < 0 || is >= srcWidth ||
1216 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001217 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1218 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1219 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1220 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1221 }
1222 else {
Brian Paul7e708742000-08-22 18:54:25 +00001223 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001224 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1225 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1226 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1227 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1228 }
Brian Paul7e708742000-08-22 18:54:25 +00001229
Brian Paulcc8e37f2000-07-12 13:00:09 +00001230 }
1231 }
Brian Paul7e708742000-08-22 18:54:25 +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 Pauld4b799b2000-08-21 14:24:30 +00001237 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001238}
1239
1240
1241static void
1242convolve_sep_replicate(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])
1248{
1249 const GLint halfFilterWidth = filterWidth / 2;
1250 const GLint halfFilterHeight = filterHeight / 2;
1251 GLint i, j, n, m;
1252
1253 for (j = 0; j < srcHeight; j++) {
1254 for (i = 0; i < srcWidth; i++) {
1255 GLfloat sumR = 0.0;
1256 GLfloat sumG = 0.0;
1257 GLfloat sumB = 0.0;
1258 GLfloat sumA = 0.0;
1259 for (m = 0; m < filterHeight; m++) {
1260 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001261 GLint is = i + n - halfFilterWidth;
1262 GLint js = j + m - halfFilterHeight;
1263 GLint k;
1264 if (is < 0)
1265 is = 0;
1266 else if (is >= srcWidth)
1267 is = srcWidth - 1;
1268 if (js < 0)
1269 js = 0;
1270 else if (js >= srcHeight)
1271 js = srcHeight - 1;
1272 k = js * srcWidth + is;
1273 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1274 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1275 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1276 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001277 }
1278 }
Brian Paul7e708742000-08-22 18:54:25 +00001279 dest[j * srcWidth + i][RCOMP] = sumR;
1280 dest[j * srcWidth + i][GCOMP] = sumG;
1281 dest[j * srcWidth + i][BCOMP] = sumB;
1282 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001283 }
1284 }
1285}
1286
1287
1288
1289void
1290_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1291 const GLfloat *srcImage, GLfloat *dstImage)
1292{
1293 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1294 case GL_REDUCE:
1295 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1296 ctx->Convolution1D.Width,
1297 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1298 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001299 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001300 break;
1301 case GL_CONSTANT_BORDER:
1302 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1303 ctx->Convolution1D.Width,
1304 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1305 (GLfloat (*)[4]) dstImage,
1306 ctx->Pixel.ConvolutionBorderColor[0]);
1307 break;
1308 case GL_REPLICATE_BORDER:
1309 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1310 ctx->Convolution1D.Width,
1311 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1312 (GLfloat (*)[4]) dstImage);
1313 break;
1314 default:
1315 ;
1316 }
1317}
1318
1319
1320void
1321_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1322 const GLfloat *srcImage, GLfloat *dstImage)
1323{
1324 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1325 case GL_REDUCE:
1326 convolve_2d_reduce(*width, *height,
1327 (const GLfloat (*)[4]) srcImage,
1328 ctx->Convolution2D.Width,
1329 ctx->Convolution2D.Height,
1330 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1331 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001332 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1333 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001334 break;
1335 case GL_CONSTANT_BORDER:
1336 convolve_2d_constant(*width, *height,
1337 (const GLfloat (*)[4]) srcImage,
1338 ctx->Convolution2D.Width,
1339 ctx->Convolution2D.Height,
1340 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1341 (GLfloat (*)[4]) dstImage,
1342 ctx->Pixel.ConvolutionBorderColor[1]);
1343 break;
1344 case GL_REPLICATE_BORDER:
1345 convolve_2d_replicate(*width, *height,
1346 (const GLfloat (*)[4]) srcImage,
1347 ctx->Convolution2D.Width,
1348 ctx->Convolution2D.Height,
1349 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1350 (GLfloat (*)[4]) dstImage);
1351 break;
1352 default:
1353 ;
1354 }
1355}
1356
1357
1358void
1359_mesa_convolve_sep_image(const GLcontext *ctx,
1360 GLsizei *width, GLsizei *height,
1361 const GLfloat *srcImage, GLfloat *dstImage)
1362{
1363 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1364 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1365
1366 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1367 case GL_REDUCE:
1368 convolve_sep_reduce(*width, *height,
1369 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001370 ctx->Separable2D.Width,
1371 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001372 (const GLfloat (*)[4]) rowFilter,
1373 (const GLfloat (*)[4]) colFilter,
1374 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001375 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1376 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001377 break;
1378 case GL_CONSTANT_BORDER:
1379 convolve_sep_constant(*width, *height,
1380 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001381 ctx->Separable2D.Width,
1382 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001383 (const GLfloat (*)[4]) rowFilter,
1384 (const GLfloat (*)[4]) colFilter,
1385 (GLfloat (*)[4]) dstImage,
1386 ctx->Pixel.ConvolutionBorderColor[2]);
1387 break;
1388 case GL_REPLICATE_BORDER:
1389 convolve_sep_replicate(*width, *height,
1390 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001391 ctx->Separable2D.Width,
1392 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001393 (const GLfloat (*)[4]) rowFilter,
1394 (const GLfloat (*)[4]) colFilter,
1395 (GLfloat (*)[4]) dstImage);
1396 break;
1397 default:
1398 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001399 }
1400}