blob: 2a5f5f9b2d29307ff9d626c836acdaf5b7964927 [file] [log] [blame]
Keith Whitwella96308c2000-10-30 13:31:59 +00001/* $Id: convolve.c,v 1.8 2000/10/30 13:32:00 keithw Exp $ */
Brian Paulcc8e37f2000-07-12 13:00:09 +00002
3/*
4 * Mesa 3-D graphics library
Brian Pauld4b799b2000-08-21 14:24:30 +00005 * Version: 3.5
Brian Paulcc8e37f2000-07-12 13:00:09 +00006 *
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"
Brian Paulc893a012000-10-28 20:41:13 +000040#include "colormac.h"
Brian Pauld4b799b2000-08-21 14:24:30 +000041#include "convolve.h"
42#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000043#include "image.h"
44#include "span.h"
Brian Paulcc8e37f2000-07-12 13:00:09 +000045#include "types.h"
46#endif
47
48
Brian Paul147b0832000-08-23 14:31:25 +000049/*
50 * Given an internalFormat token passed to glConvolutionFilter
51 * or glSeparableFilter, return the corresponding base format.
52 * Return -1 if invalid token.
53 */
54static GLint
55base_filter_format( GLenum format )
56{
57 switch (format) {
58 case GL_ALPHA:
59 case GL_ALPHA4:
60 case GL_ALPHA8:
61 case GL_ALPHA12:
62 case GL_ALPHA16:
63 return GL_ALPHA;
64 case GL_LUMINANCE:
65 case GL_LUMINANCE4:
66 case GL_LUMINANCE8:
67 case GL_LUMINANCE12:
68 case GL_LUMINANCE16:
69 return GL_LUMINANCE;
70 case GL_LUMINANCE_ALPHA:
71 case GL_LUMINANCE4_ALPHA4:
72 case GL_LUMINANCE6_ALPHA2:
73 case GL_LUMINANCE8_ALPHA8:
74 case GL_LUMINANCE12_ALPHA4:
75 case GL_LUMINANCE12_ALPHA12:
76 case GL_LUMINANCE16_ALPHA16:
77 return GL_LUMINANCE_ALPHA;
78 case GL_INTENSITY:
79 case GL_INTENSITY4:
80 case GL_INTENSITY8:
81 case GL_INTENSITY12:
82 case GL_INTENSITY16:
83 return GL_INTENSITY;
84 case GL_RGB:
85 case GL_R3_G3_B2:
86 case GL_RGB4:
87 case GL_RGB5:
88 case GL_RGB8:
89 case GL_RGB10:
90 case GL_RGB12:
91 case GL_RGB16:
92 return GL_RGB;
93 case 4:
94 case GL_RGBA:
95 case GL_RGBA2:
96 case GL_RGBA4:
97 case GL_RGB5_A1:
98 case GL_RGBA8:
99 case GL_RGB10_A2:
100 case GL_RGBA12:
101 case GL_RGBA16:
102 return GL_RGBA;
103 default:
104 return -1; /* error */
105 }
106}
107
108
109void
110_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
111{
112 GLenum baseFormat;
113 GET_CURRENT_CONTEXT(ctx);
114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter1D");
115
116 if (target != GL_CONVOLUTION_1D) {
117 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
118 return;
119 }
120
121 baseFormat = base_filter_format(internalFormat);
122 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
123 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
124 return;
125 }
126
127 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
128 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
129 return;
130 }
131
132 if (!_mesa_is_legal_format_and_type(format, type) ||
133 format == GL_COLOR_INDEX ||
134 format == GL_STENCIL_INDEX ||
135 format == GL_DEPTH_COMPONENT ||
136 format == GL_INTENSITY ||
137 type == GL_BITMAP) {
138 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
139 return;
140 }
141
142 ctx->Convolution1D.Format = format;
143 ctx->Convolution1D.InternalFormat = internalFormat;
144 ctx->Convolution1D.Width = width;
145 ctx->Convolution1D.Height = 1;
146
147 /* unpack filter image */
148 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
149 ctx->Convolution1D.Filter,
150 format, type, image, &ctx->Unpack,
151 0, GL_FALSE);
152
153 /* apply scale and bias */
154 {
155 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
156 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
157 GLint i;
158 for (i = 0; i < width; i++) {
159 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
160 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
161 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
162 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
163 r = r * scale[0] + bias[0];
164 g = g * scale[1] + bias[1];
165 b = b * scale[2] + bias[2];
166 a = a * scale[3] + bias[3];
167 ctx->Convolution1D.Filter[i * 4 + 0] = r;
168 ctx->Convolution1D.Filter[i * 4 + 1] = g;
169 ctx->Convolution1D.Filter[i * 4 + 2] = b;
170 ctx->Convolution1D.Filter[i * 4 + 3] = a;
171 }
172 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000173
174 ctx->NewState |= _NEW_IMAGING;
Brian Paul147b0832000-08-23 14:31:25 +0000175}
176
177
178void
179_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
180{
181 GLenum baseFormat;
182 GLint i, components;
183 GET_CURRENT_CONTEXT(ctx);
184 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter2D");
185
186 if (target != GL_CONVOLUTION_2D) {
187 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
188 return;
189 }
190
191 baseFormat = base_filter_format(internalFormat);
192 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
193 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
194 return;
195 }
196
197 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
198 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
199 return;
200 }
201 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
202 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
203 return;
204 }
205
206 if (!_mesa_is_legal_format_and_type(format, type) ||
207 format == GL_COLOR_INDEX ||
208 format == GL_STENCIL_INDEX ||
209 format == GL_DEPTH_COMPONENT ||
210 format == GL_INTENSITY ||
211 type == GL_BITMAP) {
212 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
213 return;
214 }
215
216 components = _mesa_components_in_format(format);
217 assert(components > 0); /* this should have been caught earlier */
218
219 ctx->Convolution2D.Format = format;
220 ctx->Convolution2D.InternalFormat = internalFormat;
221 ctx->Convolution2D.Width = width;
222 ctx->Convolution2D.Height = height;
223
224 /* Unpack filter image. We always store filters in RGBA format. */
225 for (i = 0; i < height; i++) {
226 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
227 height, format, type, 0, i, 0);
228 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
229 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
230 format, type, src, &ctx->Unpack,
231 0, GL_FALSE);
232 }
233
234 /* apply scale and bias */
235 {
236 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
237 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
238 for (i = 0; i < width * height * 4; i++) {
239 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
240 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
241 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
242 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
243 r = r * scale[0] + bias[0];
244 g = g * scale[1] + bias[1];
245 b = b * scale[2] + bias[2];
246 a = a * scale[3] + bias[3];
247 ctx->Convolution2D.Filter[i * 4 + 0] = r;
248 ctx->Convolution2D.Filter[i * 4 + 1] = g;
249 ctx->Convolution2D.Filter[i * 4 + 2] = b;
250 ctx->Convolution2D.Filter[i * 4 + 3] = a;
251 }
252 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000253
254 ctx->NewState |= _NEW_IMAGING;
Brian Paul147b0832000-08-23 14:31:25 +0000255}
256
257
258void
259_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
260{
261 GET_CURRENT_CONTEXT(ctx);
262 GLuint c;
263
264 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterf");
265
266 switch (target) {
267 case GL_CONVOLUTION_1D:
268 c = 0;
269 break;
270 case GL_CONVOLUTION_2D:
271 c = 1;
272 break;
273 case GL_SEPARABLE_2D:
274 c = 2;
275 break;
276 default:
277 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
278 return;
279 }
280
281 switch (pname) {
282 case GL_CONVOLUTION_BORDER_MODE:
283 if (param == (GLfloat) GL_REDUCE ||
284 param == (GLfloat) GL_CONSTANT_BORDER ||
285 param == (GLfloat) GL_REPLICATE_BORDER) {
286 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
287 }
288 else {
289 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
290 return;
291 }
292 break;
293 default:
294 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
295 return;
296 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000297
298 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000299}
300
301
302void
303_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
304{
305 GET_CURRENT_CONTEXT(ctx);
306 struct gl_convolution_attrib *conv;
307 GLuint c;
308
309 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterfv");
310
311 switch (target) {
312 case GL_CONVOLUTION_1D:
313 c = 0;
314 conv = &ctx->Convolution1D;
315 break;
316 case GL_CONVOLUTION_2D:
317 c = 1;
318 conv = &ctx->Convolution2D;
319 break;
320 case GL_SEPARABLE_2D:
321 c = 2;
322 conv = &ctx->Separable2D;
323 break;
324 default:
325 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
326 return;
327 }
328
329 switch (pname) {
330 case GL_CONVOLUTION_BORDER_COLOR:
331 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
332 break;
333 case GL_CONVOLUTION_BORDER_MODE:
334 if (params[0] == (GLfloat) GL_REDUCE ||
335 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
336 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
337 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
338 }
339 else {
340 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
341 return;
342 }
343 break;
344 case GL_CONVOLUTION_FILTER_SCALE:
345 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
346 break;
347 case GL_CONVOLUTION_FILTER_BIAS:
348 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
349 break;
350 default:
351 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
352 return;
353 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000354
355 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000356}
357
358
359void
360_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
361{
362 GET_CURRENT_CONTEXT(ctx);
363 GLuint c;
364
365 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteri");
366
367 switch (target) {
368 case GL_CONVOLUTION_1D:
369 c = 0;
370 break;
371 case GL_CONVOLUTION_2D:
372 c = 1;
373 break;
374 case GL_SEPARABLE_2D:
375 c = 2;
376 break;
377 default:
378 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
379 return;
380 }
381
382 switch (pname) {
383 case GL_CONVOLUTION_BORDER_MODE:
384 if (param == (GLint) GL_REDUCE ||
385 param == (GLint) GL_CONSTANT_BORDER ||
386 param == (GLint) GL_REPLICATE_BORDER) {
387 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
388 }
389 else {
390 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
391 return;
392 }
393 break;
394 default:
395 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
396 return;
397 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000398
399 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000400}
401
402
403void
404_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
405{
406 GET_CURRENT_CONTEXT(ctx);
407 struct gl_convolution_attrib *conv;
408 GLuint c;
409
410 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteriv");
411
412 switch (target) {
413 case GL_CONVOLUTION_1D:
414 c = 0;
415 conv = &ctx->Convolution1D;
416 break;
417 case GL_CONVOLUTION_2D:
418 c = 1;
419 conv = &ctx->Convolution2D;
420 break;
421 case GL_SEPARABLE_2D:
422 c = 2;
423 conv = &ctx->Separable2D;
424 break;
425 default:
426 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
427 return;
428 }
429
430 switch (pname) {
431 case GL_CONVOLUTION_BORDER_COLOR:
432 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
433 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
434 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
435 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
436 break;
437 case GL_CONVOLUTION_BORDER_MODE:
438 if (params[0] == (GLint) GL_REDUCE ||
439 params[0] == (GLint) GL_CONSTANT_BORDER ||
440 params[0] == (GLint) GL_REPLICATE_BORDER) {
441 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
442 }
443 else {
444 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
445 return;
446 }
447 break;
448 case GL_CONVOLUTION_FILTER_SCALE:
449 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
450 break;
451 case GL_CONVOLUTION_FILTER_BIAS:
452 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
453 break;
454 default:
455 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
456 return;
457 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000458
459 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000460}
461
462
463void
464_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
465{
466 GLenum baseFormat;
467 GLfloat rgba[MAX_CONVOLUTION_WIDTH][4];
468 GET_CURRENT_CONTEXT(ctx);
469 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter1D");
470
471 if (target != GL_CONVOLUTION_1D) {
472 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
473 return;
474 }
475
476 baseFormat = base_filter_format(internalFormat);
477 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
478 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
479 return;
480 }
481
482 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
483 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
484 return;
485 }
486
487 /* read pixels from framebuffer */
Brian Paulba643a22000-10-28 18:34:48 +0000488 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000489
490 /* store as convolution filter */
491 _mesa_ConvolutionFilter1D(target, internalFormat, width,
492 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
493}
494
495
496void
497_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
498{
499 GLenum baseFormat;
500 GLint i;
501 struct gl_pixelstore_attrib packSave;
502 GLfloat rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
503 GET_CURRENT_CONTEXT(ctx);
504 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter2D");
505
506 if (target != GL_CONVOLUTION_2D) {
507 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
508 return;
509 }
510
511 baseFormat = base_filter_format(internalFormat);
512 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
513 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
514 return;
515 }
516
517 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
518 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
519 return;
520 }
521 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
522 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
523 return;
524 }
525
526 /* read pixels from framebuffer */
527 for (i = 0; i < height; i++) {
528 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
Brian Paulba643a22000-10-28 18:34:48 +0000529 (GLchan (*)[4]) rgba[i]);
Brian Paul147b0832000-08-23 14:31:25 +0000530 }
531
532 /*
533 * store as convolution filter
534 */
535 packSave = ctx->Unpack; /* save pixel packing params */
536
537 ctx->Unpack.Alignment = 1;
538 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
539 ctx->Unpack.SkipPixels = 0;
540 ctx->Unpack.SkipRows = 0;
541 ctx->Unpack.ImageHeight = 0;
542 ctx->Unpack.SkipImages = 0;
543 ctx->Unpack.SwapBytes = GL_FALSE;
544 ctx->Unpack.LsbFirst = GL_FALSE;
Keith Whitwella96308c2000-10-30 13:31:59 +0000545 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000546
547 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
548 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
549
550 ctx->Unpack = packSave; /* restore pixel packing params */
Keith Whitwella96308c2000-10-30 13:31:59 +0000551 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000552}
553
554
555void
556_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
557{
Brian Paulf75d6972000-09-05 20:28:56 +0000558 const struct gl_convolution_attrib *filter;
559 GLint row;
Brian Paul147b0832000-08-23 14:31:25 +0000560 GET_CURRENT_CONTEXT(ctx);
561 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
562
Brian Paul147b0832000-08-23 14:31:25 +0000563 if (!_mesa_is_legal_format_and_type(format, type) ||
564 format == GL_COLOR_INDEX ||
565 format == GL_STENCIL_INDEX ||
566 format == GL_DEPTH_COMPONENT ||
567 format == GL_INTENSITY ||
568 type == GL_BITMAP) {
569 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
570 return;
571 }
572
Brian Paulf75d6972000-09-05 20:28:56 +0000573 switch (target) {
574 case GL_CONVOLUTION_1D:
575 filter = &(ctx->Convolution1D);
576 break;
577 case GL_CONVOLUTION_2D:
578 filter = &(ctx->Convolution2D);
579 break;
580 default:
581 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
582 return;
583 }
584
585 for (row = 0; row < filter->Height; row++) {
586 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
587 filter->Height, format, type,
588 0, row, 0);
589 const GLfloat *src = filter->Filter + row * filter->Width * 4;
590 /* XXX apply transfer ops or not? */
591 _mesa_pack_float_rgba_span(ctx, filter->Width,
592 (const GLfloat (*)[4]) src,
593 format, type, dst, &ctx->Pack, 0);
594 }
Brian Paul147b0832000-08-23 14:31:25 +0000595}
596
597
598void
599_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
600{
601 GET_CURRENT_CONTEXT(ctx);
602 const struct gl_convolution_attrib *conv;
603 GLuint c;
604
605 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
606
607 switch (target) {
608 case GL_CONVOLUTION_1D:
609 c = 0;
610 conv = &ctx->Convolution1D;
611 break;
612 case GL_CONVOLUTION_2D:
613 c = 1;
614 conv = &ctx->Convolution2D;
615 break;
616 case GL_SEPARABLE_2D:
617 c = 2;
618 conv = &ctx->Separable2D;
619 break;
620 default:
621 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
622 return;
623 }
624
625 switch (pname) {
626 case GL_CONVOLUTION_BORDER_COLOR:
627 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
628 break;
629 case GL_CONVOLUTION_BORDER_MODE:
630 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
631 break;
632 case GL_CONVOLUTION_FILTER_SCALE:
633 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
634 break;
635 case GL_CONVOLUTION_FILTER_BIAS:
636 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
637 break;
638 case GL_CONVOLUTION_FORMAT:
639 *params = (GLfloat) conv->Format;
640 break;
641 case GL_CONVOLUTION_WIDTH:
642 *params = (GLfloat) conv->Width;
643 break;
644 case GL_CONVOLUTION_HEIGHT:
645 *params = (GLfloat) conv->Height;
646 break;
647 case GL_MAX_CONVOLUTION_WIDTH:
648 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
649 break;
650 case GL_MAX_CONVOLUTION_HEIGHT:
651 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
652 break;
653 default:
654 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
655 return;
656 }
657}
658
659
660void
661_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
662{
663 GET_CURRENT_CONTEXT(ctx);
664 const struct gl_convolution_attrib *conv;
665 GLuint c;
666
667 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
668
669 switch (target) {
670 case GL_CONVOLUTION_1D:
671 c = 0;
672 conv = &ctx->Convolution1D;
673 break;
674 case GL_CONVOLUTION_2D:
675 c = 1;
676 conv = &ctx->Convolution2D;
677 break;
678 case GL_SEPARABLE_2D:
679 c = 2;
680 conv = &ctx->Separable2D;
681 break;
682 default:
683 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
684 return;
685 }
686
687 switch (pname) {
688 case GL_CONVOLUTION_BORDER_COLOR:
689 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
690 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
691 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
692 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
693 break;
694 case GL_CONVOLUTION_BORDER_MODE:
695 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
696 break;
697 case GL_CONVOLUTION_FILTER_SCALE:
698 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
699 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
700 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
701 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
702 break;
703 case GL_CONVOLUTION_FILTER_BIAS:
704 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
705 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
706 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
707 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
708 break;
709 case GL_CONVOLUTION_FORMAT:
710 *params = (GLint) conv->Format;
711 break;
712 case GL_CONVOLUTION_WIDTH:
713 *params = (GLint) conv->Width;
714 break;
715 case GL_CONVOLUTION_HEIGHT:
716 *params = (GLint) conv->Height;
717 break;
718 case GL_MAX_CONVOLUTION_WIDTH:
719 *params = (GLint) ctx->Const.MaxConvolutionWidth;
720 break;
721 case GL_MAX_CONVOLUTION_HEIGHT:
722 *params = (GLint) ctx->Const.MaxConvolutionHeight;
723 break;
724 default:
725 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
726 return;
727 }
728}
729
730
731void
732_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
733{
Brian Paulf75d6972000-09-05 20:28:56 +0000734 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
735 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000736 GET_CURRENT_CONTEXT(ctx);
737 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
738
739 if (target != GL_SEPARABLE_2D) {
740 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
741 return;
742 }
743
744 if (!_mesa_is_legal_format_and_type(format, type) ||
745 format == GL_COLOR_INDEX ||
746 format == GL_STENCIL_INDEX ||
747 format == GL_DEPTH_COMPONENT ||
748 format == GL_INTENSITY ||
749 type == GL_BITMAP) {
750 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
751 return;
752 }
753
Brian Paulf75d6972000-09-05 20:28:56 +0000754 filter = &ctx->Separable2D;
755
756 /* Row filter */
757 {
758 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
759 filter->Height, format, type,
760 0, 0, 0);
761 _mesa_pack_float_rgba_span(ctx, filter->Width,
762 (const GLfloat (*)[4]) filter->Filter,
763 format, type, dst, &ctx->Pack, 0);
764 }
765
766 /* Column filter */
767 {
768 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
769 1, format, type,
770 0, 0, 0);
771 const GLfloat *src = filter->Filter + colStart;
772 _mesa_pack_float_rgba_span(ctx, filter->Height,
773 (const GLfloat (*)[4]) src,
774 format, type, dst, &ctx->Pack, 0);
775 }
776
777 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000778}
779
780
781void
782_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
783{
784 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
785 GLenum baseFormat;
786 GET_CURRENT_CONTEXT(ctx);
787 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
788
789 if (target != GL_SEPARABLE_2D) {
790 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
791 return;
792 }
793
794 baseFormat = base_filter_format(internalFormat);
795 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
796 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
797 return;
798 }
799
800 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
801 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
802 return;
803 }
804 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
805 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
806 return;
807 }
808
809 if (!_mesa_is_legal_format_and_type(format, type) ||
810 format == GL_COLOR_INDEX ||
811 format == GL_STENCIL_INDEX ||
812 format == GL_DEPTH_COMPONENT ||
813 format == GL_INTENSITY ||
814 type == GL_BITMAP) {
815 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
816 return;
817 }
818
819 ctx->Separable2D.Format = format;
820 ctx->Separable2D.InternalFormat = internalFormat;
821 ctx->Separable2D.Width = width;
822 ctx->Separable2D.Height = height;
823
824 /* unpack row filter */
825 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
826 ctx->Separable2D.Filter,
827 format, type, row, &ctx->Unpack,
828 0, GL_FALSE);
829
830 /* apply scale and bias */
831 {
832 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
833 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
834 GLint i;
835 for (i = 0; i < width; i++) {
836 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
837 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
838 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
839 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
840 r = r * scale[0] + bias[0];
841 g = g * scale[1] + bias[1];
842 b = b * scale[2] + bias[2];
843 a = a * scale[3] + bias[3];
844 ctx->Separable2D.Filter[i * 4 + 0] = r;
845 ctx->Separable2D.Filter[i * 4 + 1] = g;
846 ctx->Separable2D.Filter[i * 4 + 2] = b;
847 ctx->Separable2D.Filter[i * 4 + 3] = a;
848 }
849 }
850
851 /* unpack column filter */
852 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
853 &ctx->Separable2D.Filter[colStart],
854 format, type, column, &ctx->Unpack,
855 0, GL_FALSE);
856
857 /* apply scale and bias */
858 {
859 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
860 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
861 GLint i;
862 for (i = 0; i < width; i++) {
863 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
864 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
865 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
866 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
867 r = r * scale[0] + bias[0];
868 g = g * scale[1] + bias[1];
869 b = b * scale[2] + bias[2];
870 a = a * scale[3] + bias[3];
871 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
872 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
873 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
874 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
875 }
876 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000877
878 ctx->NewState |= _NEW_IMAGING;
Brian Paul147b0832000-08-23 14:31:25 +0000879}
880
881
882/**********************************************************************/
883/*** image convolution functions ***/
884/**********************************************************************/
885
Brian Pauld4b799b2000-08-21 14:24:30 +0000886static void
887convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
888 GLint filterWidth, const GLfloat filter[][4],
889 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000890{
Brian Paul7e708742000-08-22 18:54:25 +0000891 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000892 GLint i, n;
893
Brian Paul7e708742000-08-22 18:54:25 +0000894 if (filterWidth >= 1)
895 dstWidth = srcWidth - (filterWidth - 1);
896 else
897 dstWidth = srcWidth;
898
Brian Paulcc8e37f2000-07-12 13:00:09 +0000899 if (dstWidth <= 0)
900 return; /* null result */
901
902 for (i = 0; i < dstWidth; i++) {
903 GLfloat sumR = 0.0;
904 GLfloat sumG = 0.0;
905 GLfloat sumB = 0.0;
906 GLfloat sumA = 0.0;
907 for (n = 0; n < filterWidth; n++) {
908 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
909 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
910 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
911 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
912 }
913 dest[i][RCOMP] = sumR;
914 dest[i][GCOMP] = sumG;
915 dest[i][BCOMP] = sumB;
916 dest[i][ACOMP] = sumA;
917 }
918}
919
920
Brian Pauld4b799b2000-08-21 14:24:30 +0000921static void
922convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
923 GLint filterWidth, const GLfloat filter[][4],
924 GLfloat dest[][4],
925 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000926{
927 const GLint halfFilterWidth = filterWidth / 2;
928 GLint i, n;
929
930 for (i = 0; i < srcWidth; i++) {
931 GLfloat sumR = 0.0;
932 GLfloat sumG = 0.0;
933 GLfloat sumB = 0.0;
934 GLfloat sumA = 0.0;
935 for (n = 0; n < filterWidth; n++) {
936 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
937 sumR += borderColor[RCOMP] * filter[n][RCOMP];
938 sumG += borderColor[GCOMP] * filter[n][GCOMP];
939 sumB += borderColor[BCOMP] * filter[n][BCOMP];
940 sumA += borderColor[ACOMP] * filter[n][ACOMP];
941 }
942 else {
943 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
944 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
945 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
946 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
947 }
948 }
949 dest[i][RCOMP] = sumR;
950 dest[i][GCOMP] = sumG;
951 dest[i][BCOMP] = sumB;
952 dest[i][ACOMP] = sumA;
953 }
954}
955
956
Brian Pauld4b799b2000-08-21 14:24:30 +0000957static void
958convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
959 GLint filterWidth, const GLfloat filter[][4],
960 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000961{
962 const GLint halfFilterWidth = filterWidth / 2;
963 GLint i, n;
964
965 for (i = 0; i < srcWidth; i++) {
966 GLfloat sumR = 0.0;
967 GLfloat sumG = 0.0;
968 GLfloat sumB = 0.0;
969 GLfloat sumA = 0.0;
970 for (n = 0; n < filterWidth; n++) {
971 if (i + n < halfFilterWidth) {
972 sumR += src[0][RCOMP] * filter[n][RCOMP];
973 sumG += src[0][GCOMP] * filter[n][GCOMP];
974 sumB += src[0][BCOMP] * filter[n][BCOMP];
975 sumA += src[0][ACOMP] * filter[n][ACOMP];
976 }
977 else if (i + n - halfFilterWidth >= srcWidth) {
978 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
979 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
980 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
981 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
982 }
983 else {
984 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
985 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
986 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
987 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
988 }
989 }
990 dest[i][RCOMP] = sumR;
991 dest[i][GCOMP] = sumG;
992 dest[i][BCOMP] = sumB;
993 dest[i][ACOMP] = sumA;
994 }
995}
996
997
Brian Pauld4b799b2000-08-21 14:24:30 +0000998static void
999convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
1000 const GLfloat src[][4],
1001 GLint filterWidth, GLint filterHeight,
1002 const GLfloat filter[][4],
1003 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001004{
Brian Paul7e708742000-08-22 18:54:25 +00001005 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001006 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001007
Brian Paul7e708742000-08-22 18:54:25 +00001008 if (filterWidth >= 1)
1009 dstWidth = srcWidth - (filterWidth - 1);
1010 else
1011 dstWidth = srcWidth;
1012
1013 if (filterHeight >= 1)
1014 dstHeight = srcHeight - (filterHeight - 1);
1015 else
1016 dstHeight = srcHeight;
1017
Brian Pauld4b799b2000-08-21 14:24:30 +00001018 if (dstWidth <= 0 || dstHeight <= 0)
1019 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001020
Brian Pauld4b799b2000-08-21 14:24:30 +00001021 for (j = 0; j < dstHeight; j++) {
1022 for (i = 0; i < dstWidth; i++) {
1023 GLfloat sumR = 0.0;
1024 GLfloat sumG = 0.0;
1025 GLfloat sumB = 0.0;
1026 GLfloat sumA = 0.0;
1027 for (m = 0; m < filterHeight; m++) {
1028 for (n = 0; n < filterWidth; n++) {
1029 const GLint k = (j + m) * srcWidth + i + n;
1030 const GLint f = m * filterWidth + n;
1031 sumR += src[k][RCOMP] * filter[f][RCOMP];
1032 sumG += src[k][GCOMP] * filter[f][GCOMP];
1033 sumB += src[k][BCOMP] * filter[f][BCOMP];
1034 sumA += src[k][ACOMP] * filter[f][ACOMP];
1035 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001036 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001037 dest[j * dstWidth + i][RCOMP] = sumR;
1038 dest[j * dstWidth + i][GCOMP] = sumG;
1039 dest[j * dstWidth + i][BCOMP] = sumB;
1040 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001041 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001042 }
1043}
1044
1045
Brian Pauld4b799b2000-08-21 14:24:30 +00001046static void
1047convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1048 const GLfloat src[][4],
1049 GLint filterWidth, GLint filterHeight,
1050 const GLfloat filter[][4],
1051 GLfloat dest[][4],
1052 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001053{
1054 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001055 const GLint halfFilterHeight = filterHeight / 2;
1056 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001057
Brian Pauld4b799b2000-08-21 14:24:30 +00001058 for (j = 0; j < srcHeight; j++) {
1059 for (i = 0; i < srcWidth; i++) {
1060 GLfloat sumR = 0.0;
1061 GLfloat sumG = 0.0;
1062 GLfloat sumB = 0.0;
1063 GLfloat sumA = 0.0;
1064 for (m = 0; m < filterHeight; m++) {
1065 for (n = 0; n < filterWidth; n++) {
1066 const GLint f = m * filterWidth + n;
1067 const GLint is = i + n - halfFilterWidth;
1068 const GLint js = j + m - halfFilterHeight;
1069 if (is < 0 || is >= srcWidth ||
1070 js < 0 || js >= srcHeight) {
1071 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1072 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1073 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1074 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1075 }
1076 else {
1077 const GLint k = js * srcWidth + is;
1078 sumR += src[k][RCOMP] * filter[f][RCOMP];
1079 sumG += src[k][GCOMP] * filter[f][GCOMP];
1080 sumB += src[k][BCOMP] * filter[f][BCOMP];
1081 sumA += src[k][ACOMP] * filter[f][ACOMP];
1082 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001083 }
1084 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001085 dest[j * srcWidth + i][RCOMP] = sumR;
1086 dest[j * srcWidth + i][GCOMP] = sumG;
1087 dest[j * srcWidth + i][BCOMP] = sumB;
1088 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001089 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001090 }
1091}
1092
1093
Brian Pauld4b799b2000-08-21 14:24:30 +00001094static void
1095convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1096 const GLfloat src[][4],
1097 GLint filterWidth, GLint filterHeight,
1098 const GLfloat filter[][4],
1099 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001100{
1101 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001102 const GLint halfFilterHeight = filterHeight / 2;
1103 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001104
Brian Pauld4b799b2000-08-21 14:24:30 +00001105 for (j = 0; j < srcHeight; j++) {
1106 for (i = 0; i < srcWidth; i++) {
1107 GLfloat sumR = 0.0;
1108 GLfloat sumG = 0.0;
1109 GLfloat sumB = 0.0;
1110 GLfloat sumA = 0.0;
1111 for (m = 0; m < filterHeight; m++) {
1112 for (n = 0; n < filterWidth; n++) {
1113 const GLint f = m * filterWidth + n;
1114 GLint is = i + n - halfFilterWidth;
1115 GLint js = j + m - halfFilterHeight;
1116 GLint k;
1117 if (is < 0)
1118 is = 0;
1119 else if (is >= srcWidth)
1120 is = srcWidth - 1;
1121 if (js < 0)
1122 js = 0;
1123 else if (js >= srcHeight)
1124 js = srcHeight - 1;
1125 k = js * srcWidth + is;
1126 sumR += src[k][RCOMP] * filter[f][RCOMP];
1127 sumG += src[k][GCOMP] * filter[f][GCOMP];
1128 sumB += src[k][BCOMP] * filter[f][BCOMP];
1129 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001130 }
1131 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001132 dest[j * srcWidth + i][RCOMP] = sumR;
1133 dest[j * srcWidth + i][GCOMP] = sumG;
1134 dest[j * srcWidth + i][BCOMP] = sumB;
1135 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001136 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001137 }
1138}
1139
1140
Brian Pauld4b799b2000-08-21 14:24:30 +00001141static void
1142convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1143 const GLfloat src[][4],
1144 GLint filterWidth, GLint filterHeight,
1145 const GLfloat rowFilt[][4],
1146 const GLfloat colFilt[][4],
1147 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001148{
Brian Paul7e708742000-08-22 18:54:25 +00001149 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001150 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001151
1152 if (filterWidth >= 1)
1153 dstWidth = srcWidth - (filterWidth - 1);
1154 else
1155 dstWidth = srcWidth;
1156
1157 if (filterHeight >= 1)
1158 dstHeight = srcHeight - (filterHeight - 1);
1159 else
1160 dstHeight = srcHeight;
1161
1162 if (dstWidth <= 0 || dstHeight <= 0)
1163 return;
1164
1165 for (j = 0; j < dstHeight; j++) {
1166 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001167 GLfloat sumR = 0.0;
1168 GLfloat sumG = 0.0;
1169 GLfloat sumB = 0.0;
1170 GLfloat sumA = 0.0;
1171 for (m = 0; m < filterHeight; m++) {
1172 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001173 GLint k = (j + m) * srcWidth + i + n;
1174 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1175 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1176 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1177 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001178 }
1179 }
Brian Paul7e708742000-08-22 18:54:25 +00001180 dest[j * dstWidth + i][RCOMP] = sumR;
1181 dest[j * dstWidth + i][GCOMP] = sumG;
1182 dest[j * dstWidth + i][BCOMP] = sumB;
1183 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001184 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001185 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001186}
1187
1188
Brian Pauld4b799b2000-08-21 14:24:30 +00001189static void
1190convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1191 const GLfloat src[][4],
1192 GLint filterWidth, GLint filterHeight,
1193 const GLfloat rowFilt[][4],
1194 const GLfloat colFilt[][4],
1195 GLfloat dest[][4],
1196 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001197{
1198 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001199 const GLint halfFilterHeight = filterHeight / 2;
1200 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001201
Brian Pauld4b799b2000-08-21 14:24:30 +00001202 for (j = 0; j < srcHeight; j++) {
1203 for (i = 0; i < srcWidth; i++) {
1204 GLfloat sumR = 0.0;
1205 GLfloat sumG = 0.0;
1206 GLfloat sumB = 0.0;
1207 GLfloat sumA = 0.0;
1208 for (m = 0; m < filterHeight; m++) {
1209 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001210 const GLint is = i + n - halfFilterWidth;
1211 const GLint js = j + m - halfFilterHeight;
1212 if (is < 0 || is >= srcWidth ||
1213 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001214 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1215 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1216 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1217 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1218 }
1219 else {
Brian Paul7e708742000-08-22 18:54:25 +00001220 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001221 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1222 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1223 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1224 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1225 }
Brian Paul7e708742000-08-22 18:54:25 +00001226
Brian Paulcc8e37f2000-07-12 13:00:09 +00001227 }
1228 }
Brian Paul7e708742000-08-22 18:54:25 +00001229 dest[j * srcWidth + i][RCOMP] = sumR;
1230 dest[j * srcWidth + i][GCOMP] = sumG;
1231 dest[j * srcWidth + i][BCOMP] = sumB;
1232 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001233 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001234 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001235}
1236
1237
1238static void
1239convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1240 const GLfloat src[][4],
1241 GLint filterWidth, GLint filterHeight,
1242 const GLfloat rowFilt[][4],
1243 const GLfloat colFilt[][4],
1244 GLfloat dest[][4])
1245{
1246 const GLint halfFilterWidth = filterWidth / 2;
1247 const GLint halfFilterHeight = filterHeight / 2;
1248 GLint i, j, n, m;
1249
1250 for (j = 0; j < srcHeight; j++) {
1251 for (i = 0; i < srcWidth; i++) {
1252 GLfloat sumR = 0.0;
1253 GLfloat sumG = 0.0;
1254 GLfloat sumB = 0.0;
1255 GLfloat sumA = 0.0;
1256 for (m = 0; m < filterHeight; m++) {
1257 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001258 GLint is = i + n - halfFilterWidth;
1259 GLint js = j + m - halfFilterHeight;
1260 GLint k;
1261 if (is < 0)
1262 is = 0;
1263 else if (is >= srcWidth)
1264 is = srcWidth - 1;
1265 if (js < 0)
1266 js = 0;
1267 else if (js >= srcHeight)
1268 js = srcHeight - 1;
1269 k = js * srcWidth + is;
1270 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1271 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1272 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1273 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001274 }
1275 }
Brian Paul7e708742000-08-22 18:54:25 +00001276 dest[j * srcWidth + i][RCOMP] = sumR;
1277 dest[j * srcWidth + i][GCOMP] = sumG;
1278 dest[j * srcWidth + i][BCOMP] = sumB;
1279 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001280 }
1281 }
1282}
1283
1284
1285
1286void
1287_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1288 const GLfloat *srcImage, GLfloat *dstImage)
1289{
1290 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1291 case GL_REDUCE:
1292 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1293 ctx->Convolution1D.Width,
1294 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1295 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001296 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001297 break;
1298 case GL_CONSTANT_BORDER:
1299 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1300 ctx->Convolution1D.Width,
1301 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1302 (GLfloat (*)[4]) dstImage,
1303 ctx->Pixel.ConvolutionBorderColor[0]);
1304 break;
1305 case GL_REPLICATE_BORDER:
1306 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1307 ctx->Convolution1D.Width,
1308 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1309 (GLfloat (*)[4]) dstImage);
1310 break;
1311 default:
1312 ;
1313 }
1314}
1315
1316
1317void
1318_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1319 const GLfloat *srcImage, GLfloat *dstImage)
1320{
1321 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1322 case GL_REDUCE:
1323 convolve_2d_reduce(*width, *height,
1324 (const GLfloat (*)[4]) srcImage,
1325 ctx->Convolution2D.Width,
1326 ctx->Convolution2D.Height,
1327 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1328 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001329 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1330 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001331 break;
1332 case GL_CONSTANT_BORDER:
1333 convolve_2d_constant(*width, *height,
1334 (const GLfloat (*)[4]) srcImage,
1335 ctx->Convolution2D.Width,
1336 ctx->Convolution2D.Height,
1337 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1338 (GLfloat (*)[4]) dstImage,
1339 ctx->Pixel.ConvolutionBorderColor[1]);
1340 break;
1341 case GL_REPLICATE_BORDER:
1342 convolve_2d_replicate(*width, *height,
1343 (const GLfloat (*)[4]) srcImage,
1344 ctx->Convolution2D.Width,
1345 ctx->Convolution2D.Height,
1346 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1347 (GLfloat (*)[4]) dstImage);
1348 break;
1349 default:
1350 ;
1351 }
1352}
1353
1354
1355void
1356_mesa_convolve_sep_image(const GLcontext *ctx,
1357 GLsizei *width, GLsizei *height,
1358 const GLfloat *srcImage, GLfloat *dstImage)
1359{
1360 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1361 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1362
1363 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1364 case GL_REDUCE:
1365 convolve_sep_reduce(*width, *height,
1366 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001367 ctx->Separable2D.Width,
1368 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001369 (const GLfloat (*)[4]) rowFilter,
1370 (const GLfloat (*)[4]) colFilter,
1371 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001372 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1373 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001374 break;
1375 case GL_CONSTANT_BORDER:
1376 convolve_sep_constant(*width, *height,
1377 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001378 ctx->Separable2D.Width,
1379 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001380 (const GLfloat (*)[4]) rowFilter,
1381 (const GLfloat (*)[4]) colFilter,
1382 (GLfloat (*)[4]) dstImage,
1383 ctx->Pixel.ConvolutionBorderColor[2]);
1384 break;
1385 case GL_REPLICATE_BORDER:
1386 convolve_sep_replicate(*width, *height,
1387 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001388 ctx->Separable2D.Width,
1389 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001390 (const GLfloat (*)[4]) rowFilter,
1391 (const GLfloat (*)[4]) colFilter,
1392 (GLfloat (*)[4]) dstImage);
1393 break;
1394 default:
1395 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001396 }
1397}