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