More auto* build system updates
[mesa.git] / src / mesa / main / convolve.c
1 /* $Id: convolve.c,v 1.15 2000/11/23 02:50:56 jtaylor 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 "mtypes.h"
45 #include "state.h"
46 #include "swrast/s_span.h" /* XXX SWRAST hack */
47 #endif
48
49
50 /*
51 * Given an internalFormat token passed to glConvolutionFilter
52 * or glSeparableFilter, return the corresponding base format.
53 * Return -1 if invalid token.
54 */
55 static GLint
56 base_filter_format( GLenum format )
57 {
58 switch (format) {
59 case GL_ALPHA:
60 case GL_ALPHA4:
61 case GL_ALPHA8:
62 case GL_ALPHA12:
63 case GL_ALPHA16:
64 return GL_ALPHA;
65 case GL_LUMINANCE:
66 case GL_LUMINANCE4:
67 case GL_LUMINANCE8:
68 case GL_LUMINANCE12:
69 case GL_LUMINANCE16:
70 return GL_LUMINANCE;
71 case GL_LUMINANCE_ALPHA:
72 case GL_LUMINANCE4_ALPHA4:
73 case GL_LUMINANCE6_ALPHA2:
74 case GL_LUMINANCE8_ALPHA8:
75 case GL_LUMINANCE12_ALPHA4:
76 case GL_LUMINANCE12_ALPHA12:
77 case GL_LUMINANCE16_ALPHA16:
78 return GL_LUMINANCE_ALPHA;
79 case GL_INTENSITY:
80 case GL_INTENSITY4:
81 case GL_INTENSITY8:
82 case GL_INTENSITY12:
83 case GL_INTENSITY16:
84 return GL_INTENSITY;
85 case GL_RGB:
86 case GL_R3_G3_B2:
87 case GL_RGB4:
88 case GL_RGB5:
89 case GL_RGB8:
90 case GL_RGB10:
91 case GL_RGB12:
92 case GL_RGB16:
93 return GL_RGB;
94 case 4:
95 case GL_RGBA:
96 case GL_RGBA2:
97 case GL_RGBA4:
98 case GL_RGB5_A1:
99 case GL_RGBA8:
100 case GL_RGB10_A2:
101 case GL_RGBA12:
102 case GL_RGBA16:
103 return GL_RGBA;
104 default:
105 return -1; /* error */
106 }
107 }
108
109
110 void
111 _mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
112 {
113 GLenum baseFormat;
114 GET_CURRENT_CONTEXT(ctx);
115 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter1D");
116
117 if (target != GL_CONVOLUTION_1D) {
118 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
119 return;
120 }
121
122 baseFormat = base_filter_format(internalFormat);
123 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
124 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
125 return;
126 }
127
128 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
129 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
130 return;
131 }
132
133 if (!_mesa_is_legal_format_and_type(format, type) ||
134 format == GL_COLOR_INDEX ||
135 format == GL_STENCIL_INDEX ||
136 format == GL_DEPTH_COMPONENT ||
137 format == GL_INTENSITY ||
138 type == GL_BITMAP) {
139 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
140 return;
141 }
142
143 ctx->Convolution1D.Format = format;
144 ctx->Convolution1D.InternalFormat = internalFormat;
145 ctx->Convolution1D.Width = width;
146 ctx->Convolution1D.Height = 1;
147
148 /* unpack filter image */
149 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
150 ctx->Convolution1D.Filter,
151 format, type, image, &ctx->Unpack,
152 0, GL_FALSE);
153
154 /* apply scale and bias */
155 {
156 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
157 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
158 GLint i;
159 for (i = 0; i < width; i++) {
160 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
161 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
162 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
163 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
164 r = r * scale[0] + bias[0];
165 g = g * scale[1] + bias[1];
166 b = b * scale[2] + bias[2];
167 a = a * scale[3] + bias[3];
168 ctx->Convolution1D.Filter[i * 4 + 0] = r;
169 ctx->Convolution1D.Filter[i * 4 + 1] = g;
170 ctx->Convolution1D.Filter[i * 4 + 2] = b;
171 ctx->Convolution1D.Filter[i * 4 + 3] = a;
172 }
173 }
174
175 ctx->NewState |= _NEW_PIXEL;
176 }
177
178
179 void
180 _mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
181 {
182 GLenum baseFormat;
183 GLint i, components;
184 GET_CURRENT_CONTEXT(ctx);
185 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter2D");
186
187 if (target != GL_CONVOLUTION_2D) {
188 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
189 return;
190 }
191
192 baseFormat = base_filter_format(internalFormat);
193 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
194 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
195 return;
196 }
197
198 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
199 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
200 return;
201 }
202 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
203 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
204 return;
205 }
206
207 if (!_mesa_is_legal_format_and_type(format, type) ||
208 format == GL_COLOR_INDEX ||
209 format == GL_STENCIL_INDEX ||
210 format == GL_DEPTH_COMPONENT ||
211 format == GL_INTENSITY ||
212 type == GL_BITMAP) {
213 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
214 return;
215 }
216
217 components = _mesa_components_in_format(format);
218 assert(components > 0); /* this should have been caught earlier */
219
220 ctx->Convolution2D.Format = format;
221 ctx->Convolution2D.InternalFormat = internalFormat;
222 ctx->Convolution2D.Width = width;
223 ctx->Convolution2D.Height = height;
224
225 /* Unpack filter image. We always store filters in RGBA format. */
226 for (i = 0; i < height; i++) {
227 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
228 height, format, type, 0, i, 0);
229 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
230 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
231 format, type, src, &ctx->Unpack,
232 0, GL_FALSE);
233 }
234
235 /* apply scale and bias */
236 {
237 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
238 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
239 for (i = 0; i < width * height * 4; i++) {
240 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
241 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
242 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
243 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
244 r = r * scale[0] + bias[0];
245 g = g * scale[1] + bias[1];
246 b = b * scale[2] + bias[2];
247 a = a * scale[3] + bias[3];
248 ctx->Convolution2D.Filter[i * 4 + 0] = r;
249 ctx->Convolution2D.Filter[i * 4 + 1] = g;
250 ctx->Convolution2D.Filter[i * 4 + 2] = b;
251 ctx->Convolution2D.Filter[i * 4 + 3] = a;
252 }
253 }
254
255 ctx->NewState |= _NEW_PIXEL;
256 }
257
258
259 void
260 _mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
261 {
262 GET_CURRENT_CONTEXT(ctx);
263 GLuint c;
264
265 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterf");
266
267 switch (target) {
268 case GL_CONVOLUTION_1D:
269 c = 0;
270 break;
271 case GL_CONVOLUTION_2D:
272 c = 1;
273 break;
274 case GL_SEPARABLE_2D:
275 c = 2;
276 break;
277 default:
278 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
279 return;
280 }
281
282 switch (pname) {
283 case GL_CONVOLUTION_BORDER_MODE:
284 if (param == (GLfloat) GL_REDUCE ||
285 param == (GLfloat) GL_CONSTANT_BORDER ||
286 param == (GLfloat) GL_REPLICATE_BORDER) {
287 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
288 }
289 else {
290 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
291 return;
292 }
293 break;
294 default:
295 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
296 return;
297 }
298
299 ctx->NewState |= _NEW_PIXEL;
300 }
301
302
303 void
304 _mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
305 {
306 GET_CURRENT_CONTEXT(ctx);
307 struct gl_convolution_attrib *conv;
308 GLuint c;
309
310 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterfv");
311
312 switch (target) {
313 case GL_CONVOLUTION_1D:
314 c = 0;
315 conv = &ctx->Convolution1D;
316 break;
317 case GL_CONVOLUTION_2D:
318 c = 1;
319 conv = &ctx->Convolution2D;
320 break;
321 case GL_SEPARABLE_2D:
322 c = 2;
323 conv = &ctx->Separable2D;
324 break;
325 default:
326 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
327 return;
328 }
329
330 switch (pname) {
331 case GL_CONVOLUTION_BORDER_COLOR:
332 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
333 break;
334 case GL_CONVOLUTION_BORDER_MODE:
335 if (params[0] == (GLfloat) GL_REDUCE ||
336 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
337 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
338 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
339 }
340 else {
341 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
342 return;
343 }
344 break;
345 case GL_CONVOLUTION_FILTER_SCALE:
346 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
347 break;
348 case GL_CONVOLUTION_FILTER_BIAS:
349 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
350 break;
351 default:
352 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
353 return;
354 }
355
356 ctx->NewState |= _NEW_PIXEL;
357 }
358
359
360 void
361 _mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
362 {
363 GET_CURRENT_CONTEXT(ctx);
364 GLuint c;
365
366 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteri");
367
368 switch (target) {
369 case GL_CONVOLUTION_1D:
370 c = 0;
371 break;
372 case GL_CONVOLUTION_2D:
373 c = 1;
374 break;
375 case GL_SEPARABLE_2D:
376 c = 2;
377 break;
378 default:
379 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
380 return;
381 }
382
383 switch (pname) {
384 case GL_CONVOLUTION_BORDER_MODE:
385 if (param == (GLint) GL_REDUCE ||
386 param == (GLint) GL_CONSTANT_BORDER ||
387 param == (GLint) GL_REPLICATE_BORDER) {
388 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
389 }
390 else {
391 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
392 return;
393 }
394 break;
395 default:
396 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
397 return;
398 }
399
400 ctx->NewState |= _NEW_PIXEL;
401 }
402
403
404 void
405 _mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
406 {
407 GET_CURRENT_CONTEXT(ctx);
408 struct gl_convolution_attrib *conv;
409 GLuint c;
410
411 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteriv");
412
413 switch (target) {
414 case GL_CONVOLUTION_1D:
415 c = 0;
416 conv = &ctx->Convolution1D;
417 break;
418 case GL_CONVOLUTION_2D:
419 c = 1;
420 conv = &ctx->Convolution2D;
421 break;
422 case GL_SEPARABLE_2D:
423 c = 2;
424 conv = &ctx->Separable2D;
425 break;
426 default:
427 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
428 return;
429 }
430
431 switch (pname) {
432 case GL_CONVOLUTION_BORDER_COLOR:
433 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
434 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
435 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
436 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
437 break;
438 case GL_CONVOLUTION_BORDER_MODE:
439 if (params[0] == (GLint) GL_REDUCE ||
440 params[0] == (GLint) GL_CONSTANT_BORDER ||
441 params[0] == (GLint) GL_REPLICATE_BORDER) {
442 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
443 }
444 else {
445 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
446 return;
447 }
448 break;
449 case GL_CONVOLUTION_FILTER_SCALE:
450 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
451 break;
452 case GL_CONVOLUTION_FILTER_BIAS:
453 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
454 break;
455 default:
456 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
457 return;
458 }
459
460 ctx->NewState |= _NEW_PIXEL;
461 }
462
463
464 void
465 _mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
466 {
467 GLenum baseFormat;
468 GLchan rgba[MAX_CONVOLUTION_WIDTH][4];
469 GET_CURRENT_CONTEXT(ctx);
470 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter1D");
471
472 if (target != GL_CONVOLUTION_1D) {
473 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
474 return;
475 }
476
477 baseFormat = base_filter_format(internalFormat);
478 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
479 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
480 return;
481 }
482
483 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
484 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
485 return;
486 }
487
488 /* read pixels from framebuffer */
489 RENDER_START(ctx);
490 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
491 RENDER_FINISH(ctx);
492
493 /* store as convolution filter */
494 _mesa_ConvolutionFilter1D(target, internalFormat, width,
495 GL_RGBA, CHAN_TYPE, rgba);
496 }
497
498
499 void
500 _mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
501 {
502 GLenum baseFormat;
503 GLint i;
504 struct gl_pixelstore_attrib packSave;
505 GLchan rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
506 GET_CURRENT_CONTEXT(ctx);
507 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter2D");
508
509 if (target != GL_CONVOLUTION_2D) {
510 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
511 return;
512 }
513
514 baseFormat = base_filter_format(internalFormat);
515 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
516 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
517 return;
518 }
519
520 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
521 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
522 return;
523 }
524 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
525 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
526 return;
527 }
528
529 /* read pixels from framebuffer */
530 RENDER_START(ctx);
531 for (i = 0; i < height; i++) {
532 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
533 (GLchan (*)[4]) rgba[i]);
534 }
535 RENDER_FINISH(ctx);
536
537 /*
538 * store as convolution filter
539 */
540 packSave = ctx->Unpack; /* save pixel packing params */
541
542 ctx->Unpack.Alignment = 1;
543 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
544 ctx->Unpack.SkipPixels = 0;
545 ctx->Unpack.SkipRows = 0;
546 ctx->Unpack.ImageHeight = 0;
547 ctx->Unpack.SkipImages = 0;
548 ctx->Unpack.SwapBytes = GL_FALSE;
549 ctx->Unpack.LsbFirst = GL_FALSE;
550 ctx->NewState |= _NEW_PACKUNPACK;
551
552 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
553 GL_RGBA, CHAN_TYPE, rgba);
554
555 ctx->Unpack = packSave; /* restore pixel packing params */
556 ctx->NewState |= _NEW_PACKUNPACK;
557 }
558
559
560 void
561 _mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
562 {
563 const struct gl_convolution_attrib *filter;
564 GLint row;
565 GET_CURRENT_CONTEXT(ctx);
566 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
567
568 if (ctx->NewState) {
569 gl_update_state(ctx);
570 }
571
572 if (!_mesa_is_legal_format_and_type(format, type) ||
573 format == GL_COLOR_INDEX ||
574 format == GL_STENCIL_INDEX ||
575 format == GL_DEPTH_COMPONENT ||
576 format == GL_INTENSITY ||
577 type == GL_BITMAP) {
578 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
579 return;
580 }
581
582 switch (target) {
583 case GL_CONVOLUTION_1D:
584 filter = &(ctx->Convolution1D);
585 break;
586 case GL_CONVOLUTION_2D:
587 filter = &(ctx->Convolution2D);
588 break;
589 default:
590 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
591 return;
592 }
593
594 for (row = 0; row < filter->Height; row++) {
595 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
596 filter->Height, format, type,
597 0, row, 0);
598 const GLfloat *src = filter->Filter + row * filter->Width * 4;
599 _mesa_pack_float_rgba_span(ctx, filter->Width,
600 (const GLfloat (*)[4]) src,
601 format, type, dst, &ctx->Pack, 0);
602 }
603 }
604
605
606 void
607 _mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
608 {
609 GET_CURRENT_CONTEXT(ctx);
610 const struct gl_convolution_attrib *conv;
611 GLuint c;
612
613 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
614
615 switch (target) {
616 case GL_CONVOLUTION_1D:
617 c = 0;
618 conv = &ctx->Convolution1D;
619 break;
620 case GL_CONVOLUTION_2D:
621 c = 1;
622 conv = &ctx->Convolution2D;
623 break;
624 case GL_SEPARABLE_2D:
625 c = 2;
626 conv = &ctx->Separable2D;
627 break;
628 default:
629 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
630 return;
631 }
632
633 switch (pname) {
634 case GL_CONVOLUTION_BORDER_COLOR:
635 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
636 break;
637 case GL_CONVOLUTION_BORDER_MODE:
638 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
639 break;
640 case GL_CONVOLUTION_FILTER_SCALE:
641 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
642 break;
643 case GL_CONVOLUTION_FILTER_BIAS:
644 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
645 break;
646 case GL_CONVOLUTION_FORMAT:
647 *params = (GLfloat) conv->Format;
648 break;
649 case GL_CONVOLUTION_WIDTH:
650 *params = (GLfloat) conv->Width;
651 break;
652 case GL_CONVOLUTION_HEIGHT:
653 *params = (GLfloat) conv->Height;
654 break;
655 case GL_MAX_CONVOLUTION_WIDTH:
656 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
657 break;
658 case GL_MAX_CONVOLUTION_HEIGHT:
659 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
660 break;
661 default:
662 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
663 return;
664 }
665 }
666
667
668 void
669 _mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
670 {
671 GET_CURRENT_CONTEXT(ctx);
672 const struct gl_convolution_attrib *conv;
673 GLuint c;
674
675 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
676
677 switch (target) {
678 case GL_CONVOLUTION_1D:
679 c = 0;
680 conv = &ctx->Convolution1D;
681 break;
682 case GL_CONVOLUTION_2D:
683 c = 1;
684 conv = &ctx->Convolution2D;
685 break;
686 case GL_SEPARABLE_2D:
687 c = 2;
688 conv = &ctx->Separable2D;
689 break;
690 default:
691 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
692 return;
693 }
694
695 switch (pname) {
696 case GL_CONVOLUTION_BORDER_COLOR:
697 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
698 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
699 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
700 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
701 break;
702 case GL_CONVOLUTION_BORDER_MODE:
703 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
704 break;
705 case GL_CONVOLUTION_FILTER_SCALE:
706 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
707 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
708 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
709 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
710 break;
711 case GL_CONVOLUTION_FILTER_BIAS:
712 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
713 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
714 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
715 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
716 break;
717 case GL_CONVOLUTION_FORMAT:
718 *params = (GLint) conv->Format;
719 break;
720 case GL_CONVOLUTION_WIDTH:
721 *params = (GLint) conv->Width;
722 break;
723 case GL_CONVOLUTION_HEIGHT:
724 *params = (GLint) conv->Height;
725 break;
726 case GL_MAX_CONVOLUTION_WIDTH:
727 *params = (GLint) ctx->Const.MaxConvolutionWidth;
728 break;
729 case GL_MAX_CONVOLUTION_HEIGHT:
730 *params = (GLint) ctx->Const.MaxConvolutionHeight;
731 break;
732 default:
733 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
734 return;
735 }
736 }
737
738
739 void
740 _mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
741 {
742 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
743 const struct gl_convolution_attrib *filter;
744 GET_CURRENT_CONTEXT(ctx);
745 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
746
747 if (ctx->NewState) {
748 gl_update_state(ctx);
749 }
750
751 if (target != GL_SEPARABLE_2D) {
752 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
753 return;
754 }
755
756 if (!_mesa_is_legal_format_and_type(format, type) ||
757 format == GL_COLOR_INDEX ||
758 format == GL_STENCIL_INDEX ||
759 format == GL_DEPTH_COMPONENT ||
760 format == GL_INTENSITY ||
761 type == GL_BITMAP) {
762 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
763 return;
764 }
765
766 filter = &ctx->Separable2D;
767
768 /* Row filter */
769 {
770 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
771 filter->Height, format, type,
772 0, 0, 0);
773 _mesa_pack_float_rgba_span(ctx, filter->Width,
774 (const GLfloat (*)[4]) filter->Filter,
775 format, type, dst, &ctx->Pack, 0);
776 }
777
778 /* Column filter */
779 {
780 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
781 1, format, type,
782 0, 0, 0);
783 const GLfloat *src = filter->Filter + colStart;
784 _mesa_pack_float_rgba_span(ctx, filter->Height,
785 (const GLfloat (*)[4]) src,
786 format, type, dst, &ctx->Pack, 0);
787 }
788
789 (void) span; /* unused at this time */
790 }
791
792
793 void
794 _mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
795 {
796 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
797 GLenum baseFormat;
798 GET_CURRENT_CONTEXT(ctx);
799 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
800
801 if (target != GL_SEPARABLE_2D) {
802 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
803 return;
804 }
805
806 baseFormat = base_filter_format(internalFormat);
807 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
808 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
809 return;
810 }
811
812 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
813 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
814 return;
815 }
816 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
817 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
818 return;
819 }
820
821 if (!_mesa_is_legal_format_and_type(format, type) ||
822 format == GL_COLOR_INDEX ||
823 format == GL_STENCIL_INDEX ||
824 format == GL_DEPTH_COMPONENT ||
825 format == GL_INTENSITY ||
826 type == GL_BITMAP) {
827 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
828 return;
829 }
830
831 ctx->Separable2D.Format = format;
832 ctx->Separable2D.InternalFormat = internalFormat;
833 ctx->Separable2D.Width = width;
834 ctx->Separable2D.Height = height;
835
836 /* unpack row filter */
837 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
838 ctx->Separable2D.Filter,
839 format, type, row, &ctx->Unpack,
840 0, GL_FALSE);
841
842 /* apply scale and bias */
843 {
844 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
845 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
846 GLint i;
847 for (i = 0; i < width; i++) {
848 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
849 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
850 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
851 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
852 r = r * scale[0] + bias[0];
853 g = g * scale[1] + bias[1];
854 b = b * scale[2] + bias[2];
855 a = a * scale[3] + bias[3];
856 ctx->Separable2D.Filter[i * 4 + 0] = r;
857 ctx->Separable2D.Filter[i * 4 + 1] = g;
858 ctx->Separable2D.Filter[i * 4 + 2] = b;
859 ctx->Separable2D.Filter[i * 4 + 3] = a;
860 }
861 }
862
863 /* unpack column filter */
864 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
865 &ctx->Separable2D.Filter[colStart],
866 format, type, column, &ctx->Unpack,
867 0, GL_FALSE);
868
869 /* apply scale and bias */
870 {
871 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
872 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
873 GLint i;
874 for (i = 0; i < width; i++) {
875 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
876 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
877 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
878 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
879 r = r * scale[0] + bias[0];
880 g = g * scale[1] + bias[1];
881 b = b * scale[2] + bias[2];
882 a = a * scale[3] + bias[3];
883 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
884 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
885 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
886 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
887 }
888 }
889
890 ctx->NewState |= _NEW_PIXEL;
891 }
892
893
894 /**********************************************************************/
895 /*** image convolution functions ***/
896 /**********************************************************************/
897
898 static void
899 convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
900 GLint filterWidth, const GLfloat filter[][4],
901 GLfloat dest[][4])
902 {
903 GLint dstWidth;
904 GLint i, n;
905
906 if (filterWidth >= 1)
907 dstWidth = srcWidth - (filterWidth - 1);
908 else
909 dstWidth = srcWidth;
910
911 if (dstWidth <= 0)
912 return; /* null result */
913
914 for (i = 0; i < dstWidth; 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 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
921 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
922 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
923 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
924 }
925 dest[i][RCOMP] = sumR;
926 dest[i][GCOMP] = sumG;
927 dest[i][BCOMP] = sumB;
928 dest[i][ACOMP] = sumA;
929 }
930 }
931
932
933 static void
934 convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
935 GLint filterWidth, const GLfloat filter[][4],
936 GLfloat dest[][4],
937 const GLfloat borderColor[4])
938 {
939 const GLint halfFilterWidth = filterWidth / 2;
940 GLint i, n;
941
942 for (i = 0; i < srcWidth; i++) {
943 GLfloat sumR = 0.0;
944 GLfloat sumG = 0.0;
945 GLfloat sumB = 0.0;
946 GLfloat sumA = 0.0;
947 for (n = 0; n < filterWidth; n++) {
948 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
949 sumR += borderColor[RCOMP] * filter[n][RCOMP];
950 sumG += borderColor[GCOMP] * filter[n][GCOMP];
951 sumB += borderColor[BCOMP] * filter[n][BCOMP];
952 sumA += borderColor[ACOMP] * filter[n][ACOMP];
953 }
954 else {
955 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
956 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
957 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
958 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
959 }
960 }
961 dest[i][RCOMP] = sumR;
962 dest[i][GCOMP] = sumG;
963 dest[i][BCOMP] = sumB;
964 dest[i][ACOMP] = sumA;
965 }
966 }
967
968
969 static void
970 convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
971 GLint filterWidth, const GLfloat filter[][4],
972 GLfloat dest[][4])
973 {
974 const GLint halfFilterWidth = filterWidth / 2;
975 GLint i, n;
976
977 for (i = 0; i < srcWidth; i++) {
978 GLfloat sumR = 0.0;
979 GLfloat sumG = 0.0;
980 GLfloat sumB = 0.0;
981 GLfloat sumA = 0.0;
982 for (n = 0; n < filterWidth; n++) {
983 if (i + n < halfFilterWidth) {
984 sumR += src[0][RCOMP] * filter[n][RCOMP];
985 sumG += src[0][GCOMP] * filter[n][GCOMP];
986 sumB += src[0][BCOMP] * filter[n][BCOMP];
987 sumA += src[0][ACOMP] * filter[n][ACOMP];
988 }
989 else if (i + n - halfFilterWidth >= srcWidth) {
990 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
991 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
992 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
993 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
994 }
995 else {
996 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
997 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
998 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
999 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
1000 }
1001 }
1002 dest[i][RCOMP] = sumR;
1003 dest[i][GCOMP] = sumG;
1004 dest[i][BCOMP] = sumB;
1005 dest[i][ACOMP] = sumA;
1006 }
1007 }
1008
1009
1010 static void
1011 convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1012 const GLfloat src[][4],
1013 GLint filterWidth, GLint filterHeight,
1014 const GLfloat filter[][4],
1015 GLfloat dest[][4])
1016 {
1017 GLint dstWidth, dstHeight;
1018 GLint i, j, n, m;
1019
1020 if (filterWidth >= 1)
1021 dstWidth = srcWidth - (filterWidth - 1);
1022 else
1023 dstWidth = srcWidth;
1024
1025 if (filterHeight >= 1)
1026 dstHeight = srcHeight - (filterHeight - 1);
1027 else
1028 dstHeight = srcHeight;
1029
1030 if (dstWidth <= 0 || dstHeight <= 0)
1031 return;
1032
1033 for (j = 0; j < dstHeight; j++) {
1034 for (i = 0; i < dstWidth; i++) {
1035 GLfloat sumR = 0.0;
1036 GLfloat sumG = 0.0;
1037 GLfloat sumB = 0.0;
1038 GLfloat sumA = 0.0;
1039 for (m = 0; m < filterHeight; m++) {
1040 for (n = 0; n < filterWidth; n++) {
1041 const GLint k = (j + m) * srcWidth + i + n;
1042 const GLint f = m * filterWidth + n;
1043 sumR += src[k][RCOMP] * filter[f][RCOMP];
1044 sumG += src[k][GCOMP] * filter[f][GCOMP];
1045 sumB += src[k][BCOMP] * filter[f][BCOMP];
1046 sumA += src[k][ACOMP] * filter[f][ACOMP];
1047 }
1048 }
1049 dest[j * dstWidth + i][RCOMP] = sumR;
1050 dest[j * dstWidth + i][GCOMP] = sumG;
1051 dest[j * dstWidth + i][BCOMP] = sumB;
1052 dest[j * dstWidth + i][ACOMP] = sumA;
1053 }
1054 }
1055 }
1056
1057
1058 static void
1059 convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1060 const GLfloat src[][4],
1061 GLint filterWidth, GLint filterHeight,
1062 const GLfloat filter[][4],
1063 GLfloat dest[][4],
1064 const GLfloat borderColor[4])
1065 {
1066 const GLint halfFilterWidth = filterWidth / 2;
1067 const GLint halfFilterHeight = filterHeight / 2;
1068 GLint i, j, n, m;
1069
1070 for (j = 0; j < srcHeight; j++) {
1071 for (i = 0; i < srcWidth; i++) {
1072 GLfloat sumR = 0.0;
1073 GLfloat sumG = 0.0;
1074 GLfloat sumB = 0.0;
1075 GLfloat sumA = 0.0;
1076 for (m = 0; m < filterHeight; m++) {
1077 for (n = 0; n < filterWidth; n++) {
1078 const GLint f = m * filterWidth + n;
1079 const GLint is = i + n - halfFilterWidth;
1080 const GLint js = j + m - halfFilterHeight;
1081 if (is < 0 || is >= srcWidth ||
1082 js < 0 || js >= srcHeight) {
1083 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1084 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1085 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1086 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1087 }
1088 else {
1089 const GLint k = js * srcWidth + is;
1090 sumR += src[k][RCOMP] * filter[f][RCOMP];
1091 sumG += src[k][GCOMP] * filter[f][GCOMP];
1092 sumB += src[k][BCOMP] * filter[f][BCOMP];
1093 sumA += src[k][ACOMP] * filter[f][ACOMP];
1094 }
1095 }
1096 }
1097 dest[j * srcWidth + i][RCOMP] = sumR;
1098 dest[j * srcWidth + i][GCOMP] = sumG;
1099 dest[j * srcWidth + i][BCOMP] = sumB;
1100 dest[j * srcWidth + i][ACOMP] = sumA;
1101 }
1102 }
1103 }
1104
1105
1106 static void
1107 convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1108 const GLfloat src[][4],
1109 GLint filterWidth, GLint filterHeight,
1110 const GLfloat filter[][4],
1111 GLfloat dest[][4])
1112 {
1113 const GLint halfFilterWidth = filterWidth / 2;
1114 const GLint halfFilterHeight = filterHeight / 2;
1115 GLint i, j, n, m;
1116
1117 for (j = 0; j < srcHeight; j++) {
1118 for (i = 0; i < srcWidth; i++) {
1119 GLfloat sumR = 0.0;
1120 GLfloat sumG = 0.0;
1121 GLfloat sumB = 0.0;
1122 GLfloat sumA = 0.0;
1123 for (m = 0; m < filterHeight; m++) {
1124 for (n = 0; n < filterWidth; n++) {
1125 const GLint f = m * filterWidth + n;
1126 GLint is = i + n - halfFilterWidth;
1127 GLint js = j + m - halfFilterHeight;
1128 GLint k;
1129 if (is < 0)
1130 is = 0;
1131 else if (is >= srcWidth)
1132 is = srcWidth - 1;
1133 if (js < 0)
1134 js = 0;
1135 else if (js >= srcHeight)
1136 js = srcHeight - 1;
1137 k = js * srcWidth + is;
1138 sumR += src[k][RCOMP] * filter[f][RCOMP];
1139 sumG += src[k][GCOMP] * filter[f][GCOMP];
1140 sumB += src[k][BCOMP] * filter[f][BCOMP];
1141 sumA += src[k][ACOMP] * filter[f][ACOMP];
1142 }
1143 }
1144 dest[j * srcWidth + i][RCOMP] = sumR;
1145 dest[j * srcWidth + i][GCOMP] = sumG;
1146 dest[j * srcWidth + i][BCOMP] = sumB;
1147 dest[j * srcWidth + i][ACOMP] = sumA;
1148 }
1149 }
1150 }
1151
1152
1153 static void
1154 convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1155 const GLfloat src[][4],
1156 GLint filterWidth, GLint filterHeight,
1157 const GLfloat rowFilt[][4],
1158 const GLfloat colFilt[][4],
1159 GLfloat dest[][4])
1160 {
1161 GLint dstWidth, dstHeight;
1162 GLint i, j, n, m;
1163
1164 if (filterWidth >= 1)
1165 dstWidth = srcWidth - (filterWidth - 1);
1166 else
1167 dstWidth = srcWidth;
1168
1169 if (filterHeight >= 1)
1170 dstHeight = srcHeight - (filterHeight - 1);
1171 else
1172 dstHeight = srcHeight;
1173
1174 if (dstWidth <= 0 || dstHeight <= 0)
1175 return;
1176
1177 for (j = 0; j < dstHeight; j++) {
1178 for (i = 0; i < dstWidth; i++) {
1179 GLfloat sumR = 0.0;
1180 GLfloat sumG = 0.0;
1181 GLfloat sumB = 0.0;
1182 GLfloat sumA = 0.0;
1183 for (m = 0; m < filterHeight; m++) {
1184 for (n = 0; n < filterWidth; n++) {
1185 GLint k = (j + m) * srcWidth + i + n;
1186 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1187 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1188 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1189 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1190 }
1191 }
1192 dest[j * dstWidth + i][RCOMP] = sumR;
1193 dest[j * dstWidth + i][GCOMP] = sumG;
1194 dest[j * dstWidth + i][BCOMP] = sumB;
1195 dest[j * dstWidth + i][ACOMP] = sumA;
1196 }
1197 }
1198 }
1199
1200
1201 static void
1202 convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1203 const GLfloat src[][4],
1204 GLint filterWidth, GLint filterHeight,
1205 const GLfloat rowFilt[][4],
1206 const GLfloat colFilt[][4],
1207 GLfloat dest[][4],
1208 const GLfloat borderColor[4])
1209 {
1210 const GLint halfFilterWidth = filterWidth / 2;
1211 const GLint halfFilterHeight = filterHeight / 2;
1212 GLint i, j, n, m;
1213
1214 for (j = 0; j < srcHeight; j++) {
1215 for (i = 0; i < srcWidth; i++) {
1216 GLfloat sumR = 0.0;
1217 GLfloat sumG = 0.0;
1218 GLfloat sumB = 0.0;
1219 GLfloat sumA = 0.0;
1220 for (m = 0; m < filterHeight; m++) {
1221 for (n = 0; n < filterWidth; n++) {
1222 const GLint is = i + n - halfFilterWidth;
1223 const GLint js = j + m - halfFilterHeight;
1224 if (is < 0 || is >= srcWidth ||
1225 js < 0 || js >= srcHeight) {
1226 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1227 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1228 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1229 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1230 }
1231 else {
1232 GLint k = js * srcWidth + is;
1233 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1234 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1235 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1236 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1237 }
1238
1239 }
1240 }
1241 dest[j * srcWidth + i][RCOMP] = sumR;
1242 dest[j * srcWidth + i][GCOMP] = sumG;
1243 dest[j * srcWidth + i][BCOMP] = sumB;
1244 dest[j * srcWidth + i][ACOMP] = sumA;
1245 }
1246 }
1247 }
1248
1249
1250 static void
1251 convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1252 const GLfloat src[][4],
1253 GLint filterWidth, GLint filterHeight,
1254 const GLfloat rowFilt[][4],
1255 const GLfloat colFilt[][4],
1256 GLfloat dest[][4])
1257 {
1258 const GLint halfFilterWidth = filterWidth / 2;
1259 const GLint halfFilterHeight = filterHeight / 2;
1260 GLint i, j, n, m;
1261
1262 for (j = 0; j < srcHeight; j++) {
1263 for (i = 0; i < srcWidth; i++) {
1264 GLfloat sumR = 0.0;
1265 GLfloat sumG = 0.0;
1266 GLfloat sumB = 0.0;
1267 GLfloat sumA = 0.0;
1268 for (m = 0; m < filterHeight; m++) {
1269 for (n = 0; n < filterWidth; n++) {
1270 GLint is = i + n - halfFilterWidth;
1271 GLint js = j + m - halfFilterHeight;
1272 GLint k;
1273 if (is < 0)
1274 is = 0;
1275 else if (is >= srcWidth)
1276 is = srcWidth - 1;
1277 if (js < 0)
1278 js = 0;
1279 else if (js >= srcHeight)
1280 js = srcHeight - 1;
1281 k = js * srcWidth + is;
1282 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1283 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1284 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1285 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1286 }
1287 }
1288 dest[j * srcWidth + i][RCOMP] = sumR;
1289 dest[j * srcWidth + i][GCOMP] = sumG;
1290 dest[j * srcWidth + i][BCOMP] = sumB;
1291 dest[j * srcWidth + i][ACOMP] = sumA;
1292 }
1293 }
1294 }
1295
1296
1297
1298 void
1299 _mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1300 const GLfloat *srcImage, GLfloat *dstImage)
1301 {
1302 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1303 case GL_REDUCE:
1304 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1305 ctx->Convolution1D.Width,
1306 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1307 (GLfloat (*)[4]) dstImage);
1308 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1309 break;
1310 case GL_CONSTANT_BORDER:
1311 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1312 ctx->Convolution1D.Width,
1313 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1314 (GLfloat (*)[4]) dstImage,
1315 ctx->Pixel.ConvolutionBorderColor[0]);
1316 break;
1317 case GL_REPLICATE_BORDER:
1318 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1319 ctx->Convolution1D.Width,
1320 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1321 (GLfloat (*)[4]) dstImage);
1322 break;
1323 default:
1324 ;
1325 }
1326 }
1327
1328
1329 void
1330 _mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1331 const GLfloat *srcImage, GLfloat *dstImage)
1332 {
1333 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1334 case GL_REDUCE:
1335 convolve_2d_reduce(*width, *height,
1336 (const GLfloat (*)[4]) srcImage,
1337 ctx->Convolution2D.Width,
1338 ctx->Convolution2D.Height,
1339 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1340 (GLfloat (*)[4]) dstImage);
1341 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1342 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1343 break;
1344 case GL_CONSTANT_BORDER:
1345 convolve_2d_constant(*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 ctx->Pixel.ConvolutionBorderColor[1]);
1352 break;
1353 case GL_REPLICATE_BORDER:
1354 convolve_2d_replicate(*width, *height,
1355 (const GLfloat (*)[4]) srcImage,
1356 ctx->Convolution2D.Width,
1357 ctx->Convolution2D.Height,
1358 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1359 (GLfloat (*)[4]) dstImage);
1360 break;
1361 default:
1362 ;
1363 }
1364 }
1365
1366
1367 void
1368 _mesa_convolve_sep_image(const GLcontext *ctx,
1369 GLsizei *width, GLsizei *height,
1370 const GLfloat *srcImage, GLfloat *dstImage)
1371 {
1372 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1373 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1374
1375 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1376 case GL_REDUCE:
1377 convolve_sep_reduce(*width, *height,
1378 (const GLfloat (*)[4]) srcImage,
1379 ctx->Separable2D.Width,
1380 ctx->Separable2D.Height,
1381 (const GLfloat (*)[4]) rowFilter,
1382 (const GLfloat (*)[4]) colFilter,
1383 (GLfloat (*)[4]) dstImage);
1384 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1385 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1386 break;
1387 case GL_CONSTANT_BORDER:
1388 convolve_sep_constant(*width, *height,
1389 (const GLfloat (*)[4]) srcImage,
1390 ctx->Separable2D.Width,
1391 ctx->Separable2D.Height,
1392 (const GLfloat (*)[4]) rowFilter,
1393 (const GLfloat (*)[4]) colFilter,
1394 (GLfloat (*)[4]) dstImage,
1395 ctx->Pixel.ConvolutionBorderColor[2]);
1396 break;
1397 case GL_REPLICATE_BORDER:
1398 convolve_sep_replicate(*width, *height,
1399 (const GLfloat (*)[4]) srcImage,
1400 ctx->Separable2D.Width,
1401 ctx->Separable2D.Height,
1402 (const GLfloat (*)[4]) rowFilter,
1403 (const GLfloat (*)[4]) colFilter,
1404 (GLfloat (*)[4]) dstImage);
1405 break;
1406 default:
1407 ;
1408 }
1409 }