blob: 252ef92e3d575ef701bc5ccfe11376efa70ce087 [file] [log] [blame]
Brian Paulf75d6972000-09-05 20:28:56 +00001/* $Id: convolve.c,v 1.5 2000/09/05 20:28:56 brianp 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 Pauld4b799b2000-08-21 14:24:30 +000040#include "convolve.h"
41#include "context.h"
Brian Paul147b0832000-08-23 14:31:25 +000042#include "image.h"
43#include "span.h"
Brian Paulcc8e37f2000-07-12 13:00:09 +000044#include "types.h"
45#endif
46
47
Brian Paul147b0832000-08-23 14:31:25 +000048/*
49 * Given an internalFormat token passed to glConvolutionFilter
50 * or glSeparableFilter, return the corresponding base format.
51 * Return -1 if invalid token.
52 */
53static GLint
54base_filter_format( GLenum format )
55{
56 switch (format) {
57 case GL_ALPHA:
58 case GL_ALPHA4:
59 case GL_ALPHA8:
60 case GL_ALPHA12:
61 case GL_ALPHA16:
62 return GL_ALPHA;
63 case GL_LUMINANCE:
64 case GL_LUMINANCE4:
65 case GL_LUMINANCE8:
66 case GL_LUMINANCE12:
67 case GL_LUMINANCE16:
68 return GL_LUMINANCE;
69 case GL_LUMINANCE_ALPHA:
70 case GL_LUMINANCE4_ALPHA4:
71 case GL_LUMINANCE6_ALPHA2:
72 case GL_LUMINANCE8_ALPHA8:
73 case GL_LUMINANCE12_ALPHA4:
74 case GL_LUMINANCE12_ALPHA12:
75 case GL_LUMINANCE16_ALPHA16:
76 return GL_LUMINANCE_ALPHA;
77 case GL_INTENSITY:
78 case GL_INTENSITY4:
79 case GL_INTENSITY8:
80 case GL_INTENSITY12:
81 case GL_INTENSITY16:
82 return GL_INTENSITY;
83 case GL_RGB:
84 case GL_R3_G3_B2:
85 case GL_RGB4:
86 case GL_RGB5:
87 case GL_RGB8:
88 case GL_RGB10:
89 case GL_RGB12:
90 case GL_RGB16:
91 return GL_RGB;
92 case 4:
93 case GL_RGBA:
94 case GL_RGBA2:
95 case GL_RGBA4:
96 case GL_RGB5_A1:
97 case GL_RGBA8:
98 case GL_RGB10_A2:
99 case GL_RGBA12:
100 case GL_RGBA16:
101 return GL_RGBA;
102 default:
103 return -1; /* error */
104 }
105}
106
107
108void
109_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
110{
111 GLenum baseFormat;
112 GET_CURRENT_CONTEXT(ctx);
113 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter1D");
114
115 if (target != GL_CONVOLUTION_1D) {
116 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
117 return;
118 }
119
120 baseFormat = base_filter_format(internalFormat);
121 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
122 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
123 return;
124 }
125
126 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
127 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
128 return;
129 }
130
131 if (!_mesa_is_legal_format_and_type(format, type) ||
132 format == GL_COLOR_INDEX ||
133 format == GL_STENCIL_INDEX ||
134 format == GL_DEPTH_COMPONENT ||
135 format == GL_INTENSITY ||
136 type == GL_BITMAP) {
137 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
138 return;
139 }
140
141 ctx->Convolution1D.Format = format;
142 ctx->Convolution1D.InternalFormat = internalFormat;
143 ctx->Convolution1D.Width = width;
144 ctx->Convolution1D.Height = 1;
145
146 /* unpack filter image */
147 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
148 ctx->Convolution1D.Filter,
149 format, type, image, &ctx->Unpack,
150 0, GL_FALSE);
151
152 /* apply scale and bias */
153 {
154 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
155 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
156 GLint i;
157 for (i = 0; i < width; i++) {
158 GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
159 GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
160 GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
161 GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
162 r = r * scale[0] + bias[0];
163 g = g * scale[1] + bias[1];
164 b = b * scale[2] + bias[2];
165 a = a * scale[3] + bias[3];
166 ctx->Convolution1D.Filter[i * 4 + 0] = r;
167 ctx->Convolution1D.Filter[i * 4 + 1] = g;
168 ctx->Convolution1D.Filter[i * 4 + 2] = b;
169 ctx->Convolution1D.Filter[i * 4 + 3] = a;
170 }
171 }
172}
173
174
175void
176_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
177{
178 GLenum baseFormat;
179 GLint i, components;
180 GET_CURRENT_CONTEXT(ctx);
181 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter2D");
182
183 if (target != GL_CONVOLUTION_2D) {
184 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
185 return;
186 }
187
188 baseFormat = base_filter_format(internalFormat);
189 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
190 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
191 return;
192 }
193
194 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
195 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
196 return;
197 }
198 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
199 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
200 return;
201 }
202
203 if (!_mesa_is_legal_format_and_type(format, type) ||
204 format == GL_COLOR_INDEX ||
205 format == GL_STENCIL_INDEX ||
206 format == GL_DEPTH_COMPONENT ||
207 format == GL_INTENSITY ||
208 type == GL_BITMAP) {
209 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
210 return;
211 }
212
213 components = _mesa_components_in_format(format);
214 assert(components > 0); /* this should have been caught earlier */
215
216 ctx->Convolution2D.Format = format;
217 ctx->Convolution2D.InternalFormat = internalFormat;
218 ctx->Convolution2D.Width = width;
219 ctx->Convolution2D.Height = height;
220
221 /* Unpack filter image. We always store filters in RGBA format. */
222 for (i = 0; i < height; i++) {
223 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
224 height, format, type, 0, i, 0);
225 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
226 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
227 format, type, src, &ctx->Unpack,
228 0, GL_FALSE);
229 }
230
231 /* apply scale and bias */
232 {
233 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
234 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
235 for (i = 0; i < width * height * 4; i++) {
236 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
237 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
238 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
239 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
240 r = r * scale[0] + bias[0];
241 g = g * scale[1] + bias[1];
242 b = b * scale[2] + bias[2];
243 a = a * scale[3] + bias[3];
244 ctx->Convolution2D.Filter[i * 4 + 0] = r;
245 ctx->Convolution2D.Filter[i * 4 + 1] = g;
246 ctx->Convolution2D.Filter[i * 4 + 2] = b;
247 ctx->Convolution2D.Filter[i * 4 + 3] = a;
248 }
249 }
250}
251
252
253void
254_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
255{
256 GET_CURRENT_CONTEXT(ctx);
257 GLuint c;
258
259 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterf");
260
261 switch (target) {
262 case GL_CONVOLUTION_1D:
263 c = 0;
264 break;
265 case GL_CONVOLUTION_2D:
266 c = 1;
267 break;
268 case GL_SEPARABLE_2D:
269 c = 2;
270 break;
271 default:
272 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
273 return;
274 }
275
276 switch (pname) {
277 case GL_CONVOLUTION_BORDER_MODE:
278 if (param == (GLfloat) GL_REDUCE ||
279 param == (GLfloat) GL_CONSTANT_BORDER ||
280 param == (GLfloat) GL_REPLICATE_BORDER) {
281 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
282 }
283 else {
284 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
285 return;
286 }
287 break;
288 default:
289 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
290 return;
291 }
292}
293
294
295void
296_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
297{
298 GET_CURRENT_CONTEXT(ctx);
299 struct gl_convolution_attrib *conv;
300 GLuint c;
301
302 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterfv");
303
304 switch (target) {
305 case GL_CONVOLUTION_1D:
306 c = 0;
307 conv = &ctx->Convolution1D;
308 break;
309 case GL_CONVOLUTION_2D:
310 c = 1;
311 conv = &ctx->Convolution2D;
312 break;
313 case GL_SEPARABLE_2D:
314 c = 2;
315 conv = &ctx->Separable2D;
316 break;
317 default:
318 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
319 return;
320 }
321
322 switch (pname) {
323 case GL_CONVOLUTION_BORDER_COLOR:
324 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
325 break;
326 case GL_CONVOLUTION_BORDER_MODE:
327 if (params[0] == (GLfloat) GL_REDUCE ||
328 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
329 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
330 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
331 }
332 else {
333 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
334 return;
335 }
336 break;
337 case GL_CONVOLUTION_FILTER_SCALE:
338 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
339 break;
340 case GL_CONVOLUTION_FILTER_BIAS:
341 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
342 break;
343 default:
344 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
345 return;
346 }
347}
348
349
350void
351_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
352{
353 GET_CURRENT_CONTEXT(ctx);
354 GLuint c;
355
356 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteri");
357
358 switch (target) {
359 case GL_CONVOLUTION_1D:
360 c = 0;
361 break;
362 case GL_CONVOLUTION_2D:
363 c = 1;
364 break;
365 case GL_SEPARABLE_2D:
366 c = 2;
367 break;
368 default:
369 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
370 return;
371 }
372
373 switch (pname) {
374 case GL_CONVOLUTION_BORDER_MODE:
375 if (param == (GLint) GL_REDUCE ||
376 param == (GLint) GL_CONSTANT_BORDER ||
377 param == (GLint) GL_REPLICATE_BORDER) {
378 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
379 }
380 else {
381 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
382 return;
383 }
384 break;
385 default:
386 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
387 return;
388 }
389}
390
391
392void
393_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
394{
395 GET_CURRENT_CONTEXT(ctx);
396 struct gl_convolution_attrib *conv;
397 GLuint c;
398
399 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteriv");
400
401 switch (target) {
402 case GL_CONVOLUTION_1D:
403 c = 0;
404 conv = &ctx->Convolution1D;
405 break;
406 case GL_CONVOLUTION_2D:
407 c = 1;
408 conv = &ctx->Convolution2D;
409 break;
410 case GL_SEPARABLE_2D:
411 c = 2;
412 conv = &ctx->Separable2D;
413 break;
414 default:
415 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
416 return;
417 }
418
419 switch (pname) {
420 case GL_CONVOLUTION_BORDER_COLOR:
421 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
422 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
423 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
424 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
425 break;
426 case GL_CONVOLUTION_BORDER_MODE:
427 if (params[0] == (GLint) GL_REDUCE ||
428 params[0] == (GLint) GL_CONSTANT_BORDER ||
429 params[0] == (GLint) GL_REPLICATE_BORDER) {
430 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
431 }
432 else {
433 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
434 return;
435 }
436 break;
437 case GL_CONVOLUTION_FILTER_SCALE:
438 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
439 break;
440 case GL_CONVOLUTION_FILTER_BIAS:
441 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
442 break;
443 default:
444 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
445 return;
446 }
447}
448
449
450void
451_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
452{
453 GLenum baseFormat;
454 GLfloat rgba[MAX_CONVOLUTION_WIDTH][4];
455 GET_CURRENT_CONTEXT(ctx);
456 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter1D");
457
458 if (target != GL_CONVOLUTION_1D) {
459 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
460 return;
461 }
462
463 baseFormat = base_filter_format(internalFormat);
464 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
465 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
466 return;
467 }
468
469 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
470 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
471 return;
472 }
473
474 /* read pixels from framebuffer */
475 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLubyte (*)[4]) rgba);
476
477 /* store as convolution filter */
478 _mesa_ConvolutionFilter1D(target, internalFormat, width,
479 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
480}
481
482
483void
484_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
485{
486 GLenum baseFormat;
487 GLint i;
488 struct gl_pixelstore_attrib packSave;
489 GLfloat rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
490 GET_CURRENT_CONTEXT(ctx);
491 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter2D");
492
493 if (target != GL_CONVOLUTION_2D) {
494 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
495 return;
496 }
497
498 baseFormat = base_filter_format(internalFormat);
499 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
500 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
501 return;
502 }
503
504 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
505 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
506 return;
507 }
508 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
509 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
510 return;
511 }
512
513 /* read pixels from framebuffer */
514 for (i = 0; i < height; i++) {
515 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
516 (GLubyte (*)[4]) rgba[i]);
517 }
518
519 /*
520 * store as convolution filter
521 */
522 packSave = ctx->Unpack; /* save pixel packing params */
523
524 ctx->Unpack.Alignment = 1;
525 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
526 ctx->Unpack.SkipPixels = 0;
527 ctx->Unpack.SkipRows = 0;
528 ctx->Unpack.ImageHeight = 0;
529 ctx->Unpack.SkipImages = 0;
530 ctx->Unpack.SwapBytes = GL_FALSE;
531 ctx->Unpack.LsbFirst = GL_FALSE;
532
533 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
534 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
535
536 ctx->Unpack = packSave; /* restore pixel packing params */
537}
538
539
540void
541_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
542{
Brian Paulf75d6972000-09-05 20:28:56 +0000543 const struct gl_convolution_attrib *filter;
544 GLint row;
Brian Paul147b0832000-08-23 14:31:25 +0000545 GET_CURRENT_CONTEXT(ctx);
546 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
547
Brian Paul147b0832000-08-23 14:31:25 +0000548 if (!_mesa_is_legal_format_and_type(format, type) ||
549 format == GL_COLOR_INDEX ||
550 format == GL_STENCIL_INDEX ||
551 format == GL_DEPTH_COMPONENT ||
552 format == GL_INTENSITY ||
553 type == GL_BITMAP) {
554 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
555 return;
556 }
557
Brian Paulf75d6972000-09-05 20:28:56 +0000558 switch (target) {
559 case GL_CONVOLUTION_1D:
560 filter = &(ctx->Convolution1D);
561 break;
562 case GL_CONVOLUTION_2D:
563 filter = &(ctx->Convolution2D);
564 break;
565 default:
566 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
567 return;
568 }
569
570 for (row = 0; row < filter->Height; row++) {
571 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
572 filter->Height, format, type,
573 0, row, 0);
574 const GLfloat *src = filter->Filter + row * filter->Width * 4;
575 /* XXX apply transfer ops or not? */
576 _mesa_pack_float_rgba_span(ctx, filter->Width,
577 (const GLfloat (*)[4]) src,
578 format, type, dst, &ctx->Pack, 0);
579 }
Brian Paul147b0832000-08-23 14:31:25 +0000580}
581
582
583void
584_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
585{
586 GET_CURRENT_CONTEXT(ctx);
587 const struct gl_convolution_attrib *conv;
588 GLuint c;
589
590 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
591
592 switch (target) {
593 case GL_CONVOLUTION_1D:
594 c = 0;
595 conv = &ctx->Convolution1D;
596 break;
597 case GL_CONVOLUTION_2D:
598 c = 1;
599 conv = &ctx->Convolution2D;
600 break;
601 case GL_SEPARABLE_2D:
602 c = 2;
603 conv = &ctx->Separable2D;
604 break;
605 default:
606 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
607 return;
608 }
609
610 switch (pname) {
611 case GL_CONVOLUTION_BORDER_COLOR:
612 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
613 break;
614 case GL_CONVOLUTION_BORDER_MODE:
615 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
616 break;
617 case GL_CONVOLUTION_FILTER_SCALE:
618 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
619 break;
620 case GL_CONVOLUTION_FILTER_BIAS:
621 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
622 break;
623 case GL_CONVOLUTION_FORMAT:
624 *params = (GLfloat) conv->Format;
625 break;
626 case GL_CONVOLUTION_WIDTH:
627 *params = (GLfloat) conv->Width;
628 break;
629 case GL_CONVOLUTION_HEIGHT:
630 *params = (GLfloat) conv->Height;
631 break;
632 case GL_MAX_CONVOLUTION_WIDTH:
633 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
634 break;
635 case GL_MAX_CONVOLUTION_HEIGHT:
636 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
637 break;
638 default:
639 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
640 return;
641 }
642}
643
644
645void
646_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
647{
648 GET_CURRENT_CONTEXT(ctx);
649 const struct gl_convolution_attrib *conv;
650 GLuint c;
651
652 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
653
654 switch (target) {
655 case GL_CONVOLUTION_1D:
656 c = 0;
657 conv = &ctx->Convolution1D;
658 break;
659 case GL_CONVOLUTION_2D:
660 c = 1;
661 conv = &ctx->Convolution2D;
662 break;
663 case GL_SEPARABLE_2D:
664 c = 2;
665 conv = &ctx->Separable2D;
666 break;
667 default:
668 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
669 return;
670 }
671
672 switch (pname) {
673 case GL_CONVOLUTION_BORDER_COLOR:
674 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
675 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
676 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
677 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
678 break;
679 case GL_CONVOLUTION_BORDER_MODE:
680 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
681 break;
682 case GL_CONVOLUTION_FILTER_SCALE:
683 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
684 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
685 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
686 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
687 break;
688 case GL_CONVOLUTION_FILTER_BIAS:
689 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
690 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
691 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
692 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
693 break;
694 case GL_CONVOLUTION_FORMAT:
695 *params = (GLint) conv->Format;
696 break;
697 case GL_CONVOLUTION_WIDTH:
698 *params = (GLint) conv->Width;
699 break;
700 case GL_CONVOLUTION_HEIGHT:
701 *params = (GLint) conv->Height;
702 break;
703 case GL_MAX_CONVOLUTION_WIDTH:
704 *params = (GLint) ctx->Const.MaxConvolutionWidth;
705 break;
706 case GL_MAX_CONVOLUTION_HEIGHT:
707 *params = (GLint) ctx->Const.MaxConvolutionHeight;
708 break;
709 default:
710 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
711 return;
712 }
713}
714
715
716void
717_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
718{
Brian Paulf75d6972000-09-05 20:28:56 +0000719 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
720 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000721 GET_CURRENT_CONTEXT(ctx);
722 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
723
724 if (target != GL_SEPARABLE_2D) {
725 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
726 return;
727 }
728
729 if (!_mesa_is_legal_format_and_type(format, type) ||
730 format == GL_COLOR_INDEX ||
731 format == GL_STENCIL_INDEX ||
732 format == GL_DEPTH_COMPONENT ||
733 format == GL_INTENSITY ||
734 type == GL_BITMAP) {
735 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
736 return;
737 }
738
Brian Paulf75d6972000-09-05 20:28:56 +0000739 filter = &ctx->Separable2D;
740
741 /* Row filter */
742 {
743 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
744 filter->Height, format, type,
745 0, 0, 0);
746 _mesa_pack_float_rgba_span(ctx, filter->Width,
747 (const GLfloat (*)[4]) filter->Filter,
748 format, type, dst, &ctx->Pack, 0);
749 }
750
751 /* Column filter */
752 {
753 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
754 1, format, type,
755 0, 0, 0);
756 const GLfloat *src = filter->Filter + colStart;
757 _mesa_pack_float_rgba_span(ctx, filter->Height,
758 (const GLfloat (*)[4]) src,
759 format, type, dst, &ctx->Pack, 0);
760 }
761
762 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000763}
764
765
766void
767_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
768{
769 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
770 GLenum baseFormat;
771 GET_CURRENT_CONTEXT(ctx);
772 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
773
774 if (target != GL_SEPARABLE_2D) {
775 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
776 return;
777 }
778
779 baseFormat = base_filter_format(internalFormat);
780 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
781 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
782 return;
783 }
784
785 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
786 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
787 return;
788 }
789 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
790 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
791 return;
792 }
793
794 if (!_mesa_is_legal_format_and_type(format, type) ||
795 format == GL_COLOR_INDEX ||
796 format == GL_STENCIL_INDEX ||
797 format == GL_DEPTH_COMPONENT ||
798 format == GL_INTENSITY ||
799 type == GL_BITMAP) {
800 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
801 return;
802 }
803
804 ctx->Separable2D.Format = format;
805 ctx->Separable2D.InternalFormat = internalFormat;
806 ctx->Separable2D.Width = width;
807 ctx->Separable2D.Height = height;
808
809 /* unpack row filter */
810 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
811 ctx->Separable2D.Filter,
812 format, type, row, &ctx->Unpack,
813 0, GL_FALSE);
814
815 /* apply scale and bias */
816 {
817 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
818 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
819 GLint i;
820 for (i = 0; i < width; i++) {
821 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
822 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
823 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
824 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
825 r = r * scale[0] + bias[0];
826 g = g * scale[1] + bias[1];
827 b = b * scale[2] + bias[2];
828 a = a * scale[3] + bias[3];
829 ctx->Separable2D.Filter[i * 4 + 0] = r;
830 ctx->Separable2D.Filter[i * 4 + 1] = g;
831 ctx->Separable2D.Filter[i * 4 + 2] = b;
832 ctx->Separable2D.Filter[i * 4 + 3] = a;
833 }
834 }
835
836 /* unpack column filter */
837 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
838 &ctx->Separable2D.Filter[colStart],
839 format, type, column, &ctx->Unpack,
840 0, GL_FALSE);
841
842 /* apply scale and bias */
843 {
844 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
845 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
846 GLint i;
847 for (i = 0; i < width; i++) {
848 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
849 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
850 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
851 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
852 r = r * scale[0] + bias[0];
853 g = g * scale[1] + bias[1];
854 b = b * scale[2] + bias[2];
855 a = a * scale[3] + bias[3];
856 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
857 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
858 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
859 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
860 }
861 }
862}
863
864
865/**********************************************************************/
866/*** image convolution functions ***/
867/**********************************************************************/
868
Brian Pauld4b799b2000-08-21 14:24:30 +0000869static void
870convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
871 GLint filterWidth, const GLfloat filter[][4],
872 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000873{
Brian Paul7e708742000-08-22 18:54:25 +0000874 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000875 GLint i, n;
876
Brian Paul7e708742000-08-22 18:54:25 +0000877 if (filterWidth >= 1)
878 dstWidth = srcWidth - (filterWidth - 1);
879 else
880 dstWidth = srcWidth;
881
Brian Paulcc8e37f2000-07-12 13:00:09 +0000882 if (dstWidth <= 0)
883 return; /* null result */
884
885 for (i = 0; i < dstWidth; i++) {
886 GLfloat sumR = 0.0;
887 GLfloat sumG = 0.0;
888 GLfloat sumB = 0.0;
889 GLfloat sumA = 0.0;
890 for (n = 0; n < filterWidth; n++) {
891 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
892 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
893 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
894 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
895 }
896 dest[i][RCOMP] = sumR;
897 dest[i][GCOMP] = sumG;
898 dest[i][BCOMP] = sumB;
899 dest[i][ACOMP] = sumA;
900 }
901}
902
903
Brian Pauld4b799b2000-08-21 14:24:30 +0000904static void
905convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
906 GLint filterWidth, const GLfloat filter[][4],
907 GLfloat dest[][4],
908 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000909{
910 const GLint halfFilterWidth = filterWidth / 2;
911 GLint i, n;
912
913 for (i = 0; i < srcWidth; i++) {
914 GLfloat sumR = 0.0;
915 GLfloat sumG = 0.0;
916 GLfloat sumB = 0.0;
917 GLfloat sumA = 0.0;
918 for (n = 0; n < filterWidth; n++) {
919 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
920 sumR += borderColor[RCOMP] * filter[n][RCOMP];
921 sumG += borderColor[GCOMP] * filter[n][GCOMP];
922 sumB += borderColor[BCOMP] * filter[n][BCOMP];
923 sumA += borderColor[ACOMP] * filter[n][ACOMP];
924 }
925 else {
926 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
927 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
928 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
929 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
930 }
931 }
932 dest[i][RCOMP] = sumR;
933 dest[i][GCOMP] = sumG;
934 dest[i][BCOMP] = sumB;
935 dest[i][ACOMP] = sumA;
936 }
937}
938
939
Brian Pauld4b799b2000-08-21 14:24:30 +0000940static void
941convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
942 GLint filterWidth, const GLfloat filter[][4],
943 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000944{
945 const GLint halfFilterWidth = filterWidth / 2;
946 GLint i, n;
947
948 for (i = 0; i < srcWidth; i++) {
949 GLfloat sumR = 0.0;
950 GLfloat sumG = 0.0;
951 GLfloat sumB = 0.0;
952 GLfloat sumA = 0.0;
953 for (n = 0; n < filterWidth; n++) {
954 if (i + n < halfFilterWidth) {
955 sumR += src[0][RCOMP] * filter[n][RCOMP];
956 sumG += src[0][GCOMP] * filter[n][GCOMP];
957 sumB += src[0][BCOMP] * filter[n][BCOMP];
958 sumA += src[0][ACOMP] * filter[n][ACOMP];
959 }
960 else if (i + n - halfFilterWidth >= srcWidth) {
961 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
962 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
963 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
964 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
965 }
966 else {
967 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
968 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
969 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
970 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
971 }
972 }
973 dest[i][RCOMP] = sumR;
974 dest[i][GCOMP] = sumG;
975 dest[i][BCOMP] = sumB;
976 dest[i][ACOMP] = sumA;
977 }
978}
979
980
Brian Pauld4b799b2000-08-21 14:24:30 +0000981static void
982convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
983 const GLfloat src[][4],
984 GLint filterWidth, GLint filterHeight,
985 const GLfloat filter[][4],
986 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000987{
Brian Paul7e708742000-08-22 18:54:25 +0000988 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +0000989 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000990
Brian Paul7e708742000-08-22 18:54:25 +0000991 if (filterWidth >= 1)
992 dstWidth = srcWidth - (filterWidth - 1);
993 else
994 dstWidth = srcWidth;
995
996 if (filterHeight >= 1)
997 dstHeight = srcHeight - (filterHeight - 1);
998 else
999 dstHeight = srcHeight;
1000
Brian Pauld4b799b2000-08-21 14:24:30 +00001001 if (dstWidth <= 0 || dstHeight <= 0)
1002 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001003
Brian Pauld4b799b2000-08-21 14:24:30 +00001004 for (j = 0; j < dstHeight; j++) {
1005 for (i = 0; i < dstWidth; i++) {
1006 GLfloat sumR = 0.0;
1007 GLfloat sumG = 0.0;
1008 GLfloat sumB = 0.0;
1009 GLfloat sumA = 0.0;
1010 for (m = 0; m < filterHeight; m++) {
1011 for (n = 0; n < filterWidth; n++) {
1012 const GLint k = (j + m) * srcWidth + i + n;
1013 const GLint f = m * filterWidth + n;
1014 sumR += src[k][RCOMP] * filter[f][RCOMP];
1015 sumG += src[k][GCOMP] * filter[f][GCOMP];
1016 sumB += src[k][BCOMP] * filter[f][BCOMP];
1017 sumA += src[k][ACOMP] * filter[f][ACOMP];
1018 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001019 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001020 dest[j * dstWidth + i][RCOMP] = sumR;
1021 dest[j * dstWidth + i][GCOMP] = sumG;
1022 dest[j * dstWidth + i][BCOMP] = sumB;
1023 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001024 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001025 }
1026}
1027
1028
Brian Pauld4b799b2000-08-21 14:24:30 +00001029static void
1030convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1031 const GLfloat src[][4],
1032 GLint filterWidth, GLint filterHeight,
1033 const GLfloat filter[][4],
1034 GLfloat dest[][4],
1035 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001036{
1037 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001038 const GLint halfFilterHeight = filterHeight / 2;
1039 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001040
Brian Pauld4b799b2000-08-21 14:24:30 +00001041 for (j = 0; j < srcHeight; j++) {
1042 for (i = 0; i < srcWidth; i++) {
1043 GLfloat sumR = 0.0;
1044 GLfloat sumG = 0.0;
1045 GLfloat sumB = 0.0;
1046 GLfloat sumA = 0.0;
1047 for (m = 0; m < filterHeight; m++) {
1048 for (n = 0; n < filterWidth; n++) {
1049 const GLint f = m * filterWidth + n;
1050 const GLint is = i + n - halfFilterWidth;
1051 const GLint js = j + m - halfFilterHeight;
1052 if (is < 0 || is >= srcWidth ||
1053 js < 0 || js >= srcHeight) {
1054 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1055 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1056 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1057 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1058 }
1059 else {
1060 const GLint k = js * srcWidth + is;
1061 sumR += src[k][RCOMP] * filter[f][RCOMP];
1062 sumG += src[k][GCOMP] * filter[f][GCOMP];
1063 sumB += src[k][BCOMP] * filter[f][BCOMP];
1064 sumA += src[k][ACOMP] * filter[f][ACOMP];
1065 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001066 }
1067 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001068 dest[j * srcWidth + i][RCOMP] = sumR;
1069 dest[j * srcWidth + i][GCOMP] = sumG;
1070 dest[j * srcWidth + i][BCOMP] = sumB;
1071 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001072 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001073 }
1074}
1075
1076
Brian Pauld4b799b2000-08-21 14:24:30 +00001077static void
1078convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1079 const GLfloat src[][4],
1080 GLint filterWidth, GLint filterHeight,
1081 const GLfloat filter[][4],
1082 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001083{
1084 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001085 const GLint halfFilterHeight = filterHeight / 2;
1086 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001087
Brian Pauld4b799b2000-08-21 14:24:30 +00001088 for (j = 0; j < srcHeight; j++) {
1089 for (i = 0; i < srcWidth; i++) {
1090 GLfloat sumR = 0.0;
1091 GLfloat sumG = 0.0;
1092 GLfloat sumB = 0.0;
1093 GLfloat sumA = 0.0;
1094 for (m = 0; m < filterHeight; m++) {
1095 for (n = 0; n < filterWidth; n++) {
1096 const GLint f = m * filterWidth + n;
1097 GLint is = i + n - halfFilterWidth;
1098 GLint js = j + m - halfFilterHeight;
1099 GLint k;
1100 if (is < 0)
1101 is = 0;
1102 else if (is >= srcWidth)
1103 is = srcWidth - 1;
1104 if (js < 0)
1105 js = 0;
1106 else if (js >= srcHeight)
1107 js = srcHeight - 1;
1108 k = js * srcWidth + is;
1109 sumR += src[k][RCOMP] * filter[f][RCOMP];
1110 sumG += src[k][GCOMP] * filter[f][GCOMP];
1111 sumB += src[k][BCOMP] * filter[f][BCOMP];
1112 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001113 }
1114 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001115 dest[j * srcWidth + i][RCOMP] = sumR;
1116 dest[j * srcWidth + i][GCOMP] = sumG;
1117 dest[j * srcWidth + i][BCOMP] = sumB;
1118 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001119 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001120 }
1121}
1122
1123
Brian Pauld4b799b2000-08-21 14:24:30 +00001124static void
1125convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1126 const GLfloat src[][4],
1127 GLint filterWidth, GLint filterHeight,
1128 const GLfloat rowFilt[][4],
1129 const GLfloat colFilt[][4],
1130 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001131{
Brian Paul7e708742000-08-22 18:54:25 +00001132 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001133 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001134
1135 if (filterWidth >= 1)
1136 dstWidth = srcWidth - (filterWidth - 1);
1137 else
1138 dstWidth = srcWidth;
1139
1140 if (filterHeight >= 1)
1141 dstHeight = srcHeight - (filterHeight - 1);
1142 else
1143 dstHeight = srcHeight;
1144
1145 if (dstWidth <= 0 || dstHeight <= 0)
1146 return;
1147
1148 for (j = 0; j < dstHeight; j++) {
1149 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001150 GLfloat sumR = 0.0;
1151 GLfloat sumG = 0.0;
1152 GLfloat sumB = 0.0;
1153 GLfloat sumA = 0.0;
1154 for (m = 0; m < filterHeight; m++) {
1155 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001156 GLint k = (j + m) * srcWidth + i + n;
1157 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1158 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1159 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1160 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001161 }
1162 }
Brian Paul7e708742000-08-22 18:54:25 +00001163 dest[j * dstWidth + i][RCOMP] = sumR;
1164 dest[j * dstWidth + i][GCOMP] = sumG;
1165 dest[j * dstWidth + i][BCOMP] = sumB;
1166 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001167 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001168 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001169}
1170
1171
Brian Pauld4b799b2000-08-21 14:24:30 +00001172static void
1173convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1174 const GLfloat src[][4],
1175 GLint filterWidth, GLint filterHeight,
1176 const GLfloat rowFilt[][4],
1177 const GLfloat colFilt[][4],
1178 GLfloat dest[][4],
1179 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001180{
1181 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001182 const GLint halfFilterHeight = filterHeight / 2;
1183 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001184
Brian Pauld4b799b2000-08-21 14:24:30 +00001185 for (j = 0; j < srcHeight; j++) {
1186 for (i = 0; i < srcWidth; i++) {
1187 GLfloat sumR = 0.0;
1188 GLfloat sumG = 0.0;
1189 GLfloat sumB = 0.0;
1190 GLfloat sumA = 0.0;
1191 for (m = 0; m < filterHeight; m++) {
1192 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001193 const GLint is = i + n - halfFilterWidth;
1194 const GLint js = j + m - halfFilterHeight;
1195 if (is < 0 || is >= srcWidth ||
1196 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001197 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1198 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1199 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1200 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1201 }
1202 else {
Brian Paul7e708742000-08-22 18:54:25 +00001203 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001204 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1205 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1206 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1207 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1208 }
Brian Paul7e708742000-08-22 18:54:25 +00001209
Brian Paulcc8e37f2000-07-12 13:00:09 +00001210 }
1211 }
Brian Paul7e708742000-08-22 18:54:25 +00001212 dest[j * srcWidth + i][RCOMP] = sumR;
1213 dest[j * srcWidth + i][GCOMP] = sumG;
1214 dest[j * srcWidth + i][BCOMP] = sumB;
1215 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001216 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001217 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001218}
1219
1220
1221static void
1222convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1223 const GLfloat src[][4],
1224 GLint filterWidth, GLint filterHeight,
1225 const GLfloat rowFilt[][4],
1226 const GLfloat colFilt[][4],
1227 GLfloat dest[][4])
1228{
1229 const GLint halfFilterWidth = filterWidth / 2;
1230 const GLint halfFilterHeight = filterHeight / 2;
1231 GLint i, j, n, m;
1232
1233 for (j = 0; j < srcHeight; j++) {
1234 for (i = 0; i < srcWidth; i++) {
1235 GLfloat sumR = 0.0;
1236 GLfloat sumG = 0.0;
1237 GLfloat sumB = 0.0;
1238 GLfloat sumA = 0.0;
1239 for (m = 0; m < filterHeight; m++) {
1240 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001241 GLint is = i + n - halfFilterWidth;
1242 GLint js = j + m - halfFilterHeight;
1243 GLint k;
1244 if (is < 0)
1245 is = 0;
1246 else if (is >= srcWidth)
1247 is = srcWidth - 1;
1248 if (js < 0)
1249 js = 0;
1250 else if (js >= srcHeight)
1251 js = srcHeight - 1;
1252 k = js * srcWidth + is;
1253 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1254 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1255 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1256 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001257 }
1258 }
Brian Paul7e708742000-08-22 18:54:25 +00001259 dest[j * srcWidth + i][RCOMP] = sumR;
1260 dest[j * srcWidth + i][GCOMP] = sumG;
1261 dest[j * srcWidth + i][BCOMP] = sumB;
1262 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001263 }
1264 }
1265}
1266
1267
1268
1269void
1270_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1271 const GLfloat *srcImage, GLfloat *dstImage)
1272{
1273 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1274 case GL_REDUCE:
1275 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1276 ctx->Convolution1D.Width,
1277 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1278 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001279 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001280 break;
1281 case GL_CONSTANT_BORDER:
1282 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1283 ctx->Convolution1D.Width,
1284 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1285 (GLfloat (*)[4]) dstImage,
1286 ctx->Pixel.ConvolutionBorderColor[0]);
1287 break;
1288 case GL_REPLICATE_BORDER:
1289 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1290 ctx->Convolution1D.Width,
1291 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1292 (GLfloat (*)[4]) dstImage);
1293 break;
1294 default:
1295 ;
1296 }
1297}
1298
1299
1300void
1301_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1302 const GLfloat *srcImage, GLfloat *dstImage)
1303{
1304 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1305 case GL_REDUCE:
1306 convolve_2d_reduce(*width, *height,
1307 (const GLfloat (*)[4]) srcImage,
1308 ctx->Convolution2D.Width,
1309 ctx->Convolution2D.Height,
1310 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1311 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001312 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1313 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001314 break;
1315 case GL_CONSTANT_BORDER:
1316 convolve_2d_constant(*width, *height,
1317 (const GLfloat (*)[4]) srcImage,
1318 ctx->Convolution2D.Width,
1319 ctx->Convolution2D.Height,
1320 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1321 (GLfloat (*)[4]) dstImage,
1322 ctx->Pixel.ConvolutionBorderColor[1]);
1323 break;
1324 case GL_REPLICATE_BORDER:
1325 convolve_2d_replicate(*width, *height,
1326 (const GLfloat (*)[4]) srcImage,
1327 ctx->Convolution2D.Width,
1328 ctx->Convolution2D.Height,
1329 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1330 (GLfloat (*)[4]) dstImage);
1331 break;
1332 default:
1333 ;
1334 }
1335}
1336
1337
1338void
1339_mesa_convolve_sep_image(const GLcontext *ctx,
1340 GLsizei *width, GLsizei *height,
1341 const GLfloat *srcImage, GLfloat *dstImage)
1342{
1343 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1344 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1345
1346 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1347 case GL_REDUCE:
1348 convolve_sep_reduce(*width, *height,
1349 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001350 ctx->Separable2D.Width,
1351 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001352 (const GLfloat (*)[4]) rowFilter,
1353 (const GLfloat (*)[4]) colFilter,
1354 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001355 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1356 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001357 break;
1358 case GL_CONSTANT_BORDER:
1359 convolve_sep_constant(*width, *height,
1360 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001361 ctx->Separable2D.Width,
1362 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001363 (const GLfloat (*)[4]) rowFilter,
1364 (const GLfloat (*)[4]) colFilter,
1365 (GLfloat (*)[4]) dstImage,
1366 ctx->Pixel.ConvolutionBorderColor[2]);
1367 break;
1368 case GL_REPLICATE_BORDER:
1369 convolve_sep_replicate(*width, *height,
1370 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001371 ctx->Separable2D.Width,
1372 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001373 (const GLfloat (*)[4]) rowFilter,
1374 (const GLfloat (*)[4]) colFilter,
1375 (GLfloat (*)[4]) dstImage);
1376 break;
1377 default:
1378 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001379 }
1380}