1 /* $Id: convolve.c,v 1.4 2000/08/23 14:31: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
49 * Given an internalFormat token passed to glConvolutionFilter
50 * or glSeparableFilter, return the corresponding base format.
51 * Return -1 if invalid token.
54 base_filter_format( GLenum format
)
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
;
103 return -1; /* error */
109 _mesa_ConvolutionFilter1D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLenum format
, GLenum type
, const GLvoid
*image
)
112 GET_CURRENT_CONTEXT(ctx
);
113 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glConvolutionFilter1D");
115 if (target
!= GL_CONVOLUTION_1D
) {
116 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter1D(target)");
120 baseFormat
= base_filter_format(internalFormat
);
121 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
122 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter1D(internalFormat)");
126 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
127 gl_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter1D(width)");
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
||
137 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter1D(format or type)");
141 ctx
->Convolution1D
.Format
= format
;
142 ctx
->Convolution1D
.InternalFormat
= internalFormat
;
143 ctx
->Convolution1D
.Width
= width
;
144 ctx
->Convolution1D
.Height
= 1;
146 /* unpack filter image */
147 _mesa_unpack_float_color_span(ctx
, width
, GL_RGBA
,
148 ctx
->Convolution1D
.Filter
,
149 format
, type
, image
, &ctx
->Unpack
,
152 /* apply scale and bias */
154 const GLfloat
*scale
= ctx
->Pixel
.ConvolutionFilterScale
[0];
155 const GLfloat
*bias
= ctx
->Pixel
.ConvolutionFilterBias
[0];
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
;
176 _mesa_ConvolutionFilter2D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*image
)
180 GET_CURRENT_CONTEXT(ctx
);
181 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glConvolutionFilter2D");
183 if (target
!= GL_CONVOLUTION_2D
) {
184 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(target)");
188 baseFormat
= base_filter_format(internalFormat
);
189 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
190 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(internalFormat)");
194 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
195 gl_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter2D(width)");
198 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
199 gl_error(ctx
, GL_INVALID_VALUE
, "glConvolutionFilter2D(height)");
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
||
209 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionFilter2D(format or type)");
213 components
= _mesa_components_in_format(format
);
214 assert(components
> 0); /* this should have been caught earlier */
216 ctx
->Convolution2D
.Format
= format
;
217 ctx
->Convolution2D
.InternalFormat
= internalFormat
;
218 ctx
->Convolution2D
.Width
= width
;
219 ctx
->Convolution2D
.Height
= height
;
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
,
231 /* apply scale and bias */
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
;
254 _mesa_ConvolutionParameterf(GLenum target
, GLenum pname
, GLfloat param
)
256 GET_CURRENT_CONTEXT(ctx
);
259 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glConvolutionParameterf");
262 case GL_CONVOLUTION_1D
:
265 case GL_CONVOLUTION_2D
:
268 case GL_SEPARABLE_2D
:
272 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(target)");
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
;
284 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(params)");
289 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterf(pname)");
296 _mesa_ConvolutionParameterfv(GLenum target
, GLenum pname
, const GLfloat
*params
)
298 GET_CURRENT_CONTEXT(ctx
);
299 struct gl_convolution_attrib
*conv
;
302 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glConvolutionParameterfv");
305 case GL_CONVOLUTION_1D
:
307 conv
= &ctx
->Convolution1D
;
309 case GL_CONVOLUTION_2D
:
311 conv
= &ctx
->Convolution2D
;
313 case GL_SEPARABLE_2D
:
315 conv
= &ctx
->Separable2D
;
318 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(target)");
323 case GL_CONVOLUTION_BORDER_COLOR
:
324 COPY_4V(ctx
->Pixel
.ConvolutionBorderColor
[c
], params
);
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];
333 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(params)");
337 case GL_CONVOLUTION_FILTER_SCALE
:
338 COPY_4V(ctx
->Pixel
.ConvolutionFilterScale
[c
], params
);
340 case GL_CONVOLUTION_FILTER_BIAS
:
341 COPY_4V(ctx
->Pixel
.ConvolutionFilterBias
[c
], params
);
344 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameterfv(pname)");
351 _mesa_ConvolutionParameteri(GLenum target
, GLenum pname
, GLint param
)
353 GET_CURRENT_CONTEXT(ctx
);
356 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glConvolutionParameteri");
359 case GL_CONVOLUTION_1D
:
362 case GL_CONVOLUTION_2D
:
365 case GL_SEPARABLE_2D
:
369 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(target)");
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
;
381 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(params)");
386 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteri(pname)");
393 _mesa_ConvolutionParameteriv(GLenum target
, GLenum pname
, const GLint
*params
)
395 GET_CURRENT_CONTEXT(ctx
);
396 struct gl_convolution_attrib
*conv
;
399 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glConvolutionParameteriv");
402 case GL_CONVOLUTION_1D
:
404 conv
= &ctx
->Convolution1D
;
406 case GL_CONVOLUTION_2D
:
408 conv
= &ctx
->Convolution2D
;
410 case GL_SEPARABLE_2D
:
412 conv
= &ctx
->Separable2D
;
415 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(target)");
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]);
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];
433 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(params)");
437 case GL_CONVOLUTION_FILTER_SCALE
:
438 COPY_4V(ctx
->Pixel
.ConvolutionFilterScale
[c
], params
);
440 case GL_CONVOLUTION_FILTER_BIAS
:
441 COPY_4V(ctx
->Pixel
.ConvolutionFilterBias
[c
], params
);
444 gl_error(ctx
, GL_INVALID_ENUM
, "glConvolutionParameteriv(pname)");
451 _mesa_CopyConvolutionFilter1D(GLenum target
, GLenum internalFormat
, GLint x
, GLint y
, GLsizei width
)
454 GLfloat rgba
[MAX_CONVOLUTION_WIDTH
][4];
455 GET_CURRENT_CONTEXT(ctx
);
456 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glCopyConvolutionFilter1D");
458 if (target
!= GL_CONVOLUTION_1D
) {
459 gl_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter1D(target)");
463 baseFormat
= base_filter_format(internalFormat
);
464 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
465 gl_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter1D(internalFormat)");
469 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
470 gl_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter1D(width)");
474 /* read pixels from framebuffer */
475 gl_read_rgba_span(ctx
, ctx
->ReadBuffer
, width
, x
, y
, (GLubyte (*)[4]) rgba
);
477 /* store as convolution filter */
478 _mesa_ConvolutionFilter1D(target
, internalFormat
, width
,
479 GL_RGBA
, GL_UNSIGNED_BYTE
, rgba
);
484 _mesa_CopyConvolutionFilter2D(GLenum target
, GLenum internalFormat
, GLint x
, GLint y
, GLsizei width
, GLsizei height
)
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");
493 if (target
!= GL_CONVOLUTION_2D
) {
494 gl_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter2D(target)");
498 baseFormat
= base_filter_format(internalFormat
);
499 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
500 gl_error(ctx
, GL_INVALID_ENUM
, "glCopyConvolutionFilter2D(internalFormat)");
504 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
505 gl_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter2D(width)");
508 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
509 gl_error(ctx
, GL_INVALID_VALUE
, "glCopyConvolutionFilter2D(height)");
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
]);
520 * store as convolution filter
522 packSave
= ctx
->Unpack
; /* save pixel packing params */
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
;
533 _mesa_ConvolutionFilter2D(target
, internalFormat
, width
, height
,
534 GL_RGBA
, GL_UNSIGNED_BYTE
, rgba
);
536 ctx
->Unpack
= packSave
; /* restore pixel packing params */
541 _mesa_GetConvolutionFilter(GLenum target
, GLenum format
, GLenum type
, GLvoid
*image
)
543 GET_CURRENT_CONTEXT(ctx
);
544 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glGetConvolutionFilter");
546 if (target
!= GL_CONVOLUTION_1D
&& target
!= GL_CONVOLUTION_2D
) {
547 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(target)");
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
||
557 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(format or type)");
562 /* XXX store image */
567 _mesa_GetConvolutionParameterfv(GLenum target
, GLenum pname
, GLfloat
*params
)
569 GET_CURRENT_CONTEXT(ctx
);
570 const struct gl_convolution_attrib
*conv
;
573 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glGetConvolutionParameterfv");
576 case GL_CONVOLUTION_1D
:
578 conv
= &ctx
->Convolution1D
;
580 case GL_CONVOLUTION_2D
:
582 conv
= &ctx
->Convolution2D
;
584 case GL_SEPARABLE_2D
:
586 conv
= &ctx
->Separable2D
;
589 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameterfv(target)");
594 case GL_CONVOLUTION_BORDER_COLOR
:
595 COPY_4V(params
, ctx
->Pixel
.ConvolutionBorderColor
[c
]);
597 case GL_CONVOLUTION_BORDER_MODE
:
598 *params
= (GLfloat
) ctx
->Pixel
.ConvolutionBorderMode
[c
];
600 case GL_CONVOLUTION_FILTER_SCALE
:
601 COPY_4V(params
, ctx
->Pixel
.ConvolutionFilterScale
[c
]);
603 case GL_CONVOLUTION_FILTER_BIAS
:
604 COPY_4V(params
, ctx
->Pixel
.ConvolutionFilterBias
[c
]);
606 case GL_CONVOLUTION_FORMAT
:
607 *params
= (GLfloat
) conv
->Format
;
609 case GL_CONVOLUTION_WIDTH
:
610 *params
= (GLfloat
) conv
->Width
;
612 case GL_CONVOLUTION_HEIGHT
:
613 *params
= (GLfloat
) conv
->Height
;
615 case GL_MAX_CONVOLUTION_WIDTH
:
616 *params
= (GLfloat
) ctx
->Const
.MaxConvolutionWidth
;
618 case GL_MAX_CONVOLUTION_HEIGHT
:
619 *params
= (GLfloat
) ctx
->Const
.MaxConvolutionHeight
;
622 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameterfv(pname)");
629 _mesa_GetConvolutionParameteriv(GLenum target
, GLenum pname
, GLint
*params
)
631 GET_CURRENT_CONTEXT(ctx
);
632 const struct gl_convolution_attrib
*conv
;
635 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glGetConvolutionParameteriv");
638 case GL_CONVOLUTION_1D
:
640 conv
= &ctx
->Convolution1D
;
642 case GL_CONVOLUTION_2D
:
644 conv
= &ctx
->Convolution2D
;
646 case GL_SEPARABLE_2D
:
648 conv
= &ctx
->Separable2D
;
651 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameteriv(target)");
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]);
662 case GL_CONVOLUTION_BORDER_MODE
:
663 *params
= (GLint
) ctx
->Pixel
.ConvolutionBorderMode
[c
];
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];
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];
677 case GL_CONVOLUTION_FORMAT
:
678 *params
= (GLint
) conv
->Format
;
680 case GL_CONVOLUTION_WIDTH
:
681 *params
= (GLint
) conv
->Width
;
683 case GL_CONVOLUTION_HEIGHT
:
684 *params
= (GLint
) conv
->Height
;
686 case GL_MAX_CONVOLUTION_WIDTH
:
687 *params
= (GLint
) ctx
->Const
.MaxConvolutionWidth
;
689 case GL_MAX_CONVOLUTION_HEIGHT
:
690 *params
= (GLint
) ctx
->Const
.MaxConvolutionHeight
;
693 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionParameteriv(pname)");
700 _mesa_GetSeparableFilter(GLenum target
, GLenum format
, GLenum type
, GLvoid
*row
, GLvoid
*column
, GLvoid
*span
)
702 GET_CURRENT_CONTEXT(ctx
);
703 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glGetSeparableFilter");
705 if (target
!= GL_SEPARABLE_2D
) {
706 gl_error(ctx
, GL_INVALID_ENUM
, "glGetSeparableFilter(target)");
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
||
716 gl_error(ctx
, GL_INVALID_ENUM
, "glGetConvolutionFilter(format or type)");
728 _mesa_SeparableFilter2D(GLenum target
, GLenum internalFormat
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*row
, const GLvoid
*column
)
730 const GLint colStart
= MAX_CONVOLUTION_WIDTH
* 4;
732 GET_CURRENT_CONTEXT(ctx
);
733 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx
, "glSeparableFilter2D");
735 if (target
!= GL_SEPARABLE_2D
) {
736 gl_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(target)");
740 baseFormat
= base_filter_format(internalFormat
);
741 if (baseFormat
< 0 || baseFormat
== GL_COLOR_INDEX
) {
742 gl_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(internalFormat)");
746 if (width
< 0 || width
> MAX_CONVOLUTION_WIDTH
) {
747 gl_error(ctx
, GL_INVALID_VALUE
, "glSeparableFilter2D(width)");
750 if (height
< 0 || height
> MAX_CONVOLUTION_HEIGHT
) {
751 gl_error(ctx
, GL_INVALID_VALUE
, "glSeparableFilter2D(height)");
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
||
761 gl_error(ctx
, GL_INVALID_ENUM
, "glSeparableFilter2D(format or type)");
765 ctx
->Separable2D
.Format
= format
;
766 ctx
->Separable2D
.InternalFormat
= internalFormat
;
767 ctx
->Separable2D
.Width
= width
;
768 ctx
->Separable2D
.Height
= height
;
770 /* unpack row filter */
771 _mesa_unpack_float_color_span(ctx
, width
, GL_RGBA
,
772 ctx
->Separable2D
.Filter
,
773 format
, type
, row
, &ctx
->Unpack
,
776 /* apply scale and bias */
778 const GLfloat
*scale
= ctx
->Pixel
.ConvolutionFilterScale
[2];
779 const GLfloat
*bias
= ctx
->Pixel
.ConvolutionFilterBias
[2];
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
;
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
,
803 /* apply scale and bias */
805 const GLfloat
*scale
= ctx
->Pixel
.ConvolutionFilterScale
[2];
806 const GLfloat
*bias
= ctx
->Pixel
.ConvolutionFilterBias
[2];
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
;
826 /**********************************************************************/
827 /*** image convolution functions ***/
828 /**********************************************************************/
831 convolve_1d_reduce(GLint srcWidth
, const GLfloat src
[][4],
832 GLint filterWidth
, const GLfloat filter
[][4],
838 if (filterWidth
>= 1)
839 dstWidth
= srcWidth
- (filterWidth
- 1);
844 return; /* null result */
846 for (i
= 0; i
< dstWidth
; i
++) {
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
];
857 dest
[i
][RCOMP
] = sumR
;
858 dest
[i
][GCOMP
] = sumG
;
859 dest
[i
][BCOMP
] = sumB
;
860 dest
[i
][ACOMP
] = sumA
;
866 convolve_1d_constant(GLint srcWidth
, const GLfloat src
[][4],
867 GLint filterWidth
, const GLfloat filter
[][4],
869 const GLfloat borderColor
[4])
871 const GLint halfFilterWidth
= filterWidth
/ 2;
874 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
893 dest
[i
][RCOMP
] = sumR
;
894 dest
[i
][GCOMP
] = sumG
;
895 dest
[i
][BCOMP
] = sumB
;
896 dest
[i
][ACOMP
] = sumA
;
902 convolve_1d_replicate(GLint srcWidth
, const GLfloat src
[][4],
903 GLint filterWidth
, const GLfloat filter
[][4],
906 const GLint halfFilterWidth
= filterWidth
/ 2;
909 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
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
];
934 dest
[i
][RCOMP
] = sumR
;
935 dest
[i
][GCOMP
] = sumG
;
936 dest
[i
][BCOMP
] = sumB
;
937 dest
[i
][ACOMP
] = sumA
;
943 convolve_2d_reduce(GLint srcWidth
, GLint srcHeight
,
944 const GLfloat src
[][4],
945 GLint filterWidth
, GLint filterHeight
,
946 const GLfloat filter
[][4],
949 GLint dstWidth
, dstHeight
;
952 if (filterWidth
>= 1)
953 dstWidth
= srcWidth
- (filterWidth
- 1);
957 if (filterHeight
>= 1)
958 dstHeight
= srcHeight
- (filterHeight
- 1);
960 dstHeight
= srcHeight
;
962 if (dstWidth
<= 0 || dstHeight
<= 0)
965 for (j
= 0; j
< dstHeight
; j
++) {
966 for (i
= 0; i
< dstWidth
; i
++) {
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
];
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
;
991 convolve_2d_constant(GLint srcWidth
, GLint srcHeight
,
992 const GLfloat src
[][4],
993 GLint filterWidth
, GLint filterHeight
,
994 const GLfloat filter
[][4],
996 const GLfloat borderColor
[4])
998 const GLint halfFilterWidth
= filterWidth
/ 2;
999 const GLint halfFilterHeight
= filterHeight
/ 2;
1002 for (j
= 0; j
< srcHeight
; j
++) {
1003 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
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
;
1039 convolve_2d_replicate(GLint srcWidth
, GLint srcHeight
,
1040 const GLfloat src
[][4],
1041 GLint filterWidth
, GLint filterHeight
,
1042 const GLfloat filter
[][4],
1045 const GLint halfFilterWidth
= filterWidth
/ 2;
1046 const GLint halfFilterHeight
= filterHeight
/ 2;
1049 for (j
= 0; j
< srcHeight
; j
++) {
1050 for (i
= 0; i
< srcWidth
; i
++) {
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
;
1063 else if (is
>= srcWidth
)
1067 else if (js
>= srcHeight
)
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
];
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
;
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],
1093 GLint dstWidth
, dstHeight
;
1096 if (filterWidth
>= 1)
1097 dstWidth
= srcWidth
- (filterWidth
- 1);
1099 dstWidth
= srcWidth
;
1101 if (filterHeight
>= 1)
1102 dstHeight
= srcHeight
- (filterHeight
- 1);
1104 dstHeight
= srcHeight
;
1106 if (dstWidth
<= 0 || dstHeight
<= 0)
1109 for (j
= 0; j
< dstHeight
; j
++) {
1110 for (i
= 0; i
< dstWidth
; i
++) {
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
];
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
;
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],
1140 const GLfloat borderColor
[4])
1142 const GLint halfFilterWidth
= filterWidth
/ 2;
1143 const GLint halfFilterHeight
= filterHeight
/ 2;
1146 for (j
= 0; j
< srcHeight
; j
++) {
1147 for (i
= 0; i
< srcWidth
; i
++) {
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
];
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
];
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
;
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],
1190 const GLint halfFilterWidth
= filterWidth
/ 2;
1191 const GLint halfFilterHeight
= filterHeight
/ 2;
1194 for (j
= 0; j
< srcHeight
; j
++) {
1195 for (i
= 0; i
< srcWidth
; i
++) {
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
;
1207 else if (is
>= srcWidth
)
1211 else if (js
>= srcHeight
)
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
];
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
;
1231 _mesa_convolve_1d_image(const GLcontext
*ctx
, GLsizei
*width
,
1232 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1234 switch (ctx
->Pixel
.ConvolutionBorderMode
[0]) {
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);
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]);
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
);
1262 _mesa_convolve_2d_image(const GLcontext
*ctx
, GLsizei
*width
, GLsizei
*height
,
1263 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1265 switch (ctx
->Pixel
.ConvolutionBorderMode
[1]) {
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);
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]);
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
);
1300 _mesa_convolve_sep_image(const GLcontext
*ctx
,
1301 GLsizei
*width
, GLsizei
*height
,
1302 const GLfloat
*srcImage
, GLfloat
*dstImage
)
1304 const GLfloat
*rowFilter
= ctx
->Separable2D
.Filter
;
1305 const GLfloat
*colFilter
= rowFilter
+ 4 * MAX_CONVOLUTION_WIDTH
;
1307 switch (ctx
->Pixel
.ConvolutionBorderMode
[2]) {
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);
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]);
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
);