blob: 172afd3dd26e551eafe0329ce899645c13582fa0 [file] [log] [blame]
Brian Paul0c000ec2000-11-21 23:26:13 +00001/* $Id: convolve.c,v 1.13 2000/11/21 23:26:13 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 Paul0c000ec2000-11-21 23:26:13 +0000567 if (ctx->NewState) {
568 gl_update_state(ctx);
569 }
570
Brian Paul147b0832000-08-23 14:31:25 +0000571 if (!_mesa_is_legal_format_and_type(format, type) ||
572 format == GL_COLOR_INDEX ||
573 format == GL_STENCIL_INDEX ||
574 format == GL_DEPTH_COMPONENT ||
575 format == GL_INTENSITY ||
576 type == GL_BITMAP) {
577 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
578 return;
579 }
580
Brian Paulf75d6972000-09-05 20:28:56 +0000581 switch (target) {
582 case GL_CONVOLUTION_1D:
583 filter = &(ctx->Convolution1D);
584 break;
585 case GL_CONVOLUTION_2D:
586 filter = &(ctx->Convolution2D);
587 break;
588 default:
589 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
590 return;
591 }
592
593 for (row = 0; row < filter->Height; row++) {
594 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
595 filter->Height, format, type,
596 0, row, 0);
597 const GLfloat *src = filter->Filter + row * filter->Width * 4;
Brian Paulf75d6972000-09-05 20:28:56 +0000598 _mesa_pack_float_rgba_span(ctx, filter->Width,
599 (const GLfloat (*)[4]) src,
600 format, type, dst, &ctx->Pack, 0);
601 }
Brian Paul147b0832000-08-23 14:31:25 +0000602}
603
604
605void
606_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
607{
608 GET_CURRENT_CONTEXT(ctx);
609 const struct gl_convolution_attrib *conv;
610 GLuint c;
611
612 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
613
614 switch (target) {
615 case GL_CONVOLUTION_1D:
616 c = 0;
617 conv = &ctx->Convolution1D;
618 break;
619 case GL_CONVOLUTION_2D:
620 c = 1;
621 conv = &ctx->Convolution2D;
622 break;
623 case GL_SEPARABLE_2D:
624 c = 2;
625 conv = &ctx->Separable2D;
626 break;
627 default:
628 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
629 return;
630 }
631
632 switch (pname) {
633 case GL_CONVOLUTION_BORDER_COLOR:
634 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
635 break;
636 case GL_CONVOLUTION_BORDER_MODE:
637 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
638 break;
639 case GL_CONVOLUTION_FILTER_SCALE:
640 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
641 break;
642 case GL_CONVOLUTION_FILTER_BIAS:
643 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
644 break;
645 case GL_CONVOLUTION_FORMAT:
646 *params = (GLfloat) conv->Format;
647 break;
648 case GL_CONVOLUTION_WIDTH:
649 *params = (GLfloat) conv->Width;
650 break;
651 case GL_CONVOLUTION_HEIGHT:
652 *params = (GLfloat) conv->Height;
653 break;
654 case GL_MAX_CONVOLUTION_WIDTH:
655 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
656 break;
657 case GL_MAX_CONVOLUTION_HEIGHT:
658 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
659 break;
660 default:
661 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
662 return;
663 }
664}
665
666
667void
668_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
669{
670 GET_CURRENT_CONTEXT(ctx);
671 const struct gl_convolution_attrib *conv;
672 GLuint c;
673
674 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
675
676 switch (target) {
677 case GL_CONVOLUTION_1D:
678 c = 0;
679 conv = &ctx->Convolution1D;
680 break;
681 case GL_CONVOLUTION_2D:
682 c = 1;
683 conv = &ctx->Convolution2D;
684 break;
685 case GL_SEPARABLE_2D:
686 c = 2;
687 conv = &ctx->Separable2D;
688 break;
689 default:
690 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
691 return;
692 }
693
694 switch (pname) {
695 case GL_CONVOLUTION_BORDER_COLOR:
696 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
697 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
698 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
699 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
700 break;
701 case GL_CONVOLUTION_BORDER_MODE:
702 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
703 break;
704 case GL_CONVOLUTION_FILTER_SCALE:
705 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
706 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
707 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
708 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
709 break;
710 case GL_CONVOLUTION_FILTER_BIAS:
711 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
712 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
713 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
714 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
715 break;
716 case GL_CONVOLUTION_FORMAT:
717 *params = (GLint) conv->Format;
718 break;
719 case GL_CONVOLUTION_WIDTH:
720 *params = (GLint) conv->Width;
721 break;
722 case GL_CONVOLUTION_HEIGHT:
723 *params = (GLint) conv->Height;
724 break;
725 case GL_MAX_CONVOLUTION_WIDTH:
726 *params = (GLint) ctx->Const.MaxConvolutionWidth;
727 break;
728 case GL_MAX_CONVOLUTION_HEIGHT:
729 *params = (GLint) ctx->Const.MaxConvolutionHeight;
730 break;
731 default:
732 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
733 return;
734 }
735}
736
737
738void
739_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
740{
Brian Paulf75d6972000-09-05 20:28:56 +0000741 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
742 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000743 GET_CURRENT_CONTEXT(ctx);
744 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
745
Brian Paul0c000ec2000-11-21 23:26:13 +0000746 if (ctx->NewState) {
747 gl_update_state(ctx);
748 }
749
Brian Paul147b0832000-08-23 14:31:25 +0000750 if (target != GL_SEPARABLE_2D) {
751 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
752 return;
753 }
754
755 if (!_mesa_is_legal_format_and_type(format, type) ||
756 format == GL_COLOR_INDEX ||
757 format == GL_STENCIL_INDEX ||
758 format == GL_DEPTH_COMPONENT ||
759 format == GL_INTENSITY ||
760 type == GL_BITMAP) {
761 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
762 return;
763 }
764
Brian Paulf75d6972000-09-05 20:28:56 +0000765 filter = &ctx->Separable2D;
766
767 /* Row filter */
768 {
769 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
770 filter->Height, format, type,
771 0, 0, 0);
772 _mesa_pack_float_rgba_span(ctx, filter->Width,
773 (const GLfloat (*)[4]) filter->Filter,
774 format, type, dst, &ctx->Pack, 0);
775 }
776
777 /* Column filter */
778 {
779 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
780 1, format, type,
781 0, 0, 0);
782 const GLfloat *src = filter->Filter + colStart;
783 _mesa_pack_float_rgba_span(ctx, filter->Height,
784 (const GLfloat (*)[4]) src,
785 format, type, dst, &ctx->Pack, 0);
786 }
787
788 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000789}
790
791
792void
793_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
794{
795 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
796 GLenum baseFormat;
797 GET_CURRENT_CONTEXT(ctx);
798 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
799
800 if (target != GL_SEPARABLE_2D) {
801 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
802 return;
803 }
804
805 baseFormat = base_filter_format(internalFormat);
806 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
807 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
808 return;
809 }
810
811 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
812 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
813 return;
814 }
815 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
816 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
817 return;
818 }
819
820 if (!_mesa_is_legal_format_and_type(format, type) ||
821 format == GL_COLOR_INDEX ||
822 format == GL_STENCIL_INDEX ||
823 format == GL_DEPTH_COMPONENT ||
824 format == GL_INTENSITY ||
825 type == GL_BITMAP) {
826 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
827 return;
828 }
829
830 ctx->Separable2D.Format = format;
831 ctx->Separable2D.InternalFormat = internalFormat;
832 ctx->Separable2D.Width = width;
833 ctx->Separable2D.Height = height;
834
835 /* unpack row filter */
836 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
837 ctx->Separable2D.Filter,
838 format, type, row, &ctx->Unpack,
839 0, GL_FALSE);
840
841 /* apply scale and bias */
842 {
843 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
844 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
845 GLint i;
846 for (i = 0; i < width; i++) {
847 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
848 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
849 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
850 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
851 r = r * scale[0] + bias[0];
852 g = g * scale[1] + bias[1];
853 b = b * scale[2] + bias[2];
854 a = a * scale[3] + bias[3];
855 ctx->Separable2D.Filter[i * 4 + 0] = r;
856 ctx->Separable2D.Filter[i * 4 + 1] = g;
857 ctx->Separable2D.Filter[i * 4 + 2] = b;
858 ctx->Separable2D.Filter[i * 4 + 3] = a;
859 }
860 }
861
862 /* unpack column filter */
863 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
864 &ctx->Separable2D.Filter[colStart],
865 format, type, column, &ctx->Unpack,
866 0, GL_FALSE);
867
868 /* apply scale and bias */
869 {
870 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
871 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
872 GLint i;
873 for (i = 0; i < width; i++) {
874 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
875 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
876 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
877 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
878 r = r * scale[0] + bias[0];
879 g = g * scale[1] + bias[1];
880 b = b * scale[2] + bias[2];
881 a = a * scale[3] + bias[3];
882 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
883 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
884 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
885 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
886 }
887 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000888
Brian Paulb5012e12000-11-10 18:31:04 +0000889 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000890}
891
892
893/**********************************************************************/
894/*** image convolution functions ***/
895/**********************************************************************/
896
Brian Pauld4b799b2000-08-21 14:24:30 +0000897static void
898convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
899 GLint filterWidth, const GLfloat filter[][4],
900 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000901{
Brian Paul7e708742000-08-22 18:54:25 +0000902 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000903 GLint i, n;
904
Brian Paul7e708742000-08-22 18:54:25 +0000905 if (filterWidth >= 1)
906 dstWidth = srcWidth - (filterWidth - 1);
907 else
908 dstWidth = srcWidth;
909
Brian Paulcc8e37f2000-07-12 13:00:09 +0000910 if (dstWidth <= 0)
911 return; /* null result */
912
913 for (i = 0; i < dstWidth; i++) {
914 GLfloat sumR = 0.0;
915 GLfloat sumG = 0.0;
916 GLfloat sumB = 0.0;
917 GLfloat sumA = 0.0;
918 for (n = 0; n < filterWidth; n++) {
919 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
920 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
921 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
922 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
923 }
924 dest[i][RCOMP] = sumR;
925 dest[i][GCOMP] = sumG;
926 dest[i][BCOMP] = sumB;
927 dest[i][ACOMP] = sumA;
928 }
929}
930
931
Brian Pauld4b799b2000-08-21 14:24:30 +0000932static void
933convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
934 GLint filterWidth, const GLfloat filter[][4],
935 GLfloat dest[][4],
936 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000937{
938 const GLint halfFilterWidth = filterWidth / 2;
939 GLint i, n;
940
941 for (i = 0; i < srcWidth; i++) {
942 GLfloat sumR = 0.0;
943 GLfloat sumG = 0.0;
944 GLfloat sumB = 0.0;
945 GLfloat sumA = 0.0;
946 for (n = 0; n < filterWidth; n++) {
947 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
948 sumR += borderColor[RCOMP] * filter[n][RCOMP];
949 sumG += borderColor[GCOMP] * filter[n][GCOMP];
950 sumB += borderColor[BCOMP] * filter[n][BCOMP];
951 sumA += borderColor[ACOMP] * filter[n][ACOMP];
952 }
953 else {
954 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
955 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
956 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
957 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
958 }
959 }
960 dest[i][RCOMP] = sumR;
961 dest[i][GCOMP] = sumG;
962 dest[i][BCOMP] = sumB;
963 dest[i][ACOMP] = sumA;
964 }
965}
966
967
Brian Pauld4b799b2000-08-21 14:24:30 +0000968static void
969convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
970 GLint filterWidth, const GLfloat filter[][4],
971 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000972{
973 const GLint halfFilterWidth = filterWidth / 2;
974 GLint i, n;
975
976 for (i = 0; i < srcWidth; i++) {
977 GLfloat sumR = 0.0;
978 GLfloat sumG = 0.0;
979 GLfloat sumB = 0.0;
980 GLfloat sumA = 0.0;
981 for (n = 0; n < filterWidth; n++) {
982 if (i + n < halfFilterWidth) {
983 sumR += src[0][RCOMP] * filter[n][RCOMP];
984 sumG += src[0][GCOMP] * filter[n][GCOMP];
985 sumB += src[0][BCOMP] * filter[n][BCOMP];
986 sumA += src[0][ACOMP] * filter[n][ACOMP];
987 }
988 else if (i + n - halfFilterWidth >= srcWidth) {
989 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
990 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
991 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
992 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
993 }
994 else {
995 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
996 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
997 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
998 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
999 }
1000 }
1001 dest[i][RCOMP] = sumR;
1002 dest[i][GCOMP] = sumG;
1003 dest[i][BCOMP] = sumB;
1004 dest[i][ACOMP] = sumA;
1005 }
1006}
1007
1008
Brian Pauld4b799b2000-08-21 14:24:30 +00001009static void
1010convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1011 const GLfloat src[][4],
1012 GLint filterWidth, GLint filterHeight,
1013 const GLfloat filter[][4],
1014 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001015{
Brian Paul7e708742000-08-22 18:54:25 +00001016 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001017 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001018
Brian Paul7e708742000-08-22 18:54:25 +00001019 if (filterWidth >= 1)
1020 dstWidth = srcWidth - (filterWidth - 1);
1021 else
1022 dstWidth = srcWidth;
1023
1024 if (filterHeight >= 1)
1025 dstHeight = srcHeight - (filterHeight - 1);
1026 else
1027 dstHeight = srcHeight;
1028
Brian Pauld4b799b2000-08-21 14:24:30 +00001029 if (dstWidth <= 0 || dstHeight <= 0)
1030 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001031
Brian Pauld4b799b2000-08-21 14:24:30 +00001032 for (j = 0; j < dstHeight; j++) {
1033 for (i = 0; i < dstWidth; i++) {
1034 GLfloat sumR = 0.0;
1035 GLfloat sumG = 0.0;
1036 GLfloat sumB = 0.0;
1037 GLfloat sumA = 0.0;
1038 for (m = 0; m < filterHeight; m++) {
1039 for (n = 0; n < filterWidth; n++) {
1040 const GLint k = (j + m) * srcWidth + i + n;
1041 const GLint f = m * filterWidth + n;
1042 sumR += src[k][RCOMP] * filter[f][RCOMP];
1043 sumG += src[k][GCOMP] * filter[f][GCOMP];
1044 sumB += src[k][BCOMP] * filter[f][BCOMP];
1045 sumA += src[k][ACOMP] * filter[f][ACOMP];
1046 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001047 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001048 dest[j * dstWidth + i][RCOMP] = sumR;
1049 dest[j * dstWidth + i][GCOMP] = sumG;
1050 dest[j * dstWidth + i][BCOMP] = sumB;
1051 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001052 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001053 }
1054}
1055
1056
Brian Pauld4b799b2000-08-21 14:24:30 +00001057static void
1058convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1059 const GLfloat src[][4],
1060 GLint filterWidth, GLint filterHeight,
1061 const GLfloat filter[][4],
1062 GLfloat dest[][4],
1063 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001064{
1065 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001066 const GLint halfFilterHeight = filterHeight / 2;
1067 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001068
Brian Pauld4b799b2000-08-21 14:24:30 +00001069 for (j = 0; j < srcHeight; j++) {
1070 for (i = 0; i < srcWidth; i++) {
1071 GLfloat sumR = 0.0;
1072 GLfloat sumG = 0.0;
1073 GLfloat sumB = 0.0;
1074 GLfloat sumA = 0.0;
1075 for (m = 0; m < filterHeight; m++) {
1076 for (n = 0; n < filterWidth; n++) {
1077 const GLint f = m * filterWidth + n;
1078 const GLint is = i + n - halfFilterWidth;
1079 const GLint js = j + m - halfFilterHeight;
1080 if (is < 0 || is >= srcWidth ||
1081 js < 0 || js >= srcHeight) {
1082 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1083 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1084 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1085 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1086 }
1087 else {
1088 const GLint k = js * srcWidth + is;
1089 sumR += src[k][RCOMP] * filter[f][RCOMP];
1090 sumG += src[k][GCOMP] * filter[f][GCOMP];
1091 sumB += src[k][BCOMP] * filter[f][BCOMP];
1092 sumA += src[k][ACOMP] * filter[f][ACOMP];
1093 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001094 }
1095 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001096 dest[j * srcWidth + i][RCOMP] = sumR;
1097 dest[j * srcWidth + i][GCOMP] = sumG;
1098 dest[j * srcWidth + i][BCOMP] = sumB;
1099 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001100 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001101 }
1102}
1103
1104
Brian Pauld4b799b2000-08-21 14:24:30 +00001105static void
1106convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1107 const GLfloat src[][4],
1108 GLint filterWidth, GLint filterHeight,
1109 const GLfloat filter[][4],
1110 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001111{
1112 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001113 const GLint halfFilterHeight = filterHeight / 2;
1114 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001115
Brian Pauld4b799b2000-08-21 14:24:30 +00001116 for (j = 0; j < srcHeight; j++) {
1117 for (i = 0; i < srcWidth; i++) {
1118 GLfloat sumR = 0.0;
1119 GLfloat sumG = 0.0;
1120 GLfloat sumB = 0.0;
1121 GLfloat sumA = 0.0;
1122 for (m = 0; m < filterHeight; m++) {
1123 for (n = 0; n < filterWidth; n++) {
1124 const GLint f = m * filterWidth + n;
1125 GLint is = i + n - halfFilterWidth;
1126 GLint js = j + m - halfFilterHeight;
1127 GLint k;
1128 if (is < 0)
1129 is = 0;
1130 else if (is >= srcWidth)
1131 is = srcWidth - 1;
1132 if (js < 0)
1133 js = 0;
1134 else if (js >= srcHeight)
1135 js = srcHeight - 1;
1136 k = js * srcWidth + is;
1137 sumR += src[k][RCOMP] * filter[f][RCOMP];
1138 sumG += src[k][GCOMP] * filter[f][GCOMP];
1139 sumB += src[k][BCOMP] * filter[f][BCOMP];
1140 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001141 }
1142 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001143 dest[j * srcWidth + i][RCOMP] = sumR;
1144 dest[j * srcWidth + i][GCOMP] = sumG;
1145 dest[j * srcWidth + i][BCOMP] = sumB;
1146 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001147 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001148 }
1149}
1150
1151
Brian Pauld4b799b2000-08-21 14:24:30 +00001152static void
1153convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1154 const GLfloat src[][4],
1155 GLint filterWidth, GLint filterHeight,
1156 const GLfloat rowFilt[][4],
1157 const GLfloat colFilt[][4],
1158 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001159{
Brian Paul7e708742000-08-22 18:54:25 +00001160 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001161 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001162
1163 if (filterWidth >= 1)
1164 dstWidth = srcWidth - (filterWidth - 1);
1165 else
1166 dstWidth = srcWidth;
1167
1168 if (filterHeight >= 1)
1169 dstHeight = srcHeight - (filterHeight - 1);
1170 else
1171 dstHeight = srcHeight;
1172
1173 if (dstWidth <= 0 || dstHeight <= 0)
1174 return;
1175
1176 for (j = 0; j < dstHeight; j++) {
1177 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001178 GLfloat sumR = 0.0;
1179 GLfloat sumG = 0.0;
1180 GLfloat sumB = 0.0;
1181 GLfloat sumA = 0.0;
1182 for (m = 0; m < filterHeight; m++) {
1183 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001184 GLint k = (j + m) * srcWidth + i + n;
1185 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1186 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1187 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1188 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001189 }
1190 }
Brian Paul7e708742000-08-22 18:54:25 +00001191 dest[j * dstWidth + i][RCOMP] = sumR;
1192 dest[j * dstWidth + i][GCOMP] = sumG;
1193 dest[j * dstWidth + i][BCOMP] = sumB;
1194 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001195 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001196 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001197}
1198
1199
Brian Pauld4b799b2000-08-21 14:24:30 +00001200static void
1201convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1202 const GLfloat src[][4],
1203 GLint filterWidth, GLint filterHeight,
1204 const GLfloat rowFilt[][4],
1205 const GLfloat colFilt[][4],
1206 GLfloat dest[][4],
1207 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001208{
1209 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001210 const GLint halfFilterHeight = filterHeight / 2;
1211 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001212
Brian Pauld4b799b2000-08-21 14:24:30 +00001213 for (j = 0; j < srcHeight; j++) {
1214 for (i = 0; i < srcWidth; i++) {
1215 GLfloat sumR = 0.0;
1216 GLfloat sumG = 0.0;
1217 GLfloat sumB = 0.0;
1218 GLfloat sumA = 0.0;
1219 for (m = 0; m < filterHeight; m++) {
1220 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001221 const GLint is = i + n - halfFilterWidth;
1222 const GLint js = j + m - halfFilterHeight;
1223 if (is < 0 || is >= srcWidth ||
1224 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001225 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1226 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1227 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1228 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1229 }
1230 else {
Brian Paul7e708742000-08-22 18:54:25 +00001231 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001232 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1233 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1234 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1235 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1236 }
Brian Paul7e708742000-08-22 18:54:25 +00001237
Brian Paulcc8e37f2000-07-12 13:00:09 +00001238 }
1239 }
Brian Paul7e708742000-08-22 18:54:25 +00001240 dest[j * srcWidth + i][RCOMP] = sumR;
1241 dest[j * srcWidth + i][GCOMP] = sumG;
1242 dest[j * srcWidth + i][BCOMP] = sumB;
1243 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001244 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001245 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001246}
1247
1248
1249static void
1250convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1251 const GLfloat src[][4],
1252 GLint filterWidth, GLint filterHeight,
1253 const GLfloat rowFilt[][4],
1254 const GLfloat colFilt[][4],
1255 GLfloat dest[][4])
1256{
1257 const GLint halfFilterWidth = filterWidth / 2;
1258 const GLint halfFilterHeight = filterHeight / 2;
1259 GLint i, j, n, m;
1260
1261 for (j = 0; j < srcHeight; j++) {
1262 for (i = 0; i < srcWidth; i++) {
1263 GLfloat sumR = 0.0;
1264 GLfloat sumG = 0.0;
1265 GLfloat sumB = 0.0;
1266 GLfloat sumA = 0.0;
1267 for (m = 0; m < filterHeight; m++) {
1268 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001269 GLint is = i + n - halfFilterWidth;
1270 GLint js = j + m - halfFilterHeight;
1271 GLint k;
1272 if (is < 0)
1273 is = 0;
1274 else if (is >= srcWidth)
1275 is = srcWidth - 1;
1276 if (js < 0)
1277 js = 0;
1278 else if (js >= srcHeight)
1279 js = srcHeight - 1;
1280 k = js * srcWidth + is;
1281 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1282 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1283 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1284 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001285 }
1286 }
Brian Paul7e708742000-08-22 18:54:25 +00001287 dest[j * srcWidth + i][RCOMP] = sumR;
1288 dest[j * srcWidth + i][GCOMP] = sumG;
1289 dest[j * srcWidth + i][BCOMP] = sumB;
1290 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001291 }
1292 }
1293}
1294
1295
1296
1297void
1298_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1299 const GLfloat *srcImage, GLfloat *dstImage)
1300{
1301 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1302 case GL_REDUCE:
1303 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1304 ctx->Convolution1D.Width,
1305 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1306 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001307 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001308 break;
1309 case GL_CONSTANT_BORDER:
1310 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1311 ctx->Convolution1D.Width,
1312 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1313 (GLfloat (*)[4]) dstImage,
1314 ctx->Pixel.ConvolutionBorderColor[0]);
1315 break;
1316 case GL_REPLICATE_BORDER:
1317 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1318 ctx->Convolution1D.Width,
1319 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1320 (GLfloat (*)[4]) dstImage);
1321 break;
1322 default:
1323 ;
1324 }
1325}
1326
1327
1328void
1329_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1330 const GLfloat *srcImage, GLfloat *dstImage)
1331{
1332 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1333 case GL_REDUCE:
1334 convolve_2d_reduce(*width, *height,
1335 (const GLfloat (*)[4]) srcImage,
1336 ctx->Convolution2D.Width,
1337 ctx->Convolution2D.Height,
1338 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1339 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001340 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1341 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001342 break;
1343 case GL_CONSTANT_BORDER:
1344 convolve_2d_constant(*width, *height,
1345 (const GLfloat (*)[4]) srcImage,
1346 ctx->Convolution2D.Width,
1347 ctx->Convolution2D.Height,
1348 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1349 (GLfloat (*)[4]) dstImage,
1350 ctx->Pixel.ConvolutionBorderColor[1]);
1351 break;
1352 case GL_REPLICATE_BORDER:
1353 convolve_2d_replicate(*width, *height,
1354 (const GLfloat (*)[4]) srcImage,
1355 ctx->Convolution2D.Width,
1356 ctx->Convolution2D.Height,
1357 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1358 (GLfloat (*)[4]) dstImage);
1359 break;
1360 default:
1361 ;
1362 }
1363}
1364
1365
1366void
1367_mesa_convolve_sep_image(const GLcontext *ctx,
1368 GLsizei *width, GLsizei *height,
1369 const GLfloat *srcImage, GLfloat *dstImage)
1370{
1371 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1372 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1373
1374 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1375 case GL_REDUCE:
1376 convolve_sep_reduce(*width, *height,
1377 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001378 ctx->Separable2D.Width,
1379 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001380 (const GLfloat (*)[4]) rowFilter,
1381 (const GLfloat (*)[4]) colFilter,
1382 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001383 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1384 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001385 break;
1386 case GL_CONSTANT_BORDER:
1387 convolve_sep_constant(*width, *height,
1388 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001389 ctx->Separable2D.Width,
1390 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001391 (const GLfloat (*)[4]) rowFilter,
1392 (const GLfloat (*)[4]) colFilter,
1393 (GLfloat (*)[4]) dstImage,
1394 ctx->Pixel.ConvolutionBorderColor[2]);
1395 break;
1396 case GL_REPLICATE_BORDER:
1397 convolve_sep_replicate(*width, *height,
1398 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001399 ctx->Separable2D.Width,
1400 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001401 (const GLfloat (*)[4]) rowFilter,
1402 (const GLfloat (*)[4]) colFilter,
1403 (GLfloat (*)[4]) dstImage);
1404 break;
1405 default:
1406 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001407 }
1408}