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