blob: b32b3e73731d875a4a39376924b3841d6e9e1f86 [file] [log] [blame]
Brian Paulc893a012000-10-28 20:41:13 +00001/* $Id: convolve.c,v 1.7 2000/10/28 20:41: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"
44#include "span.h"
Brian Paulcc8e37f2000-07-12 13:00:09 +000045#include "types.h"
46#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 }
173}
174
175
176void
177_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
178{
179 GLenum baseFormat;
180 GLint i, components;
181 GET_CURRENT_CONTEXT(ctx);
182 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter2D");
183
184 if (target != GL_CONVOLUTION_2D) {
185 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
186 return;
187 }
188
189 baseFormat = base_filter_format(internalFormat);
190 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
191 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
192 return;
193 }
194
195 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
196 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
197 return;
198 }
199 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
200 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
201 return;
202 }
203
204 if (!_mesa_is_legal_format_and_type(format, type) ||
205 format == GL_COLOR_INDEX ||
206 format == GL_STENCIL_INDEX ||
207 format == GL_DEPTH_COMPONENT ||
208 format == GL_INTENSITY ||
209 type == GL_BITMAP) {
210 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
211 return;
212 }
213
214 components = _mesa_components_in_format(format);
215 assert(components > 0); /* this should have been caught earlier */
216
217 ctx->Convolution2D.Format = format;
218 ctx->Convolution2D.InternalFormat = internalFormat;
219 ctx->Convolution2D.Width = width;
220 ctx->Convolution2D.Height = height;
221
222 /* Unpack filter image. We always store filters in RGBA format. */
223 for (i = 0; i < height; i++) {
224 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
225 height, format, type, 0, i, 0);
226 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
227 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
228 format, type, src, &ctx->Unpack,
229 0, GL_FALSE);
230 }
231
232 /* apply scale and bias */
233 {
234 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
235 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
236 for (i = 0; i < width * height * 4; i++) {
237 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
238 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
239 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
240 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
241 r = r * scale[0] + bias[0];
242 g = g * scale[1] + bias[1];
243 b = b * scale[2] + bias[2];
244 a = a * scale[3] + bias[3];
245 ctx->Convolution2D.Filter[i * 4 + 0] = r;
246 ctx->Convolution2D.Filter[i * 4 + 1] = g;
247 ctx->Convolution2D.Filter[i * 4 + 2] = b;
248 ctx->Convolution2D.Filter[i * 4 + 3] = a;
249 }
250 }
251}
252
253
254void
255_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
256{
257 GET_CURRENT_CONTEXT(ctx);
258 GLuint c;
259
260 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterf");
261
262 switch (target) {
263 case GL_CONVOLUTION_1D:
264 c = 0;
265 break;
266 case GL_CONVOLUTION_2D:
267 c = 1;
268 break;
269 case GL_SEPARABLE_2D:
270 c = 2;
271 break;
272 default:
273 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
274 return;
275 }
276
277 switch (pname) {
278 case GL_CONVOLUTION_BORDER_MODE:
279 if (param == (GLfloat) GL_REDUCE ||
280 param == (GLfloat) GL_CONSTANT_BORDER ||
281 param == (GLfloat) GL_REPLICATE_BORDER) {
282 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
283 }
284 else {
285 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
286 return;
287 }
288 break;
289 default:
290 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
291 return;
292 }
293}
294
295
296void
297_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
298{
299 GET_CURRENT_CONTEXT(ctx);
300 struct gl_convolution_attrib *conv;
301 GLuint c;
302
303 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterfv");
304
305 switch (target) {
306 case GL_CONVOLUTION_1D:
307 c = 0;
308 conv = &ctx->Convolution1D;
309 break;
310 case GL_CONVOLUTION_2D:
311 c = 1;
312 conv = &ctx->Convolution2D;
313 break;
314 case GL_SEPARABLE_2D:
315 c = 2;
316 conv = &ctx->Separable2D;
317 break;
318 default:
319 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
320 return;
321 }
322
323 switch (pname) {
324 case GL_CONVOLUTION_BORDER_COLOR:
325 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
326 break;
327 case GL_CONVOLUTION_BORDER_MODE:
328 if (params[0] == (GLfloat) GL_REDUCE ||
329 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
330 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
331 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
332 }
333 else {
334 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
335 return;
336 }
337 break;
338 case GL_CONVOLUTION_FILTER_SCALE:
339 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
340 break;
341 case GL_CONVOLUTION_FILTER_BIAS:
342 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
343 break;
344 default:
345 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
346 return;
347 }
348}
349
350
351void
352_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
353{
354 GET_CURRENT_CONTEXT(ctx);
355 GLuint c;
356
357 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteri");
358
359 switch (target) {
360 case GL_CONVOLUTION_1D:
361 c = 0;
362 break;
363 case GL_CONVOLUTION_2D:
364 c = 1;
365 break;
366 case GL_SEPARABLE_2D:
367 c = 2;
368 break;
369 default:
370 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
371 return;
372 }
373
374 switch (pname) {
375 case GL_CONVOLUTION_BORDER_MODE:
376 if (param == (GLint) GL_REDUCE ||
377 param == (GLint) GL_CONSTANT_BORDER ||
378 param == (GLint) GL_REPLICATE_BORDER) {
379 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
380 }
381 else {
382 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
383 return;
384 }
385 break;
386 default:
387 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
388 return;
389 }
390}
391
392
393void
394_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
395{
396 GET_CURRENT_CONTEXT(ctx);
397 struct gl_convolution_attrib *conv;
398 GLuint c;
399
400 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteriv");
401
402 switch (target) {
403 case GL_CONVOLUTION_1D:
404 c = 0;
405 conv = &ctx->Convolution1D;
406 break;
407 case GL_CONVOLUTION_2D:
408 c = 1;
409 conv = &ctx->Convolution2D;
410 break;
411 case GL_SEPARABLE_2D:
412 c = 2;
413 conv = &ctx->Separable2D;
414 break;
415 default:
416 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
417 return;
418 }
419
420 switch (pname) {
421 case GL_CONVOLUTION_BORDER_COLOR:
422 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
423 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
424 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
425 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
426 break;
427 case GL_CONVOLUTION_BORDER_MODE:
428 if (params[0] == (GLint) GL_REDUCE ||
429 params[0] == (GLint) GL_CONSTANT_BORDER ||
430 params[0] == (GLint) GL_REPLICATE_BORDER) {
431 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
432 }
433 else {
434 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
435 return;
436 }
437 break;
438 case GL_CONVOLUTION_FILTER_SCALE:
439 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
440 break;
441 case GL_CONVOLUTION_FILTER_BIAS:
442 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
443 break;
444 default:
445 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
446 return;
447 }
448}
449
450
451void
452_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
453{
454 GLenum baseFormat;
455 GLfloat rgba[MAX_CONVOLUTION_WIDTH][4];
456 GET_CURRENT_CONTEXT(ctx);
457 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter1D");
458
459 if (target != GL_CONVOLUTION_1D) {
460 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
461 return;
462 }
463
464 baseFormat = base_filter_format(internalFormat);
465 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
466 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
467 return;
468 }
469
470 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
471 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
472 return;
473 }
474
475 /* read pixels from framebuffer */
Brian Paulba643a22000-10-28 18:34:48 +0000476 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000477
478 /* store as convolution filter */
479 _mesa_ConvolutionFilter1D(target, internalFormat, width,
480 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
481}
482
483
484void
485_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
486{
487 GLenum baseFormat;
488 GLint i;
489 struct gl_pixelstore_attrib packSave;
490 GLfloat rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
491 GET_CURRENT_CONTEXT(ctx);
492 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter2D");
493
494 if (target != GL_CONVOLUTION_2D) {
495 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
496 return;
497 }
498
499 baseFormat = base_filter_format(internalFormat);
500 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
501 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
502 return;
503 }
504
505 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
506 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
507 return;
508 }
509 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
510 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
511 return;
512 }
513
514 /* read pixels from framebuffer */
515 for (i = 0; i < height; i++) {
516 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
Brian Paulba643a22000-10-28 18:34:48 +0000517 (GLchan (*)[4]) rgba[i]);
Brian Paul147b0832000-08-23 14:31:25 +0000518 }
519
520 /*
521 * store as convolution filter
522 */
523 packSave = ctx->Unpack; /* save pixel packing params */
524
525 ctx->Unpack.Alignment = 1;
526 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
527 ctx->Unpack.SkipPixels = 0;
528 ctx->Unpack.SkipRows = 0;
529 ctx->Unpack.ImageHeight = 0;
530 ctx->Unpack.SkipImages = 0;
531 ctx->Unpack.SwapBytes = GL_FALSE;
532 ctx->Unpack.LsbFirst = GL_FALSE;
533
534 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
535 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
536
537 ctx->Unpack = packSave; /* restore pixel packing params */
538}
539
540
541void
542_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
543{
Brian Paulf75d6972000-09-05 20:28:56 +0000544 const struct gl_convolution_attrib *filter;
545 GLint row;
Brian Paul147b0832000-08-23 14:31:25 +0000546 GET_CURRENT_CONTEXT(ctx);
547 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
548
Brian Paul147b0832000-08-23 14:31:25 +0000549 if (!_mesa_is_legal_format_and_type(format, type) ||
550 format == GL_COLOR_INDEX ||
551 format == GL_STENCIL_INDEX ||
552 format == GL_DEPTH_COMPONENT ||
553 format == GL_INTENSITY ||
554 type == GL_BITMAP) {
555 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
556 return;
557 }
558
Brian Paulf75d6972000-09-05 20:28:56 +0000559 switch (target) {
560 case GL_CONVOLUTION_1D:
561 filter = &(ctx->Convolution1D);
562 break;
563 case GL_CONVOLUTION_2D:
564 filter = &(ctx->Convolution2D);
565 break;
566 default:
567 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
568 return;
569 }
570
571 for (row = 0; row < filter->Height; row++) {
572 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
573 filter->Height, format, type,
574 0, row, 0);
575 const GLfloat *src = filter->Filter + row * filter->Width * 4;
576 /* XXX apply transfer ops or not? */
577 _mesa_pack_float_rgba_span(ctx, filter->Width,
578 (const GLfloat (*)[4]) src,
579 format, type, dst, &ctx->Pack, 0);
580 }
Brian Paul147b0832000-08-23 14:31:25 +0000581}
582
583
584void
585_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
586{
587 GET_CURRENT_CONTEXT(ctx);
588 const struct gl_convolution_attrib *conv;
589 GLuint c;
590
591 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
592
593 switch (target) {
594 case GL_CONVOLUTION_1D:
595 c = 0;
596 conv = &ctx->Convolution1D;
597 break;
598 case GL_CONVOLUTION_2D:
599 c = 1;
600 conv = &ctx->Convolution2D;
601 break;
602 case GL_SEPARABLE_2D:
603 c = 2;
604 conv = &ctx->Separable2D;
605 break;
606 default:
607 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
608 return;
609 }
610
611 switch (pname) {
612 case GL_CONVOLUTION_BORDER_COLOR:
613 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
614 break;
615 case GL_CONVOLUTION_BORDER_MODE:
616 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
617 break;
618 case GL_CONVOLUTION_FILTER_SCALE:
619 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
620 break;
621 case GL_CONVOLUTION_FILTER_BIAS:
622 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
623 break;
624 case GL_CONVOLUTION_FORMAT:
625 *params = (GLfloat) conv->Format;
626 break;
627 case GL_CONVOLUTION_WIDTH:
628 *params = (GLfloat) conv->Width;
629 break;
630 case GL_CONVOLUTION_HEIGHT:
631 *params = (GLfloat) conv->Height;
632 break;
633 case GL_MAX_CONVOLUTION_WIDTH:
634 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
635 break;
636 case GL_MAX_CONVOLUTION_HEIGHT:
637 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
638 break;
639 default:
640 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
641 return;
642 }
643}
644
645
646void
647_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
648{
649 GET_CURRENT_CONTEXT(ctx);
650 const struct gl_convolution_attrib *conv;
651 GLuint c;
652
653 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
654
655 switch (target) {
656 case GL_CONVOLUTION_1D:
657 c = 0;
658 conv = &ctx->Convolution1D;
659 break;
660 case GL_CONVOLUTION_2D:
661 c = 1;
662 conv = &ctx->Convolution2D;
663 break;
664 case GL_SEPARABLE_2D:
665 c = 2;
666 conv = &ctx->Separable2D;
667 break;
668 default:
669 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
670 return;
671 }
672
673 switch (pname) {
674 case GL_CONVOLUTION_BORDER_COLOR:
675 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
676 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
677 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
678 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
679 break;
680 case GL_CONVOLUTION_BORDER_MODE:
681 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
682 break;
683 case GL_CONVOLUTION_FILTER_SCALE:
684 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
685 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
686 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
687 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
688 break;
689 case GL_CONVOLUTION_FILTER_BIAS:
690 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
691 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
692 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
693 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
694 break;
695 case GL_CONVOLUTION_FORMAT:
696 *params = (GLint) conv->Format;
697 break;
698 case GL_CONVOLUTION_WIDTH:
699 *params = (GLint) conv->Width;
700 break;
701 case GL_CONVOLUTION_HEIGHT:
702 *params = (GLint) conv->Height;
703 break;
704 case GL_MAX_CONVOLUTION_WIDTH:
705 *params = (GLint) ctx->Const.MaxConvolutionWidth;
706 break;
707 case GL_MAX_CONVOLUTION_HEIGHT:
708 *params = (GLint) ctx->Const.MaxConvolutionHeight;
709 break;
710 default:
711 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
712 return;
713 }
714}
715
716
717void
718_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
719{
Brian Paulf75d6972000-09-05 20:28:56 +0000720 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
721 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000722 GET_CURRENT_CONTEXT(ctx);
723 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
724
725 if (target != GL_SEPARABLE_2D) {
726 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
727 return;
728 }
729
730 if (!_mesa_is_legal_format_and_type(format, type) ||
731 format == GL_COLOR_INDEX ||
732 format == GL_STENCIL_INDEX ||
733 format == GL_DEPTH_COMPONENT ||
734 format == GL_INTENSITY ||
735 type == GL_BITMAP) {
736 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
737 return;
738 }
739
Brian Paulf75d6972000-09-05 20:28:56 +0000740 filter = &ctx->Separable2D;
741
742 /* Row filter */
743 {
744 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
745 filter->Height, format, type,
746 0, 0, 0);
747 _mesa_pack_float_rgba_span(ctx, filter->Width,
748 (const GLfloat (*)[4]) filter->Filter,
749 format, type, dst, &ctx->Pack, 0);
750 }
751
752 /* Column filter */
753 {
754 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
755 1, format, type,
756 0, 0, 0);
757 const GLfloat *src = filter->Filter + colStart;
758 _mesa_pack_float_rgba_span(ctx, filter->Height,
759 (const GLfloat (*)[4]) src,
760 format, type, dst, &ctx->Pack, 0);
761 }
762
763 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000764}
765
766
767void
768_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
769{
770 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
771 GLenum baseFormat;
772 GET_CURRENT_CONTEXT(ctx);
773 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
774
775 if (target != GL_SEPARABLE_2D) {
776 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
777 return;
778 }
779
780 baseFormat = base_filter_format(internalFormat);
781 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
782 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
783 return;
784 }
785
786 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
787 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
788 return;
789 }
790 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
791 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
792 return;
793 }
794
795 if (!_mesa_is_legal_format_and_type(format, type) ||
796 format == GL_COLOR_INDEX ||
797 format == GL_STENCIL_INDEX ||
798 format == GL_DEPTH_COMPONENT ||
799 format == GL_INTENSITY ||
800 type == GL_BITMAP) {
801 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
802 return;
803 }
804
805 ctx->Separable2D.Format = format;
806 ctx->Separable2D.InternalFormat = internalFormat;
807 ctx->Separable2D.Width = width;
808 ctx->Separable2D.Height = height;
809
810 /* unpack row filter */
811 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
812 ctx->Separable2D.Filter,
813 format, type, row, &ctx->Unpack,
814 0, GL_FALSE);
815
816 /* apply scale and bias */
817 {
818 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
819 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
820 GLint i;
821 for (i = 0; i < width; i++) {
822 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
823 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
824 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
825 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
826 r = r * scale[0] + bias[0];
827 g = g * scale[1] + bias[1];
828 b = b * scale[2] + bias[2];
829 a = a * scale[3] + bias[3];
830 ctx->Separable2D.Filter[i * 4 + 0] = r;
831 ctx->Separable2D.Filter[i * 4 + 1] = g;
832 ctx->Separable2D.Filter[i * 4 + 2] = b;
833 ctx->Separable2D.Filter[i * 4 + 3] = a;
834 }
835 }
836
837 /* unpack column filter */
838 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
839 &ctx->Separable2D.Filter[colStart],
840 format, type, column, &ctx->Unpack,
841 0, GL_FALSE);
842
843 /* apply scale and bias */
844 {
845 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
846 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
847 GLint i;
848 for (i = 0; i < width; i++) {
849 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
850 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
851 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
852 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
853 r = r * scale[0] + bias[0];
854 g = g * scale[1] + bias[1];
855 b = b * scale[2] + bias[2];
856 a = a * scale[3] + bias[3];
857 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
858 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
859 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
860 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
861 }
862 }
863}
864
865
866/**********************************************************************/
867/*** image convolution functions ***/
868/**********************************************************************/
869
Brian Pauld4b799b2000-08-21 14:24:30 +0000870static void
871convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
872 GLint filterWidth, const GLfloat filter[][4],
873 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000874{
Brian Paul7e708742000-08-22 18:54:25 +0000875 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000876 GLint i, n;
877
Brian Paul7e708742000-08-22 18:54:25 +0000878 if (filterWidth >= 1)
879 dstWidth = srcWidth - (filterWidth - 1);
880 else
881 dstWidth = srcWidth;
882
Brian Paulcc8e37f2000-07-12 13:00:09 +0000883 if (dstWidth <= 0)
884 return; /* null result */
885
886 for (i = 0; i < dstWidth; i++) {
887 GLfloat sumR = 0.0;
888 GLfloat sumG = 0.0;
889 GLfloat sumB = 0.0;
890 GLfloat sumA = 0.0;
891 for (n = 0; n < filterWidth; n++) {
892 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
893 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
894 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
895 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
896 }
897 dest[i][RCOMP] = sumR;
898 dest[i][GCOMP] = sumG;
899 dest[i][BCOMP] = sumB;
900 dest[i][ACOMP] = sumA;
901 }
902}
903
904
Brian Pauld4b799b2000-08-21 14:24:30 +0000905static void
906convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
907 GLint filterWidth, const GLfloat filter[][4],
908 GLfloat dest[][4],
909 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000910{
911 const GLint halfFilterWidth = filterWidth / 2;
912 GLint i, n;
913
914 for (i = 0; i < srcWidth; i++) {
915 GLfloat sumR = 0.0;
916 GLfloat sumG = 0.0;
917 GLfloat sumB = 0.0;
918 GLfloat sumA = 0.0;
919 for (n = 0; n < filterWidth; n++) {
920 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
921 sumR += borderColor[RCOMP] * filter[n][RCOMP];
922 sumG += borderColor[GCOMP] * filter[n][GCOMP];
923 sumB += borderColor[BCOMP] * filter[n][BCOMP];
924 sumA += borderColor[ACOMP] * filter[n][ACOMP];
925 }
926 else {
927 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
928 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
929 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
930 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
931 }
932 }
933 dest[i][RCOMP] = sumR;
934 dest[i][GCOMP] = sumG;
935 dest[i][BCOMP] = sumB;
936 dest[i][ACOMP] = sumA;
937 }
938}
939
940
Brian Pauld4b799b2000-08-21 14:24:30 +0000941static void
942convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
943 GLint filterWidth, const GLfloat filter[][4],
944 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000945{
946 const GLint halfFilterWidth = filterWidth / 2;
947 GLint i, n;
948
949 for (i = 0; i < srcWidth; i++) {
950 GLfloat sumR = 0.0;
951 GLfloat sumG = 0.0;
952 GLfloat sumB = 0.0;
953 GLfloat sumA = 0.0;
954 for (n = 0; n < filterWidth; n++) {
955 if (i + n < halfFilterWidth) {
956 sumR += src[0][RCOMP] * filter[n][RCOMP];
957 sumG += src[0][GCOMP] * filter[n][GCOMP];
958 sumB += src[0][BCOMP] * filter[n][BCOMP];
959 sumA += src[0][ACOMP] * filter[n][ACOMP];
960 }
961 else if (i + n - halfFilterWidth >= srcWidth) {
962 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
963 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
964 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
965 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
966 }
967 else {
968 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
969 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
970 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
971 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
972 }
973 }
974 dest[i][RCOMP] = sumR;
975 dest[i][GCOMP] = sumG;
976 dest[i][BCOMP] = sumB;
977 dest[i][ACOMP] = sumA;
978 }
979}
980
981
Brian Pauld4b799b2000-08-21 14:24:30 +0000982static void
983convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
984 const GLfloat src[][4],
985 GLint filterWidth, GLint filterHeight,
986 const GLfloat filter[][4],
987 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000988{
Brian Paul7e708742000-08-22 18:54:25 +0000989 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +0000990 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000991
Brian Paul7e708742000-08-22 18:54:25 +0000992 if (filterWidth >= 1)
993 dstWidth = srcWidth - (filterWidth - 1);
994 else
995 dstWidth = srcWidth;
996
997 if (filterHeight >= 1)
998 dstHeight = srcHeight - (filterHeight - 1);
999 else
1000 dstHeight = srcHeight;
1001
Brian Pauld4b799b2000-08-21 14:24:30 +00001002 if (dstWidth <= 0 || dstHeight <= 0)
1003 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001004
Brian Pauld4b799b2000-08-21 14:24:30 +00001005 for (j = 0; j < dstHeight; j++) {
1006 for (i = 0; i < dstWidth; i++) {
1007 GLfloat sumR = 0.0;
1008 GLfloat sumG = 0.0;
1009 GLfloat sumB = 0.0;
1010 GLfloat sumA = 0.0;
1011 for (m = 0; m < filterHeight; m++) {
1012 for (n = 0; n < filterWidth; n++) {
1013 const GLint k = (j + m) * srcWidth + i + n;
1014 const GLint f = m * filterWidth + n;
1015 sumR += src[k][RCOMP] * filter[f][RCOMP];
1016 sumG += src[k][GCOMP] * filter[f][GCOMP];
1017 sumB += src[k][BCOMP] * filter[f][BCOMP];
1018 sumA += src[k][ACOMP] * filter[f][ACOMP];
1019 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001020 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001021 dest[j * dstWidth + i][RCOMP] = sumR;
1022 dest[j * dstWidth + i][GCOMP] = sumG;
1023 dest[j * dstWidth + i][BCOMP] = sumB;
1024 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001025 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001026 }
1027}
1028
1029
Brian Pauld4b799b2000-08-21 14:24:30 +00001030static void
1031convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1032 const GLfloat src[][4],
1033 GLint filterWidth, GLint filterHeight,
1034 const GLfloat filter[][4],
1035 GLfloat dest[][4],
1036 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001037{
1038 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001039 const GLint halfFilterHeight = filterHeight / 2;
1040 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001041
Brian Pauld4b799b2000-08-21 14:24:30 +00001042 for (j = 0; j < srcHeight; j++) {
1043 for (i = 0; i < srcWidth; i++) {
1044 GLfloat sumR = 0.0;
1045 GLfloat sumG = 0.0;
1046 GLfloat sumB = 0.0;
1047 GLfloat sumA = 0.0;
1048 for (m = 0; m < filterHeight; m++) {
1049 for (n = 0; n < filterWidth; n++) {
1050 const GLint f = m * filterWidth + n;
1051 const GLint is = i + n - halfFilterWidth;
1052 const GLint js = j + m - halfFilterHeight;
1053 if (is < 0 || is >= srcWidth ||
1054 js < 0 || js >= srcHeight) {
1055 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1056 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1057 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1058 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1059 }
1060 else {
1061 const GLint k = js * srcWidth + is;
1062 sumR += src[k][RCOMP] * filter[f][RCOMP];
1063 sumG += src[k][GCOMP] * filter[f][GCOMP];
1064 sumB += src[k][BCOMP] * filter[f][BCOMP];
1065 sumA += src[k][ACOMP] * filter[f][ACOMP];
1066 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001067 }
1068 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001069 dest[j * srcWidth + i][RCOMP] = sumR;
1070 dest[j * srcWidth + i][GCOMP] = sumG;
1071 dest[j * srcWidth + i][BCOMP] = sumB;
1072 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001073 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001074 }
1075}
1076
1077
Brian Pauld4b799b2000-08-21 14:24:30 +00001078static void
1079convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1080 const GLfloat src[][4],
1081 GLint filterWidth, GLint filterHeight,
1082 const GLfloat filter[][4],
1083 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001084{
1085 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001086 const GLint halfFilterHeight = filterHeight / 2;
1087 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001088
Brian Pauld4b799b2000-08-21 14:24:30 +00001089 for (j = 0; j < srcHeight; j++) {
1090 for (i = 0; i < srcWidth; i++) {
1091 GLfloat sumR = 0.0;
1092 GLfloat sumG = 0.0;
1093 GLfloat sumB = 0.0;
1094 GLfloat sumA = 0.0;
1095 for (m = 0; m < filterHeight; m++) {
1096 for (n = 0; n < filterWidth; n++) {
1097 const GLint f = m * filterWidth + n;
1098 GLint is = i + n - halfFilterWidth;
1099 GLint js = j + m - halfFilterHeight;
1100 GLint k;
1101 if (is < 0)
1102 is = 0;
1103 else if (is >= srcWidth)
1104 is = srcWidth - 1;
1105 if (js < 0)
1106 js = 0;
1107 else if (js >= srcHeight)
1108 js = srcHeight - 1;
1109 k = js * srcWidth + is;
1110 sumR += src[k][RCOMP] * filter[f][RCOMP];
1111 sumG += src[k][GCOMP] * filter[f][GCOMP];
1112 sumB += src[k][BCOMP] * filter[f][BCOMP];
1113 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001114 }
1115 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001116 dest[j * srcWidth + i][RCOMP] = sumR;
1117 dest[j * srcWidth + i][GCOMP] = sumG;
1118 dest[j * srcWidth + i][BCOMP] = sumB;
1119 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001120 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001121 }
1122}
1123
1124
Brian Pauld4b799b2000-08-21 14:24:30 +00001125static void
1126convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1127 const GLfloat src[][4],
1128 GLint filterWidth, GLint filterHeight,
1129 const GLfloat rowFilt[][4],
1130 const GLfloat colFilt[][4],
1131 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001132{
Brian Paul7e708742000-08-22 18:54:25 +00001133 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001134 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001135
1136 if (filterWidth >= 1)
1137 dstWidth = srcWidth - (filterWidth - 1);
1138 else
1139 dstWidth = srcWidth;
1140
1141 if (filterHeight >= 1)
1142 dstHeight = srcHeight - (filterHeight - 1);
1143 else
1144 dstHeight = srcHeight;
1145
1146 if (dstWidth <= 0 || dstHeight <= 0)
1147 return;
1148
1149 for (j = 0; j < dstHeight; j++) {
1150 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001151 GLfloat sumR = 0.0;
1152 GLfloat sumG = 0.0;
1153 GLfloat sumB = 0.0;
1154 GLfloat sumA = 0.0;
1155 for (m = 0; m < filterHeight; m++) {
1156 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001157 GLint k = (j + m) * srcWidth + i + n;
1158 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1159 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1160 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1161 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001162 }
1163 }
Brian Paul7e708742000-08-22 18:54:25 +00001164 dest[j * dstWidth + i][RCOMP] = sumR;
1165 dest[j * dstWidth + i][GCOMP] = sumG;
1166 dest[j * dstWidth + i][BCOMP] = sumB;
1167 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001168 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001169 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001170}
1171
1172
Brian Pauld4b799b2000-08-21 14:24:30 +00001173static void
1174convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1175 const GLfloat src[][4],
1176 GLint filterWidth, GLint filterHeight,
1177 const GLfloat rowFilt[][4],
1178 const GLfloat colFilt[][4],
1179 GLfloat dest[][4],
1180 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001181{
1182 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001183 const GLint halfFilterHeight = filterHeight / 2;
1184 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001185
Brian Pauld4b799b2000-08-21 14:24:30 +00001186 for (j = 0; j < srcHeight; j++) {
1187 for (i = 0; i < srcWidth; i++) {
1188 GLfloat sumR = 0.0;
1189 GLfloat sumG = 0.0;
1190 GLfloat sumB = 0.0;
1191 GLfloat sumA = 0.0;
1192 for (m = 0; m < filterHeight; m++) {
1193 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001194 const GLint is = i + n - halfFilterWidth;
1195 const GLint js = j + m - halfFilterHeight;
1196 if (is < 0 || is >= srcWidth ||
1197 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001198 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1199 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1200 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1201 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1202 }
1203 else {
Brian Paul7e708742000-08-22 18:54:25 +00001204 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001205 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1206 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1207 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1208 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1209 }
Brian Paul7e708742000-08-22 18:54:25 +00001210
Brian Paulcc8e37f2000-07-12 13:00:09 +00001211 }
1212 }
Brian Paul7e708742000-08-22 18:54:25 +00001213 dest[j * srcWidth + i][RCOMP] = sumR;
1214 dest[j * srcWidth + i][GCOMP] = sumG;
1215 dest[j * srcWidth + i][BCOMP] = sumB;
1216 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001217 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001218 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001219}
1220
1221
1222static void
1223convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1224 const GLfloat src[][4],
1225 GLint filterWidth, GLint filterHeight,
1226 const GLfloat rowFilt[][4],
1227 const GLfloat colFilt[][4],
1228 GLfloat dest[][4])
1229{
1230 const GLint halfFilterWidth = filterWidth / 2;
1231 const GLint halfFilterHeight = filterHeight / 2;
1232 GLint i, j, n, m;
1233
1234 for (j = 0; j < srcHeight; j++) {
1235 for (i = 0; i < srcWidth; i++) {
1236 GLfloat sumR = 0.0;
1237 GLfloat sumG = 0.0;
1238 GLfloat sumB = 0.0;
1239 GLfloat sumA = 0.0;
1240 for (m = 0; m < filterHeight; m++) {
1241 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001242 GLint is = i + n - halfFilterWidth;
1243 GLint js = j + m - halfFilterHeight;
1244 GLint k;
1245 if (is < 0)
1246 is = 0;
1247 else if (is >= srcWidth)
1248 is = srcWidth - 1;
1249 if (js < 0)
1250 js = 0;
1251 else if (js >= srcHeight)
1252 js = srcHeight - 1;
1253 k = js * srcWidth + is;
1254 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1255 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1256 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1257 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001258 }
1259 }
Brian Paul7e708742000-08-22 18:54:25 +00001260 dest[j * srcWidth + i][RCOMP] = sumR;
1261 dest[j * srcWidth + i][GCOMP] = sumG;
1262 dest[j * srcWidth + i][BCOMP] = sumB;
1263 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001264 }
1265 }
1266}
1267
1268
1269
1270void
1271_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1272 const GLfloat *srcImage, GLfloat *dstImage)
1273{
1274 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1275 case GL_REDUCE:
1276 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1277 ctx->Convolution1D.Width,
1278 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1279 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001280 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001281 break;
1282 case GL_CONSTANT_BORDER:
1283 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1284 ctx->Convolution1D.Width,
1285 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1286 (GLfloat (*)[4]) dstImage,
1287 ctx->Pixel.ConvolutionBorderColor[0]);
1288 break;
1289 case GL_REPLICATE_BORDER:
1290 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1291 ctx->Convolution1D.Width,
1292 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1293 (GLfloat (*)[4]) dstImage);
1294 break;
1295 default:
1296 ;
1297 }
1298}
1299
1300
1301void
1302_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1303 const GLfloat *srcImage, GLfloat *dstImage)
1304{
1305 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1306 case GL_REDUCE:
1307 convolve_2d_reduce(*width, *height,
1308 (const GLfloat (*)[4]) srcImage,
1309 ctx->Convolution2D.Width,
1310 ctx->Convolution2D.Height,
1311 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1312 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001313 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1314 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001315 break;
1316 case GL_CONSTANT_BORDER:
1317 convolve_2d_constant(*width, *height,
1318 (const GLfloat (*)[4]) srcImage,
1319 ctx->Convolution2D.Width,
1320 ctx->Convolution2D.Height,
1321 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1322 (GLfloat (*)[4]) dstImage,
1323 ctx->Pixel.ConvolutionBorderColor[1]);
1324 break;
1325 case GL_REPLICATE_BORDER:
1326 convolve_2d_replicate(*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);
1332 break;
1333 default:
1334 ;
1335 }
1336}
1337
1338
1339void
1340_mesa_convolve_sep_image(const GLcontext *ctx,
1341 GLsizei *width, GLsizei *height,
1342 const GLfloat *srcImage, GLfloat *dstImage)
1343{
1344 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1345 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1346
1347 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1348 case GL_REDUCE:
1349 convolve_sep_reduce(*width, *height,
1350 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001351 ctx->Separable2D.Width,
1352 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001353 (const GLfloat (*)[4]) rowFilter,
1354 (const GLfloat (*)[4]) colFilter,
1355 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001356 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1357 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001358 break;
1359 case GL_CONSTANT_BORDER:
1360 convolve_sep_constant(*width, *height,
1361 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001362 ctx->Separable2D.Width,
1363 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001364 (const GLfloat (*)[4]) rowFilter,
1365 (const GLfloat (*)[4]) colFilter,
1366 (GLfloat (*)[4]) dstImage,
1367 ctx->Pixel.ConvolutionBorderColor[2]);
1368 break;
1369 case GL_REPLICATE_BORDER:
1370 convolve_sep_replicate(*width, *height,
1371 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001372 ctx->Separable2D.Width,
1373 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001374 (const GLfloat (*)[4]) rowFilter,
1375 (const GLfloat (*)[4]) colFilter,
1376 (GLfloat (*)[4]) dstImage);
1377 break;
1378 default:
1379 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001380 }
1381}