1641f497d873d46f4b678346f1ba004f6f0990a6
[mesa.git] / src / mesa / main / convolve.c
1 /* $Id: convolve.c,v 1.12 2000/11/21 23:01:22 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
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"
40 #include "colormac.h"
41 #include "convolve.h"
42 #include "context.h"
43 #include "image.h"
44 #include "types.h"
45 #include "swrast/s_span.h" /* XXX SWRAST hack */
46 #endif
47
48
49 /*
50 * Given an internalFormat token passed to glConvolutionFilter
51 * or glSeparableFilter, return the corresponding base format.
52 * Return -1 if invalid token.
53 */
54 static GLint
55 base_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
109 void
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 ctx->NewState |= _NEW_PIXEL;
175 }
176
177
178 void
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 }
253
254 ctx->NewState |= _NEW_PIXEL;
255 }
256
257
258 void
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 }
297
298 ctx->NewState |= _NEW_PIXEL;
299 }
300
301
302 void
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 }
354
355 ctx->NewState |= _NEW_PIXEL;
356 }
357
358
359 void
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 }
398
399 ctx->NewState |= _NEW_PIXEL;
400 }
401
402
403 void
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 }
458
459 ctx->NewState |= _NEW_PIXEL;
460 }
461
462
463 void
464 _mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
465 {
466 GLenum baseFormat;
467 GLchan rgba[MAX_CONVOLUTION_WIDTH][4];
468 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 */
488 RENDER_START(ctx);
489 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
490 RENDER_FINISH(ctx);
491
492 /* store as convolution filter */
493 _mesa_ConvolutionFilter1D(target, internalFormat, width,
494 GL_RGBA, CHAN_TYPE, rgba);
495 }
496
497
498 void
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;
504 GLchan rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
505 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 */
529 RENDER_START(ctx);
530 for (i = 0; i < height; i++) {
531 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
532 (GLchan (*)[4]) rgba[i]);
533 }
534 RENDER_FINISH(ctx);
535
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;
549 ctx->NewState |= _NEW_PACKUNPACK;
550
551 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
552 GL_RGBA, CHAN_TYPE, rgba);
553
554 ctx->Unpack = packSave; /* restore pixel packing params */
555 ctx->NewState |= _NEW_PACKUNPACK;
556 }
557
558
559 void
560 _mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
561 {
562 const struct gl_convolution_attrib *filter;
563 GLint row;
564 GET_CURRENT_CONTEXT(ctx);
565 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
566
567 if (!_mesa_is_legal_format_and_type(format, type) ||
568 format == GL_COLOR_INDEX ||
569 format == GL_STENCIL_INDEX ||
570 format == GL_DEPTH_COMPONENT ||
571 format == GL_INTENSITY ||
572 type == GL_BITMAP) {
573 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
574 return;
575 }
576
577 switch (target) {
578 case GL_CONVOLUTION_1D:
579 filter = &(ctx->Convolution1D);
580 break;
581 case GL_CONVOLUTION_2D:
582 filter = &(ctx->Convolution2D);
583 break;
584 default:
585 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
586 return;
587 }
588
589 for (row = 0; row < filter->Height; row++) {
590 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
591 filter->Height, format, type,
592 0, row, 0);
593 const GLfloat *src = filter->Filter + row * filter->Width * 4;
594 _mesa_pack_float_rgba_span(ctx, filter->Width,
595 (const GLfloat (*)[4]) src,
596 format, type, dst, &ctx->Pack, 0);
597 }
598 }
599
600
601 void
602 _mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
603 {
604 GET_CURRENT_CONTEXT(ctx);
605 const struct gl_convolution_attrib *conv;
606 GLuint c;
607
608 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
609
610 switch (target) {
611 case GL_CONVOLUTION_1D:
612 c = 0;
613 conv = &ctx->Convolution1D;
614 break;
615 case GL_CONVOLUTION_2D:
616 c = 1;
617 conv = &ctx->Convolution2D;
618 break;
619 case GL_SEPARABLE_2D:
620 c = 2;
621 conv = &ctx->Separable2D;
622 break;
623 default:
624 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
625 return;
626 }
627
628 switch (pname) {
629 case GL_CONVOLUTION_BORDER_COLOR:
630 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
631 break;
632 case GL_CONVOLUTION_BORDER_MODE:
633 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
634 break;
635 case GL_CONVOLUTION_FILTER_SCALE:
636 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
637 break;
638 case GL_CONVOLUTION_FILTER_BIAS:
639 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
640 break;
641 case GL_CONVOLUTION_FORMAT:
642 *params = (GLfloat) conv->Format;
643 break;
644 case GL_CONVOLUTION_WIDTH:
645 *params = (GLfloat) conv->Width;
646 break;
647 case GL_CONVOLUTION_HEIGHT:
648 *params = (GLfloat) conv->Height;
649 break;
650 case GL_MAX_CONVOLUTION_WIDTH:
651 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
652 break;
653 case GL_MAX_CONVOLUTION_HEIGHT:
654 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
655 break;
656 default:
657 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
658 return;
659 }
660 }
661
662
663 void
664 _mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
665 {
666 GET_CURRENT_CONTEXT(ctx);
667 const struct gl_convolution_attrib *conv;
668 GLuint c;
669
670 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
671
672 switch (target) {
673 case GL_CONVOLUTION_1D:
674 c = 0;
675 conv = &ctx->Convolution1D;
676 break;
677 case GL_CONVOLUTION_2D:
678 c = 1;
679 conv = &ctx->Convolution2D;
680 break;
681 case GL_SEPARABLE_2D:
682 c = 2;
683 conv = &ctx->Separable2D;
684 break;
685 default:
686 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
687 return;
688 }
689
690 switch (pname) {
691 case GL_CONVOLUTION_BORDER_COLOR:
692 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
693 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
694 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
695 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
696 break;
697 case GL_CONVOLUTION_BORDER_MODE:
698 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
699 break;
700 case GL_CONVOLUTION_FILTER_SCALE:
701 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
702 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
703 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
704 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
705 break;
706 case GL_CONVOLUTION_FILTER_BIAS:
707 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
708 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
709 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
710 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
711 break;
712 case GL_CONVOLUTION_FORMAT:
713 *params = (GLint) conv->Format;
714 break;
715 case GL_CONVOLUTION_WIDTH:
716 *params = (GLint) conv->Width;
717 break;
718 case GL_CONVOLUTION_HEIGHT:
719 *params = (GLint) conv->Height;
720 break;
721 case GL_MAX_CONVOLUTION_WIDTH:
722 *params = (GLint) ctx->Const.MaxConvolutionWidth;
723 break;
724 case GL_MAX_CONVOLUTION_HEIGHT:
725 *params = (GLint) ctx->Const.MaxConvolutionHeight;
726 break;
727 default:
728 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
729 return;
730 }
731 }
732
733
734 void
735 _mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
736 {
737 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
738 const struct gl_convolution_attrib *filter;
739 GET_CURRENT_CONTEXT(ctx);
740 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
741
742 if (target != GL_SEPARABLE_2D) {
743 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
744 return;
745 }
746
747 if (!_mesa_is_legal_format_and_type(format, type) ||
748 format == GL_COLOR_INDEX ||
749 format == GL_STENCIL_INDEX ||
750 format == GL_DEPTH_COMPONENT ||
751 format == GL_INTENSITY ||
752 type == GL_BITMAP) {
753 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
754 return;
755 }
756
757 filter = &ctx->Separable2D;
758
759 /* Row filter */
760 {
761 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
762 filter->Height, format, type,
763 0, 0, 0);
764 _mesa_pack_float_rgba_span(ctx, filter->Width,
765 (const GLfloat (*)[4]) filter->Filter,
766 format, type, dst, &ctx->Pack, 0);
767 }
768
769 /* Column filter */
770 {
771 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
772 1, format, type,
773 0, 0, 0);
774 const GLfloat *src = filter->Filter + colStart;
775 _mesa_pack_float_rgba_span(ctx, filter->Height,
776 (const GLfloat (*)[4]) src,
777 format, type, dst, &ctx->Pack, 0);
778 }
779
780 (void) span; /* unused at this time */
781 }
782
783
784 void
785 _mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
786 {
787 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
788 GLenum baseFormat;
789 GET_CURRENT_CONTEXT(ctx);
790 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
791
792 if (target != GL_SEPARABLE_2D) {
793 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
794 return;
795 }
796
797 baseFormat = base_filter_format(internalFormat);
798 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
799 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
800 return;
801 }
802
803 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
804 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
805 return;
806 }
807 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
808 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
809 return;
810 }
811
812 if (!_mesa_is_legal_format_and_type(format, type) ||
813 format == GL_COLOR_INDEX ||
814 format == GL_STENCIL_INDEX ||
815 format == GL_DEPTH_COMPONENT ||
816 format == GL_INTENSITY ||
817 type == GL_BITMAP) {
818 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
819 return;
820 }
821
822 ctx->Separable2D.Format = format;
823 ctx->Separable2D.InternalFormat = internalFormat;
824 ctx->Separable2D.Width = width;
825 ctx->Separable2D.Height = height;
826
827 /* unpack row filter */
828 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
829 ctx->Separable2D.Filter,
830 format, type, row, &ctx->Unpack,
831 0, GL_FALSE);
832
833 /* apply scale and bias */
834 {
835 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
836 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
837 GLint i;
838 for (i = 0; i < width; i++) {
839 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
840 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
841 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
842 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
843 r = r * scale[0] + bias[0];
844 g = g * scale[1] + bias[1];
845 b = b * scale[2] + bias[2];
846 a = a * scale[3] + bias[3];
847 ctx->Separable2D.Filter[i * 4 + 0] = r;
848 ctx->Separable2D.Filter[i * 4 + 1] = g;
849 ctx->Separable2D.Filter[i * 4 + 2] = b;
850 ctx->Separable2D.Filter[i * 4 + 3] = a;
851 }
852 }
853
854 /* unpack column filter */
855 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
856 &ctx->Separable2D.Filter[colStart],
857 format, type, column, &ctx->Unpack,
858 0, GL_FALSE);
859
860 /* apply scale and bias */
861 {
862 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
863 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
864 GLint i;
865 for (i = 0; i < width; i++) {
866 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
867 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
868 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
869 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
870 r = r * scale[0] + bias[0];
871 g = g * scale[1] + bias[1];
872 b = b * scale[2] + bias[2];
873 a = a * scale[3] + bias[3];
874 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
875 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
876 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
877 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
878 }
879 }
880
881 ctx->NewState |= _NEW_PIXEL;
882 }
883
884
885 /**********************************************************************/
886 /*** image convolution functions ***/
887 /**********************************************************************/
888
889 static void
890 convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
891 GLint filterWidth, const GLfloat filter[][4],
892 GLfloat dest[][4])
893 {
894 GLint dstWidth;
895 GLint i, n;
896
897 if (filterWidth >= 1)
898 dstWidth = srcWidth - (filterWidth - 1);
899 else
900 dstWidth = srcWidth;
901
902 if (dstWidth <= 0)
903 return; /* null result */
904
905 for (i = 0; i < dstWidth; i++) {
906 GLfloat sumR = 0.0;
907 GLfloat sumG = 0.0;
908 GLfloat sumB = 0.0;
909 GLfloat sumA = 0.0;
910 for (n = 0; n < filterWidth; n++) {
911 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
912 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
913 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
914 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
915 }
916 dest[i][RCOMP] = sumR;
917 dest[i][GCOMP] = sumG;
918 dest[i][BCOMP] = sumB;
919 dest[i][ACOMP] = sumA;
920 }
921 }
922
923
924 static void
925 convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
926 GLint filterWidth, const GLfloat filter[][4],
927 GLfloat dest[][4],
928 const GLfloat borderColor[4])
929 {
930 const GLint halfFilterWidth = filterWidth / 2;
931 GLint i, n;
932
933 for (i = 0; i < srcWidth; i++) {
934 GLfloat sumR = 0.0;
935 GLfloat sumG = 0.0;
936 GLfloat sumB = 0.0;
937 GLfloat sumA = 0.0;
938 for (n = 0; n < filterWidth; n++) {
939 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
940 sumR += borderColor[RCOMP] * filter[n][RCOMP];
941 sumG += borderColor[GCOMP] * filter[n][GCOMP];
942 sumB += borderColor[BCOMP] * filter[n][BCOMP];
943 sumA += borderColor[ACOMP] * filter[n][ACOMP];
944 }
945 else {
946 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
947 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
948 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
949 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
950 }
951 }
952 dest[i][RCOMP] = sumR;
953 dest[i][GCOMP] = sumG;
954 dest[i][BCOMP] = sumB;
955 dest[i][ACOMP] = sumA;
956 }
957 }
958
959
960 static void
961 convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
962 GLint filterWidth, const GLfloat filter[][4],
963 GLfloat dest[][4])
964 {
965 const GLint halfFilterWidth = filterWidth / 2;
966 GLint i, n;
967
968 for (i = 0; i < srcWidth; i++) {
969 GLfloat sumR = 0.0;
970 GLfloat sumG = 0.0;
971 GLfloat sumB = 0.0;
972 GLfloat sumA = 0.0;
973 for (n = 0; n < filterWidth; n++) {
974 if (i + n < halfFilterWidth) {
975 sumR += src[0][RCOMP] * filter[n][RCOMP];
976 sumG += src[0][GCOMP] * filter[n][GCOMP];
977 sumB += src[0][BCOMP] * filter[n][BCOMP];
978 sumA += src[0][ACOMP] * filter[n][ACOMP];
979 }
980 else if (i + n - halfFilterWidth >= srcWidth) {
981 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
982 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
983 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
984 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
985 }
986 else {
987 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
988 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
989 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
990 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
991 }
992 }
993 dest[i][RCOMP] = sumR;
994 dest[i][GCOMP] = sumG;
995 dest[i][BCOMP] = sumB;
996 dest[i][ACOMP] = sumA;
997 }
998 }
999
1000
1001 static void
1002 convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1003 const GLfloat src[][4],
1004 GLint filterWidth, GLint filterHeight,
1005 const GLfloat filter[][4],
1006 GLfloat dest[][4])
1007 {
1008 GLint dstWidth, dstHeight;
1009 GLint i, j, n, m;
1010
1011 if (filterWidth >= 1)
1012 dstWidth = srcWidth - (filterWidth - 1);
1013 else
1014 dstWidth = srcWidth;
1015
1016 if (filterHeight >= 1)
1017 dstHeight = srcHeight - (filterHeight - 1);
1018 else
1019 dstHeight = srcHeight;
1020
1021 if (dstWidth <= 0 || dstHeight <= 0)
1022 return;
1023
1024 for (j = 0; j < dstHeight; j++) {
1025 for (i = 0; i < dstWidth; i++) {
1026 GLfloat sumR = 0.0;
1027 GLfloat sumG = 0.0;
1028 GLfloat sumB = 0.0;
1029 GLfloat sumA = 0.0;
1030 for (m = 0; m < filterHeight; m++) {
1031 for (n = 0; n < filterWidth; n++) {
1032 const GLint k = (j + m) * srcWidth + i + n;
1033 const GLint f = m * filterWidth + n;
1034 sumR += src[k][RCOMP] * filter[f][RCOMP];
1035 sumG += src[k][GCOMP] * filter[f][GCOMP];
1036 sumB += src[k][BCOMP] * filter[f][BCOMP];
1037 sumA += src[k][ACOMP] * filter[f][ACOMP];
1038 }
1039 }
1040 dest[j * dstWidth + i][RCOMP] = sumR;
1041 dest[j * dstWidth + i][GCOMP] = sumG;
1042 dest[j * dstWidth + i][BCOMP] = sumB;
1043 dest[j * dstWidth + i][ACOMP] = sumA;
1044 }
1045 }
1046 }
1047
1048
1049 static void
1050 convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1051 const GLfloat src[][4],
1052 GLint filterWidth, GLint filterHeight,
1053 const GLfloat filter[][4],
1054 GLfloat dest[][4],
1055 const GLfloat borderColor[4])
1056 {
1057 const GLint halfFilterWidth = filterWidth / 2;
1058 const GLint halfFilterHeight = filterHeight / 2;
1059 GLint i, j, n, m;
1060
1061 for (j = 0; j < srcHeight; j++) {
1062 for (i = 0; i < srcWidth; i++) {
1063 GLfloat sumR = 0.0;
1064 GLfloat sumG = 0.0;
1065 GLfloat sumB = 0.0;
1066 GLfloat sumA = 0.0;
1067 for (m = 0; m < filterHeight; m++) {
1068 for (n = 0; n < filterWidth; n++) {
1069 const GLint f = m * filterWidth + n;
1070 const GLint is = i + n - halfFilterWidth;
1071 const GLint js = j + m - halfFilterHeight;
1072 if (is < 0 || is >= srcWidth ||
1073 js < 0 || js >= srcHeight) {
1074 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1075 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1076 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1077 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1078 }
1079 else {
1080 const GLint k = js * srcWidth + is;
1081 sumR += src[k][RCOMP] * filter[f][RCOMP];
1082 sumG += src[k][GCOMP] * filter[f][GCOMP];
1083 sumB += src[k][BCOMP] * filter[f][BCOMP];
1084 sumA += src[k][ACOMP] * filter[f][ACOMP];
1085 }
1086 }
1087 }
1088 dest[j * srcWidth + i][RCOMP] = sumR;
1089 dest[j * srcWidth + i][GCOMP] = sumG;
1090 dest[j * srcWidth + i][BCOMP] = sumB;
1091 dest[j * srcWidth + i][ACOMP] = sumA;
1092 }
1093 }
1094 }
1095
1096
1097 static void
1098 convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1099 const GLfloat src[][4],
1100 GLint filterWidth, GLint filterHeight,
1101 const GLfloat filter[][4],
1102 GLfloat dest[][4])
1103 {
1104 const GLint halfFilterWidth = filterWidth / 2;
1105 const GLint halfFilterHeight = filterHeight / 2;
1106 GLint i, j, n, m;
1107
1108 for (j = 0; j < srcHeight; j++) {
1109 for (i = 0; i < srcWidth; i++) {
1110 GLfloat sumR = 0.0;
1111 GLfloat sumG = 0.0;
1112 GLfloat sumB = 0.0;
1113 GLfloat sumA = 0.0;
1114 for (m = 0; m < filterHeight; m++) {
1115 for (n = 0; n < filterWidth; n++) {
1116 const GLint f = m * filterWidth + n;
1117 GLint is = i + n - halfFilterWidth;
1118 GLint js = j + m - halfFilterHeight;
1119 GLint k;
1120 if (is < 0)
1121 is = 0;
1122 else if (is >= srcWidth)
1123 is = srcWidth - 1;
1124 if (js < 0)
1125 js = 0;
1126 else if (js >= srcHeight)
1127 js = srcHeight - 1;
1128 k = js * srcWidth + is;
1129 sumR += src[k][RCOMP] * filter[f][RCOMP];
1130 sumG += src[k][GCOMP] * filter[f][GCOMP];
1131 sumB += src[k][BCOMP] * filter[f][BCOMP];
1132 sumA += src[k][ACOMP] * filter[f][ACOMP];
1133 }
1134 }
1135 dest[j * srcWidth + i][RCOMP] = sumR;
1136 dest[j * srcWidth + i][GCOMP] = sumG;
1137 dest[j * srcWidth + i][BCOMP] = sumB;
1138 dest[j * srcWidth + i][ACOMP] = sumA;
1139 }
1140 }
1141 }
1142
1143
1144 static void
1145 convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1146 const GLfloat src[][4],
1147 GLint filterWidth, GLint filterHeight,
1148 const GLfloat rowFilt[][4],
1149 const GLfloat colFilt[][4],
1150 GLfloat dest[][4])
1151 {
1152 GLint dstWidth, dstHeight;
1153 GLint i, j, n, m;
1154
1155 if (filterWidth >= 1)
1156 dstWidth = srcWidth - (filterWidth - 1);
1157 else
1158 dstWidth = srcWidth;
1159
1160 if (filterHeight >= 1)
1161 dstHeight = srcHeight - (filterHeight - 1);
1162 else
1163 dstHeight = srcHeight;
1164
1165 if (dstWidth <= 0 || dstHeight <= 0)
1166 return;
1167
1168 for (j = 0; j < dstHeight; j++) {
1169 for (i = 0; i < dstWidth; i++) {
1170 GLfloat sumR = 0.0;
1171 GLfloat sumG = 0.0;
1172 GLfloat sumB = 0.0;
1173 GLfloat sumA = 0.0;
1174 for (m = 0; m < filterHeight; m++) {
1175 for (n = 0; n < filterWidth; n++) {
1176 GLint k = (j + m) * srcWidth + i + n;
1177 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1178 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1179 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1180 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1181 }
1182 }
1183 dest[j * dstWidth + i][RCOMP] = sumR;
1184 dest[j * dstWidth + i][GCOMP] = sumG;
1185 dest[j * dstWidth + i][BCOMP] = sumB;
1186 dest[j * dstWidth + i][ACOMP] = sumA;
1187 }
1188 }
1189 }
1190
1191
1192 static void
1193 convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1194 const GLfloat src[][4],
1195 GLint filterWidth, GLint filterHeight,
1196 const GLfloat rowFilt[][4],
1197 const GLfloat colFilt[][4],
1198 GLfloat dest[][4],
1199 const GLfloat borderColor[4])
1200 {
1201 const GLint halfFilterWidth = filterWidth / 2;
1202 const GLint halfFilterHeight = filterHeight / 2;
1203 GLint i, j, n, m;
1204
1205 for (j = 0; j < srcHeight; j++) {
1206 for (i = 0; i < srcWidth; i++) {
1207 GLfloat sumR = 0.0;
1208 GLfloat sumG = 0.0;
1209 GLfloat sumB = 0.0;
1210 GLfloat sumA = 0.0;
1211 for (m = 0; m < filterHeight; m++) {
1212 for (n = 0; n < filterWidth; n++) {
1213 const GLint is = i + n - halfFilterWidth;
1214 const GLint js = j + m - halfFilterHeight;
1215 if (is < 0 || is >= srcWidth ||
1216 js < 0 || js >= srcHeight) {
1217 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1218 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1219 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1220 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1221 }
1222 else {
1223 GLint k = js * srcWidth + is;
1224 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1225 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1226 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1227 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1228 }
1229
1230 }
1231 }
1232 dest[j * srcWidth + i][RCOMP] = sumR;
1233 dest[j * srcWidth + i][GCOMP] = sumG;
1234 dest[j * srcWidth + i][BCOMP] = sumB;
1235 dest[j * srcWidth + i][ACOMP] = sumA;
1236 }
1237 }
1238 }
1239
1240
1241 static void
1242 convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1243 const GLfloat src[][4],
1244 GLint filterWidth, GLint filterHeight,
1245 const GLfloat rowFilt[][4],
1246 const GLfloat colFilt[][4],
1247 GLfloat dest[][4])
1248 {
1249 const GLint halfFilterWidth = filterWidth / 2;
1250 const GLint halfFilterHeight = filterHeight / 2;
1251 GLint i, j, n, m;
1252
1253 for (j = 0; j < srcHeight; j++) {
1254 for (i = 0; i < srcWidth; i++) {
1255 GLfloat sumR = 0.0;
1256 GLfloat sumG = 0.0;
1257 GLfloat sumB = 0.0;
1258 GLfloat sumA = 0.0;
1259 for (m = 0; m < filterHeight; m++) {
1260 for (n = 0; n < filterWidth; n++) {
1261 GLint is = i + n - halfFilterWidth;
1262 GLint js = j + m - halfFilterHeight;
1263 GLint k;
1264 if (is < 0)
1265 is = 0;
1266 else if (is >= srcWidth)
1267 is = srcWidth - 1;
1268 if (js < 0)
1269 js = 0;
1270 else if (js >= srcHeight)
1271 js = srcHeight - 1;
1272 k = js * srcWidth + is;
1273 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1274 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1275 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1276 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1277 }
1278 }
1279 dest[j * srcWidth + i][RCOMP] = sumR;
1280 dest[j * srcWidth + i][GCOMP] = sumG;
1281 dest[j * srcWidth + i][BCOMP] = sumB;
1282 dest[j * srcWidth + i][ACOMP] = sumA;
1283 }
1284 }
1285 }
1286
1287
1288
1289 void
1290 _mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1291 const GLfloat *srcImage, GLfloat *dstImage)
1292 {
1293 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1294 case GL_REDUCE:
1295 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1296 ctx->Convolution1D.Width,
1297 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1298 (GLfloat (*)[4]) dstImage);
1299 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1300 break;
1301 case GL_CONSTANT_BORDER:
1302 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1303 ctx->Convolution1D.Width,
1304 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1305 (GLfloat (*)[4]) dstImage,
1306 ctx->Pixel.ConvolutionBorderColor[0]);
1307 break;
1308 case GL_REPLICATE_BORDER:
1309 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1310 ctx->Convolution1D.Width,
1311 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1312 (GLfloat (*)[4]) dstImage);
1313 break;
1314 default:
1315 ;
1316 }
1317 }
1318
1319
1320 void
1321 _mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1322 const GLfloat *srcImage, GLfloat *dstImage)
1323 {
1324 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1325 case GL_REDUCE:
1326 convolve_2d_reduce(*width, *height,
1327 (const GLfloat (*)[4]) srcImage,
1328 ctx->Convolution2D.Width,
1329 ctx->Convolution2D.Height,
1330 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1331 (GLfloat (*)[4]) dstImage);
1332 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1333 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1334 break;
1335 case GL_CONSTANT_BORDER:
1336 convolve_2d_constant(*width, *height,
1337 (const GLfloat (*)[4]) srcImage,
1338 ctx->Convolution2D.Width,
1339 ctx->Convolution2D.Height,
1340 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1341 (GLfloat (*)[4]) dstImage,
1342 ctx->Pixel.ConvolutionBorderColor[1]);
1343 break;
1344 case GL_REPLICATE_BORDER:
1345 convolve_2d_replicate(*width, *height,
1346 (const GLfloat (*)[4]) srcImage,
1347 ctx->Convolution2D.Width,
1348 ctx->Convolution2D.Height,
1349 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1350 (GLfloat (*)[4]) dstImage);
1351 break;
1352 default:
1353 ;
1354 }
1355 }
1356
1357
1358 void
1359 _mesa_convolve_sep_image(const GLcontext *ctx,
1360 GLsizei *width, GLsizei *height,
1361 const GLfloat *srcImage, GLfloat *dstImage)
1362 {
1363 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1364 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1365
1366 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1367 case GL_REDUCE:
1368 convolve_sep_reduce(*width, *height,
1369 (const GLfloat (*)[4]) srcImage,
1370 ctx->Separable2D.Width,
1371 ctx->Separable2D.Height,
1372 (const GLfloat (*)[4]) rowFilter,
1373 (const GLfloat (*)[4]) colFilter,
1374 (GLfloat (*)[4]) dstImage);
1375 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1376 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1377 break;
1378 case GL_CONSTANT_BORDER:
1379 convolve_sep_constant(*width, *height,
1380 (const GLfloat (*)[4]) srcImage,
1381 ctx->Separable2D.Width,
1382 ctx->Separable2D.Height,
1383 (const GLfloat (*)[4]) rowFilter,
1384 (const GLfloat (*)[4]) colFilter,
1385 (GLfloat (*)[4]) dstImage,
1386 ctx->Pixel.ConvolutionBorderColor[2]);
1387 break;
1388 case GL_REPLICATE_BORDER:
1389 convolve_sep_replicate(*width, *height,
1390 (const GLfloat (*)[4]) srcImage,
1391 ctx->Separable2D.Width,
1392 ctx->Separable2D.Height,
1393 (const GLfloat (*)[4]) rowFilter,
1394 (const GLfloat (*)[4]) colFilter,
1395 (GLfloat (*)[4]) dstImage);
1396 break;
1397 default:
1398 ;
1399 }
1400 }