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