1 /* $Id: convolve.c,v 1.3 2000/08/22 18:54:25 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
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:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
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.
29 * Image convolution functions.
31 * Notes: filter kernel elements are indexed by <n> and <m> as in
47 convolve_1d_reduce(GLint srcWidth
, const GLfloat src
[][4],
48 GLint filterWidth
, const GLfloat filter
[][4],
55 dstWidth
= srcWidth
- (filterWidth
- 1);
60 return; /* null result */
62 for (i
= 0; i
< dstWidth
; i
++) {
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
];
73 dest
[i
][RCOMP
] = sumR
;
74 dest
[i
][GCOMP
] = sumG
;
75 dest
[i
][BCOMP
] = sumB
;
76 dest
[i
][ACOMP
] = sumA
;
82 convolve_1d_constant(GLint srcWidth
, const GLfloat src
[][4],
83 GLint filterWidth
, const GLfloat filter
[][4],
85 const GLfloat borderColor
[4])
87 const GLint halfFilterWidth
= filterWidth
/ 2;
90 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
109 dest
[i
][RCOMP
] = sumR
;
110 dest
[i
][GCOMP
] = sumG
;
111 dest
[i
][BCOMP
] = sumB
;
112 dest
[i
][ACOMP
] = sumA
;
118 convolve_1d_replicate(GLint srcWidth
, const GLfloat src
[][4],
119 GLint filterWidth
, const GLfloat filter
[][4],
122 const GLint halfFilterWidth
= filterWidth
/ 2;
125 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
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
];
150 dest
[i
][RCOMP
] = sumR
;
151 dest
[i
][GCOMP
] = sumG
;
152 dest
[i
][BCOMP
] = sumB
;
153 dest
[i
][ACOMP
] = sumA
;
159 convolve_2d_reduce(GLint srcWidth
, GLint srcHeight
,
160 const GLfloat src
[][4],
161 GLint filterWidth
, GLint filterHeight
,
162 const GLfloat filter
[][4],
165 GLint dstWidth
, dstHeight
;
168 if (filterWidth
>= 1)
169 dstWidth
= srcWidth
- (filterWidth
- 1);
173 if (filterHeight
>= 1)
174 dstHeight
= srcHeight
- (filterHeight
- 1);
176 dstHeight
= srcHeight
;
178 if (dstWidth
<= 0 || dstHeight
<= 0)
181 for (j
= 0; j
< dstHeight
; j
++) {
182 for (i
= 0; i
< dstWidth
; i
++) {
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
];
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
;
207 convolve_2d_constant(GLint srcWidth
, GLint srcHeight
,
208 const GLfloat src
[][4],
209 GLint filterWidth
, GLint filterHeight
,
210 const GLfloat filter
[][4],
212 const GLfloat borderColor
[4])
214 const GLint halfFilterWidth
= filterWidth
/ 2;
215 const GLint halfFilterHeight
= filterHeight
/ 2;
218 for (j
= 0; j
< srcHeight
; j
++) {
219 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
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
;
255 convolve_2d_replicate(GLint srcWidth
, GLint srcHeight
,
256 const GLfloat src
[][4],
257 GLint filterWidth
, GLint filterHeight
,
258 const GLfloat filter
[][4],
261 const GLint halfFilterWidth
= filterWidth
/ 2;
262 const GLint halfFilterHeight
= filterHeight
/ 2;
265 for (j
= 0; j
< srcHeight
; j
++) {
266 for (i
= 0; i
< srcWidth
; i
++) {
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
;
279 else if (is
>= srcWidth
)
283 else if (js
>= srcHeight
)
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
];
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
;
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],
309 GLint dstWidth
, dstHeight
;
312 if (filterWidth
>= 1)
313 dstWidth
= srcWidth
- (filterWidth
- 1);
317 if (filterHeight
>= 1)
318 dstHeight
= srcHeight
- (filterHeight
- 1);
320 dstHeight
= srcHeight
;
322 if (dstWidth
<= 0 || dstHeight
<= 0)
325 for (j
= 0; j
< dstHeight
; j
++) {
326 for (i
= 0; i
< dstWidth
; i
++) {
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
];
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
;
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],
356 const GLfloat borderColor
[4])
358 const GLint halfFilterWidth
= filterWidth
/ 2;
359 const GLint halfFilterHeight
= filterHeight
/ 2;
362 for (j
= 0; j
< srcHeight
; j
++) {
363 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
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
;
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],
406 const GLint halfFilterWidth
= filterWidth
/ 2;
407 const GLint halfFilterHeight
= filterHeight
/ 2;
410 for (j
= 0; j
< srcHeight
; j
++) {
411 for (i
= 0; i
< srcWidth
; i
++) {
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
;
423 else if (is
>= srcWidth
)
427 else if (js
>= srcHeight
)
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
];
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
;
447 _mesa_convolve_1d_image(const GLcontext
*ctx
, GLsizei
*width
,
448 const GLfloat
*srcImage
, GLfloat
*dstImage
)
450 switch (ctx
->Pixel
.ConvolutionBorderMode
[0]) {
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);
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]);
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
);
478 _mesa_convolve_2d_image(const GLcontext
*ctx
, GLsizei
*width
, GLsizei
*height
,
479 const GLfloat
*srcImage
, GLfloat
*dstImage
)
481 switch (ctx
->Pixel
.ConvolutionBorderMode
[1]) {
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);
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]);
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
);
516 _mesa_convolve_sep_image(const GLcontext
*ctx
,
517 GLsizei
*width
, GLsizei
*height
,
518 const GLfloat
*srcImage
, GLfloat
*dstImage
)
520 const GLfloat
*rowFilter
= ctx
->Separable2D
.Filter
;
521 const GLfloat
*colFilter
= rowFilter
+ 4 * MAX_CONVOLUTION_WIDTH
;
523 switch (ctx
->Pixel
.ConvolutionBorderMode
[2]) {
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);
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]);
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
);