finished separable filter functions
[mesa.git] / src / mesa / main / convolve.c
1 /* $Id: convolve.c,v 1.3 2000/08/22 18:54: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 "types.h"
43 #endif
44
45
46 static void
47 convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
48 GLint filterWidth, const GLfloat filter[][4],
49 GLfloat dest[][4])
50 {
51 GLint dstWidth;
52 GLint i, n;
53
54 if (filterWidth >= 1)
55 dstWidth = srcWidth - (filterWidth - 1);
56 else
57 dstWidth = srcWidth;
58
59 if (dstWidth <= 0)
60 return; /* null result */
61
62 for (i = 0; i < dstWidth; i++) {
63 GLfloat sumR = 0.0;
64 GLfloat sumG = 0.0;
65 GLfloat sumB = 0.0;
66 GLfloat sumA = 0.0;
67 for (n = 0; n < filterWidth; n++) {
68 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
69 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
70 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
71 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
72 }
73 dest[i][RCOMP] = sumR;
74 dest[i][GCOMP] = sumG;
75 dest[i][BCOMP] = sumB;
76 dest[i][ACOMP] = sumA;
77 }
78 }
79
80
81 static void
82 convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
83 GLint filterWidth, const GLfloat filter[][4],
84 GLfloat dest[][4],
85 const GLfloat borderColor[4])
86 {
87 const GLint halfFilterWidth = filterWidth / 2;
88 GLint i, n;
89
90 for (i = 0; i < srcWidth; i++) {
91 GLfloat sumR = 0.0;
92 GLfloat sumG = 0.0;
93 GLfloat sumB = 0.0;
94 GLfloat sumA = 0.0;
95 for (n = 0; n < filterWidth; n++) {
96 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
97 sumR += borderColor[RCOMP] * filter[n][RCOMP];
98 sumG += borderColor[GCOMP] * filter[n][GCOMP];
99 sumB += borderColor[BCOMP] * filter[n][BCOMP];
100 sumA += borderColor[ACOMP] * filter[n][ACOMP];
101 }
102 else {
103 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
104 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
105 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
106 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
107 }
108 }
109 dest[i][RCOMP] = sumR;
110 dest[i][GCOMP] = sumG;
111 dest[i][BCOMP] = sumB;
112 dest[i][ACOMP] = sumA;
113 }
114 }
115
116
117 static void
118 convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
119 GLint filterWidth, const GLfloat filter[][4],
120 GLfloat dest[][4])
121 {
122 const GLint halfFilterWidth = filterWidth / 2;
123 GLint i, n;
124
125 for (i = 0; i < srcWidth; i++) {
126 GLfloat sumR = 0.0;
127 GLfloat sumG = 0.0;
128 GLfloat sumB = 0.0;
129 GLfloat sumA = 0.0;
130 for (n = 0; n < filterWidth; n++) {
131 if (i + n < halfFilterWidth) {
132 sumR += src[0][RCOMP] * filter[n][RCOMP];
133 sumG += src[0][GCOMP] * filter[n][GCOMP];
134 sumB += src[0][BCOMP] * filter[n][BCOMP];
135 sumA += src[0][ACOMP] * filter[n][ACOMP];
136 }
137 else if (i + n - halfFilterWidth >= srcWidth) {
138 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
139 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
140 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
141 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
142 }
143 else {
144 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
145 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
146 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
147 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
148 }
149 }
150 dest[i][RCOMP] = sumR;
151 dest[i][GCOMP] = sumG;
152 dest[i][BCOMP] = sumB;
153 dest[i][ACOMP] = sumA;
154 }
155 }
156
157
158 static void
159 convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
160 const GLfloat src[][4],
161 GLint filterWidth, GLint filterHeight,
162 const GLfloat filter[][4],
163 GLfloat dest[][4])
164 {
165 GLint dstWidth, dstHeight;
166 GLint i, j, n, m;
167
168 if (filterWidth >= 1)
169 dstWidth = srcWidth - (filterWidth - 1);
170 else
171 dstWidth = srcWidth;
172
173 if (filterHeight >= 1)
174 dstHeight = srcHeight - (filterHeight - 1);
175 else
176 dstHeight = srcHeight;
177
178 if (dstWidth <= 0 || dstHeight <= 0)
179 return;
180
181 for (j = 0; j < dstHeight; j++) {
182 for (i = 0; i < dstWidth; i++) {
183 GLfloat sumR = 0.0;
184 GLfloat sumG = 0.0;
185 GLfloat sumB = 0.0;
186 GLfloat sumA = 0.0;
187 for (m = 0; m < filterHeight; m++) {
188 for (n = 0; n < filterWidth; n++) {
189 const GLint k = (j + m) * srcWidth + i + n;
190 const GLint f = m * filterWidth + n;
191 sumR += src[k][RCOMP] * filter[f][RCOMP];
192 sumG += src[k][GCOMP] * filter[f][GCOMP];
193 sumB += src[k][BCOMP] * filter[f][BCOMP];
194 sumA += src[k][ACOMP] * filter[f][ACOMP];
195 }
196 }
197 dest[j * dstWidth + i][RCOMP] = sumR;
198 dest[j * dstWidth + i][GCOMP] = sumG;
199 dest[j * dstWidth + i][BCOMP] = sumB;
200 dest[j * dstWidth + i][ACOMP] = sumA;
201 }
202 }
203 }
204
205
206 static void
207 convolve_2d_constant(GLint srcWidth, GLint srcHeight,
208 const GLfloat src[][4],
209 GLint filterWidth, GLint filterHeight,
210 const GLfloat filter[][4],
211 GLfloat dest[][4],
212 const GLfloat borderColor[4])
213 {
214 const GLint halfFilterWidth = filterWidth / 2;
215 const GLint halfFilterHeight = filterHeight / 2;
216 GLint i, j, n, m;
217
218 for (j = 0; j < srcHeight; j++) {
219 for (i = 0; i < srcWidth; i++) {
220 GLfloat sumR = 0.0;
221 GLfloat sumG = 0.0;
222 GLfloat sumB = 0.0;
223 GLfloat sumA = 0.0;
224 for (m = 0; m < filterHeight; m++) {
225 for (n = 0; n < filterWidth; n++) {
226 const GLint f = m * filterWidth + n;
227 const GLint is = i + n - halfFilterWidth;
228 const GLint js = j + m - halfFilterHeight;
229 if (is < 0 || is >= srcWidth ||
230 js < 0 || js >= srcHeight) {
231 sumR += borderColor[RCOMP] * filter[f][RCOMP];
232 sumG += borderColor[GCOMP] * filter[f][GCOMP];
233 sumB += borderColor[BCOMP] * filter[f][BCOMP];
234 sumA += borderColor[ACOMP] * filter[f][ACOMP];
235 }
236 else {
237 const GLint k = js * srcWidth + is;
238 sumR += src[k][RCOMP] * filter[f][RCOMP];
239 sumG += src[k][GCOMP] * filter[f][GCOMP];
240 sumB += src[k][BCOMP] * filter[f][BCOMP];
241 sumA += src[k][ACOMP] * filter[f][ACOMP];
242 }
243 }
244 }
245 dest[j * srcWidth + i][RCOMP] = sumR;
246 dest[j * srcWidth + i][GCOMP] = sumG;
247 dest[j * srcWidth + i][BCOMP] = sumB;
248 dest[j * srcWidth + i][ACOMP] = sumA;
249 }
250 }
251 }
252
253
254 static void
255 convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
256 const GLfloat src[][4],
257 GLint filterWidth, GLint filterHeight,
258 const GLfloat filter[][4],
259 GLfloat dest[][4])
260 {
261 const GLint halfFilterWidth = filterWidth / 2;
262 const GLint halfFilterHeight = filterHeight / 2;
263 GLint i, j, n, m;
264
265 for (j = 0; j < srcHeight; j++) {
266 for (i = 0; i < srcWidth; i++) {
267 GLfloat sumR = 0.0;
268 GLfloat sumG = 0.0;
269 GLfloat sumB = 0.0;
270 GLfloat sumA = 0.0;
271 for (m = 0; m < filterHeight; m++) {
272 for (n = 0; n < filterWidth; n++) {
273 const GLint f = m * filterWidth + n;
274 GLint is = i + n - halfFilterWidth;
275 GLint js = j + m - halfFilterHeight;
276 GLint k;
277 if (is < 0)
278 is = 0;
279 else if (is >= srcWidth)
280 is = srcWidth - 1;
281 if (js < 0)
282 js = 0;
283 else if (js >= srcHeight)
284 js = srcHeight - 1;
285 k = js * srcWidth + is;
286 sumR += src[k][RCOMP] * filter[f][RCOMP];
287 sumG += src[k][GCOMP] * filter[f][GCOMP];
288 sumB += src[k][BCOMP] * filter[f][BCOMP];
289 sumA += src[k][ACOMP] * filter[f][ACOMP];
290 }
291 }
292 dest[j * srcWidth + i][RCOMP] = sumR;
293 dest[j * srcWidth + i][GCOMP] = sumG;
294 dest[j * srcWidth + i][BCOMP] = sumB;
295 dest[j * srcWidth + i][ACOMP] = sumA;
296 }
297 }
298 }
299
300
301 static void
302 convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
303 const GLfloat src[][4],
304 GLint filterWidth, GLint filterHeight,
305 const GLfloat rowFilt[][4],
306 const GLfloat colFilt[][4],
307 GLfloat dest[][4])
308 {
309 GLint dstWidth, dstHeight;
310 GLint i, j, n, m;
311
312 if (filterWidth >= 1)
313 dstWidth = srcWidth - (filterWidth - 1);
314 else
315 dstWidth = srcWidth;
316
317 if (filterHeight >= 1)
318 dstHeight = srcHeight - (filterHeight - 1);
319 else
320 dstHeight = srcHeight;
321
322 if (dstWidth <= 0 || dstHeight <= 0)
323 return;
324
325 for (j = 0; j < dstHeight; j++) {
326 for (i = 0; i < dstWidth; i++) {
327 GLfloat sumR = 0.0;
328 GLfloat sumG = 0.0;
329 GLfloat sumB = 0.0;
330 GLfloat sumA = 0.0;
331 for (m = 0; m < filterHeight; m++) {
332 for (n = 0; n < filterWidth; n++) {
333 GLint k = (j + m) * srcWidth + i + n;
334 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
335 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
336 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
337 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
338 }
339 }
340 dest[j * dstWidth + i][RCOMP] = sumR;
341 dest[j * dstWidth + i][GCOMP] = sumG;
342 dest[j * dstWidth + i][BCOMP] = sumB;
343 dest[j * dstWidth + i][ACOMP] = sumA;
344 }
345 }
346 }
347
348
349 static void
350 convolve_sep_constant(GLint srcWidth, GLint srcHeight,
351 const GLfloat src[][4],
352 GLint filterWidth, GLint filterHeight,
353 const GLfloat rowFilt[][4],
354 const GLfloat colFilt[][4],
355 GLfloat dest[][4],
356 const GLfloat borderColor[4])
357 {
358 const GLint halfFilterWidth = filterWidth / 2;
359 const GLint halfFilterHeight = filterHeight / 2;
360 GLint i, j, n, m;
361
362 for (j = 0; j < srcHeight; j++) {
363 for (i = 0; i < srcWidth; i++) {
364 GLfloat sumR = 0.0;
365 GLfloat sumG = 0.0;
366 GLfloat sumB = 0.0;
367 GLfloat sumA = 0.0;
368 for (m = 0; m < filterHeight; m++) {
369 for (n = 0; n < filterWidth; n++) {
370 const GLint is = i + n - halfFilterWidth;
371 const GLint js = j + m - halfFilterHeight;
372 if (is < 0 || is >= srcWidth ||
373 js < 0 || js >= srcHeight) {
374 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
375 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
376 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
377 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
378 }
379 else {
380 GLint k = js * srcWidth + is;
381 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
382 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
383 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
384 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
385 }
386
387 }
388 }
389 dest[j * srcWidth + i][RCOMP] = sumR;
390 dest[j * srcWidth + i][GCOMP] = sumG;
391 dest[j * srcWidth + i][BCOMP] = sumB;
392 dest[j * srcWidth + i][ACOMP] = sumA;
393 }
394 }
395 }
396
397
398 static void
399 convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
400 const GLfloat src[][4],
401 GLint filterWidth, GLint filterHeight,
402 const GLfloat rowFilt[][4],
403 const GLfloat colFilt[][4],
404 GLfloat dest[][4])
405 {
406 const GLint halfFilterWidth = filterWidth / 2;
407 const GLint halfFilterHeight = filterHeight / 2;
408 GLint i, j, n, m;
409
410 for (j = 0; j < srcHeight; j++) {
411 for (i = 0; i < srcWidth; i++) {
412 GLfloat sumR = 0.0;
413 GLfloat sumG = 0.0;
414 GLfloat sumB = 0.0;
415 GLfloat sumA = 0.0;
416 for (m = 0; m < filterHeight; m++) {
417 for (n = 0; n < filterWidth; n++) {
418 GLint is = i + n - halfFilterWidth;
419 GLint js = j + m - halfFilterHeight;
420 GLint k;
421 if (is < 0)
422 is = 0;
423 else if (is >= srcWidth)
424 is = srcWidth - 1;
425 if (js < 0)
426 js = 0;
427 else if (js >= srcHeight)
428 js = srcHeight - 1;
429 k = js * srcWidth + is;
430 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
431 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
432 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
433 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
434 }
435 }
436 dest[j * srcWidth + i][RCOMP] = sumR;
437 dest[j * srcWidth + i][GCOMP] = sumG;
438 dest[j * srcWidth + i][BCOMP] = sumB;
439 dest[j * srcWidth + i][ACOMP] = sumA;
440 }
441 }
442 }
443
444
445
446 void
447 _mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
448 const GLfloat *srcImage, GLfloat *dstImage)
449 {
450 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
451 case GL_REDUCE:
452 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
453 ctx->Convolution1D.Width,
454 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
455 (GLfloat (*)[4]) dstImage);
456 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
457 break;
458 case GL_CONSTANT_BORDER:
459 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
460 ctx->Convolution1D.Width,
461 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
462 (GLfloat (*)[4]) dstImage,
463 ctx->Pixel.ConvolutionBorderColor[0]);
464 break;
465 case GL_REPLICATE_BORDER:
466 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
467 ctx->Convolution1D.Width,
468 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
469 (GLfloat (*)[4]) dstImage);
470 break;
471 default:
472 ;
473 }
474 }
475
476
477 void
478 _mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
479 const GLfloat *srcImage, GLfloat *dstImage)
480 {
481 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
482 case GL_REDUCE:
483 convolve_2d_reduce(*width, *height,
484 (const GLfloat (*)[4]) srcImage,
485 ctx->Convolution2D.Width,
486 ctx->Convolution2D.Height,
487 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
488 (GLfloat (*)[4]) dstImage);
489 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
490 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
491 break;
492 case GL_CONSTANT_BORDER:
493 convolve_2d_constant(*width, *height,
494 (const GLfloat (*)[4]) srcImage,
495 ctx->Convolution2D.Width,
496 ctx->Convolution2D.Height,
497 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
498 (GLfloat (*)[4]) dstImage,
499 ctx->Pixel.ConvolutionBorderColor[1]);
500 break;
501 case GL_REPLICATE_BORDER:
502 convolve_2d_replicate(*width, *height,
503 (const GLfloat (*)[4]) srcImage,
504 ctx->Convolution2D.Width,
505 ctx->Convolution2D.Height,
506 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
507 (GLfloat (*)[4]) dstImage);
508 break;
509 default:
510 ;
511 }
512 }
513
514
515 void
516 _mesa_convolve_sep_image(const GLcontext *ctx,
517 GLsizei *width, GLsizei *height,
518 const GLfloat *srcImage, GLfloat *dstImage)
519 {
520 const GLfloat *rowFilter = ctx->Separable2D.Filter;
521 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
522
523 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
524 case GL_REDUCE:
525 convolve_sep_reduce(*width, *height,
526 (const GLfloat (*)[4]) srcImage,
527 ctx->Separable2D.Width,
528 ctx->Separable2D.Height,
529 (const GLfloat (*)[4]) rowFilter,
530 (const GLfloat (*)[4]) colFilter,
531 (GLfloat (*)[4]) dstImage);
532 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
533 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
534 break;
535 case GL_CONSTANT_BORDER:
536 convolve_sep_constant(*width, *height,
537 (const GLfloat (*)[4]) srcImage,
538 ctx->Separable2D.Width,
539 ctx->Separable2D.Height,
540 (const GLfloat (*)[4]) rowFilter,
541 (const GLfloat (*)[4]) colFilter,
542 (GLfloat (*)[4]) dstImage,
543 ctx->Pixel.ConvolutionBorderColor[2]);
544 break;
545 case GL_REPLICATE_BORDER:
546 convolve_sep_replicate(*width, *height,
547 (const GLfloat (*)[4]) srcImage,
548 ctx->Separable2D.Width,
549 ctx->Separable2D.Height,
550 (const GLfloat (*)[4]) rowFilter,
551 (const GLfloat (*)[4]) colFilter,
552 (GLfloat (*)[4]) dstImage);
553 break;
554 default:
555 ;
556 }
557 }