blob: 6b24600f31d9dc854acf78b9c9a205db22634b2f [file] [log] [blame]
Keith Whitwell724abeb2000-10-31 18:09:44 +00001/* $Id: convolve.c,v 1.9 2000/10/31 18:09:44 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"
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 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000172
173 ctx->NewState |= _NEW_IMAGING;
Brian Paul147b0832000-08-23 14:31:25 +0000174}
175
176
177void
178_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
179{
180 GLenum baseFormat;
181 GLint i, components;
182 GET_CURRENT_CONTEXT(ctx);
183 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionFilter2D");
184
185 if (target != GL_CONVOLUTION_2D) {
186 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
187 return;
188 }
189
190 baseFormat = base_filter_format(internalFormat);
191 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
192 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
193 return;
194 }
195
196 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
197 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
198 return;
199 }
200 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
201 gl_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
202 return;
203 }
204
205 if (!_mesa_is_legal_format_and_type(format, type) ||
206 format == GL_COLOR_INDEX ||
207 format == GL_STENCIL_INDEX ||
208 format == GL_DEPTH_COMPONENT ||
209 format == GL_INTENSITY ||
210 type == GL_BITMAP) {
211 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
212 return;
213 }
214
215 components = _mesa_components_in_format(format);
216 assert(components > 0); /* this should have been caught earlier */
217
218 ctx->Convolution2D.Format = format;
219 ctx->Convolution2D.InternalFormat = internalFormat;
220 ctx->Convolution2D.Width = width;
221 ctx->Convolution2D.Height = height;
222
223 /* Unpack filter image. We always store filters in RGBA format. */
224 for (i = 0; i < height; i++) {
225 const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
226 height, format, type, 0, i, 0);
227 GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
228 _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
229 format, type, src, &ctx->Unpack,
230 0, GL_FALSE);
231 }
232
233 /* apply scale and bias */
234 {
235 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
236 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
237 for (i = 0; i < width * height * 4; i++) {
238 GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
239 GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
240 GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
241 GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
242 r = r * scale[0] + bias[0];
243 g = g * scale[1] + bias[1];
244 b = b * scale[2] + bias[2];
245 a = a * scale[3] + bias[3];
246 ctx->Convolution2D.Filter[i * 4 + 0] = r;
247 ctx->Convolution2D.Filter[i * 4 + 1] = g;
248 ctx->Convolution2D.Filter[i * 4 + 2] = b;
249 ctx->Convolution2D.Filter[i * 4 + 3] = a;
250 }
251 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000252
253 ctx->NewState |= _NEW_IMAGING;
Brian Paul147b0832000-08-23 14:31:25 +0000254}
255
256
257void
258_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
259{
260 GET_CURRENT_CONTEXT(ctx);
261 GLuint c;
262
263 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterf");
264
265 switch (target) {
266 case GL_CONVOLUTION_1D:
267 c = 0;
268 break;
269 case GL_CONVOLUTION_2D:
270 c = 1;
271 break;
272 case GL_SEPARABLE_2D:
273 c = 2;
274 break;
275 default:
276 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
277 return;
278 }
279
280 switch (pname) {
281 case GL_CONVOLUTION_BORDER_MODE:
282 if (param == (GLfloat) GL_REDUCE ||
283 param == (GLfloat) GL_CONSTANT_BORDER ||
284 param == (GLfloat) GL_REPLICATE_BORDER) {
285 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
286 }
287 else {
288 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
289 return;
290 }
291 break;
292 default:
293 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
294 return;
295 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000296
297 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000298}
299
300
301void
302_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
303{
304 GET_CURRENT_CONTEXT(ctx);
305 struct gl_convolution_attrib *conv;
306 GLuint c;
307
308 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameterfv");
309
310 switch (target) {
311 case GL_CONVOLUTION_1D:
312 c = 0;
313 conv = &ctx->Convolution1D;
314 break;
315 case GL_CONVOLUTION_2D:
316 c = 1;
317 conv = &ctx->Convolution2D;
318 break;
319 case GL_SEPARABLE_2D:
320 c = 2;
321 conv = &ctx->Separable2D;
322 break;
323 default:
324 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
325 return;
326 }
327
328 switch (pname) {
329 case GL_CONVOLUTION_BORDER_COLOR:
330 COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
331 break;
332 case GL_CONVOLUTION_BORDER_MODE:
333 if (params[0] == (GLfloat) GL_REDUCE ||
334 params[0] == (GLfloat) GL_CONSTANT_BORDER ||
335 params[0] == (GLfloat) GL_REPLICATE_BORDER) {
336 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
337 }
338 else {
339 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
340 return;
341 }
342 break;
343 case GL_CONVOLUTION_FILTER_SCALE:
344 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
345 break;
346 case GL_CONVOLUTION_FILTER_BIAS:
347 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
348 break;
349 default:
350 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
351 return;
352 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000353
354 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000355}
356
357
358void
359_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
360{
361 GET_CURRENT_CONTEXT(ctx);
362 GLuint c;
363
364 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteri");
365
366 switch (target) {
367 case GL_CONVOLUTION_1D:
368 c = 0;
369 break;
370 case GL_CONVOLUTION_2D:
371 c = 1;
372 break;
373 case GL_SEPARABLE_2D:
374 c = 2;
375 break;
376 default:
377 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
378 return;
379 }
380
381 switch (pname) {
382 case GL_CONVOLUTION_BORDER_MODE:
383 if (param == (GLint) GL_REDUCE ||
384 param == (GLint) GL_CONSTANT_BORDER ||
385 param == (GLint) GL_REPLICATE_BORDER) {
386 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
387 }
388 else {
389 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
390 return;
391 }
392 break;
393 default:
394 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
395 return;
396 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000397
398 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000399}
400
401
402void
403_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
404{
405 GET_CURRENT_CONTEXT(ctx);
406 struct gl_convolution_attrib *conv;
407 GLuint c;
408
409 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glConvolutionParameteriv");
410
411 switch (target) {
412 case GL_CONVOLUTION_1D:
413 c = 0;
414 conv = &ctx->Convolution1D;
415 break;
416 case GL_CONVOLUTION_2D:
417 c = 1;
418 conv = &ctx->Convolution2D;
419 break;
420 case GL_SEPARABLE_2D:
421 c = 2;
422 conv = &ctx->Separable2D;
423 break;
424 default:
425 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(target)");
426 return;
427 }
428
429 switch (pname) {
430 case GL_CONVOLUTION_BORDER_COLOR:
431 ctx->Pixel.ConvolutionBorderColor[c][0] = INT_TO_FLOAT(params[0]);
432 ctx->Pixel.ConvolutionBorderColor[c][1] = INT_TO_FLOAT(params[1]);
433 ctx->Pixel.ConvolutionBorderColor[c][2] = INT_TO_FLOAT(params[2]);
434 ctx->Pixel.ConvolutionBorderColor[c][3] = INT_TO_FLOAT(params[3]);
435 break;
436 case GL_CONVOLUTION_BORDER_MODE:
437 if (params[0] == (GLint) GL_REDUCE ||
438 params[0] == (GLint) GL_CONSTANT_BORDER ||
439 params[0] == (GLint) GL_REPLICATE_BORDER) {
440 ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
441 }
442 else {
443 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(params)");
444 return;
445 }
446 break;
447 case GL_CONVOLUTION_FILTER_SCALE:
448 COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
449 break;
450 case GL_CONVOLUTION_FILTER_BIAS:
451 COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
452 break;
453 default:
454 gl_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
455 return;
456 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000457
458 ctx->NewState |= _NEW_PIXEL;
Brian Paul147b0832000-08-23 14:31:25 +0000459}
460
461
462void
463_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
464{
465 GLenum baseFormat;
466 GLfloat rgba[MAX_CONVOLUTION_WIDTH][4];
467 GET_CURRENT_CONTEXT(ctx);
468 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter1D");
469
470 if (target != GL_CONVOLUTION_1D) {
471 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
472 return;
473 }
474
475 baseFormat = base_filter_format(internalFormat);
476 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
477 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
478 return;
479 }
480
481 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
482 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
483 return;
484 }
485
486 /* read pixels from framebuffer */
Brian Paulba643a22000-10-28 18:34:48 +0000487 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y, (GLchan (*)[4]) rgba);
Brian Paul147b0832000-08-23 14:31:25 +0000488
489 /* store as convolution filter */
490 _mesa_ConvolutionFilter1D(target, internalFormat, width,
491 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
492}
493
494
495void
496_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
497{
498 GLenum baseFormat;
499 GLint i;
500 struct gl_pixelstore_attrib packSave;
501 GLfloat rgba[MAX_CONVOLUTION_HEIGHT][MAX_CONVOLUTION_WIDTH][4];
502 GET_CURRENT_CONTEXT(ctx);
503 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyConvolutionFilter2D");
504
505 if (target != GL_CONVOLUTION_2D) {
506 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
507 return;
508 }
509
510 baseFormat = base_filter_format(internalFormat);
511 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
512 gl_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
513 return;
514 }
515
516 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
517 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
518 return;
519 }
520 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
521 gl_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
522 return;
523 }
524
525 /* read pixels from framebuffer */
526 for (i = 0; i < height; i++) {
527 gl_read_rgba_span(ctx, ctx->ReadBuffer, width, x, y + i,
Brian Paulba643a22000-10-28 18:34:48 +0000528 (GLchan (*)[4]) rgba[i]);
Brian Paul147b0832000-08-23 14:31:25 +0000529 }
530
531 /*
532 * store as convolution filter
533 */
534 packSave = ctx->Unpack; /* save pixel packing params */
535
536 ctx->Unpack.Alignment = 1;
537 ctx->Unpack.RowLength = MAX_CONVOLUTION_WIDTH;
538 ctx->Unpack.SkipPixels = 0;
539 ctx->Unpack.SkipRows = 0;
540 ctx->Unpack.ImageHeight = 0;
541 ctx->Unpack.SkipImages = 0;
542 ctx->Unpack.SwapBytes = GL_FALSE;
543 ctx->Unpack.LsbFirst = GL_FALSE;
Keith Whitwella96308c2000-10-30 13:31:59 +0000544 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000545
546 _mesa_ConvolutionFilter2D(target, internalFormat, width, height,
547 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
548
549 ctx->Unpack = packSave; /* restore pixel packing params */
Keith Whitwella96308c2000-10-30 13:31:59 +0000550 ctx->NewState |= _NEW_PACKUNPACK;
Brian Paul147b0832000-08-23 14:31:25 +0000551}
552
553
554void
555_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
556{
Brian Paulf75d6972000-09-05 20:28:56 +0000557 const struct gl_convolution_attrib *filter;
558 GLint row;
Brian Paul147b0832000-08-23 14:31:25 +0000559 GET_CURRENT_CONTEXT(ctx);
560 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionFilter");
561
Brian Paul147b0832000-08-23 14:31:25 +0000562 if (!_mesa_is_legal_format_and_type(format, type) ||
563 format == GL_COLOR_INDEX ||
564 format == GL_STENCIL_INDEX ||
565 format == GL_DEPTH_COMPONENT ||
566 format == GL_INTENSITY ||
567 type == GL_BITMAP) {
568 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
569 return;
570 }
571
Brian Paulf75d6972000-09-05 20:28:56 +0000572 switch (target) {
573 case GL_CONVOLUTION_1D:
574 filter = &(ctx->Convolution1D);
575 break;
576 case GL_CONVOLUTION_2D:
577 filter = &(ctx->Convolution2D);
578 break;
579 default:
580 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
581 return;
582 }
583
584 for (row = 0; row < filter->Height; row++) {
585 GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
586 filter->Height, format, type,
587 0, row, 0);
588 const GLfloat *src = filter->Filter + row * filter->Width * 4;
589 /* XXX apply transfer ops or not? */
590 _mesa_pack_float_rgba_span(ctx, filter->Width,
591 (const GLfloat (*)[4]) src,
592 format, type, dst, &ctx->Pack, 0);
593 }
Brian Paul147b0832000-08-23 14:31:25 +0000594}
595
596
597void
598_mesa_GetConvolutionParameterfv(GLenum target, GLenum pname, GLfloat *params)
599{
600 GET_CURRENT_CONTEXT(ctx);
601 const struct gl_convolution_attrib *conv;
602 GLuint c;
603
604 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameterfv");
605
606 switch (target) {
607 case GL_CONVOLUTION_1D:
608 c = 0;
609 conv = &ctx->Convolution1D;
610 break;
611 case GL_CONVOLUTION_2D:
612 c = 1;
613 conv = &ctx->Convolution2D;
614 break;
615 case GL_SEPARABLE_2D:
616 c = 2;
617 conv = &ctx->Separable2D;
618 break;
619 default:
620 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
621 return;
622 }
623
624 switch (pname) {
625 case GL_CONVOLUTION_BORDER_COLOR:
626 COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
627 break;
628 case GL_CONVOLUTION_BORDER_MODE:
629 *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
630 break;
631 case GL_CONVOLUTION_FILTER_SCALE:
632 COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
633 break;
634 case GL_CONVOLUTION_FILTER_BIAS:
635 COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
636 break;
637 case GL_CONVOLUTION_FORMAT:
638 *params = (GLfloat) conv->Format;
639 break;
640 case GL_CONVOLUTION_WIDTH:
641 *params = (GLfloat) conv->Width;
642 break;
643 case GL_CONVOLUTION_HEIGHT:
644 *params = (GLfloat) conv->Height;
645 break;
646 case GL_MAX_CONVOLUTION_WIDTH:
647 *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
648 break;
649 case GL_MAX_CONVOLUTION_HEIGHT:
650 *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
651 break;
652 default:
653 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
654 return;
655 }
656}
657
658
659void
660_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
661{
662 GET_CURRENT_CONTEXT(ctx);
663 const struct gl_convolution_attrib *conv;
664 GLuint c;
665
666 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetConvolutionParameteriv");
667
668 switch (target) {
669 case GL_CONVOLUTION_1D:
670 c = 0;
671 conv = &ctx->Convolution1D;
672 break;
673 case GL_CONVOLUTION_2D:
674 c = 1;
675 conv = &ctx->Convolution2D;
676 break;
677 case GL_SEPARABLE_2D:
678 c = 2;
679 conv = &ctx->Separable2D;
680 break;
681 default:
682 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
683 return;
684 }
685
686 switch (pname) {
687 case GL_CONVOLUTION_BORDER_COLOR:
688 params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
689 params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
690 params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
691 params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
692 break;
693 case GL_CONVOLUTION_BORDER_MODE:
694 *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
695 break;
696 case GL_CONVOLUTION_FILTER_SCALE:
697 params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
698 params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
699 params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
700 params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
701 break;
702 case GL_CONVOLUTION_FILTER_BIAS:
703 params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
704 params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
705 params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
706 params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
707 break;
708 case GL_CONVOLUTION_FORMAT:
709 *params = (GLint) conv->Format;
710 break;
711 case GL_CONVOLUTION_WIDTH:
712 *params = (GLint) conv->Width;
713 break;
714 case GL_CONVOLUTION_HEIGHT:
715 *params = (GLint) conv->Height;
716 break;
717 case GL_MAX_CONVOLUTION_WIDTH:
718 *params = (GLint) ctx->Const.MaxConvolutionWidth;
719 break;
720 case GL_MAX_CONVOLUTION_HEIGHT:
721 *params = (GLint) ctx->Const.MaxConvolutionHeight;
722 break;
723 default:
724 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
725 return;
726 }
727}
728
729
730void
731_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
732{
Brian Paulf75d6972000-09-05 20:28:56 +0000733 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
734 const struct gl_convolution_attrib *filter;
Brian Paul147b0832000-08-23 14:31:25 +0000735 GET_CURRENT_CONTEXT(ctx);
736 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glGetSeparableFilter");
737
738 if (target != GL_SEPARABLE_2D) {
739 gl_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
740 return;
741 }
742
743 if (!_mesa_is_legal_format_and_type(format, type) ||
744 format == GL_COLOR_INDEX ||
745 format == GL_STENCIL_INDEX ||
746 format == GL_DEPTH_COMPONENT ||
747 format == GL_INTENSITY ||
748 type == GL_BITMAP) {
749 gl_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
750 return;
751 }
752
Brian Paulf75d6972000-09-05 20:28:56 +0000753 filter = &ctx->Separable2D;
754
755 /* Row filter */
756 {
757 GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
758 filter->Height, format, type,
759 0, 0, 0);
760 _mesa_pack_float_rgba_span(ctx, filter->Width,
761 (const GLfloat (*)[4]) filter->Filter,
762 format, type, dst, &ctx->Pack, 0);
763 }
764
765 /* Column filter */
766 {
767 GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
768 1, format, type,
769 0, 0, 0);
770 const GLfloat *src = filter->Filter + colStart;
771 _mesa_pack_float_rgba_span(ctx, filter->Height,
772 (const GLfloat (*)[4]) src,
773 format, type, dst, &ctx->Pack, 0);
774 }
775
776 (void) span; /* unused at this time */
Brian Paul147b0832000-08-23 14:31:25 +0000777}
778
779
780void
781_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
782{
783 const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
784 GLenum baseFormat;
785 GET_CURRENT_CONTEXT(ctx);
786 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glSeparableFilter2D");
787
788 if (target != GL_SEPARABLE_2D) {
789 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
790 return;
791 }
792
793 baseFormat = base_filter_format(internalFormat);
794 if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
795 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
796 return;
797 }
798
799 if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
800 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
801 return;
802 }
803 if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
804 gl_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
805 return;
806 }
807
808 if (!_mesa_is_legal_format_and_type(format, type) ||
809 format == GL_COLOR_INDEX ||
810 format == GL_STENCIL_INDEX ||
811 format == GL_DEPTH_COMPONENT ||
812 format == GL_INTENSITY ||
813 type == GL_BITMAP) {
814 gl_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
815 return;
816 }
817
818 ctx->Separable2D.Format = format;
819 ctx->Separable2D.InternalFormat = internalFormat;
820 ctx->Separable2D.Width = width;
821 ctx->Separable2D.Height = height;
822
823 /* unpack row filter */
824 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
825 ctx->Separable2D.Filter,
826 format, type, row, &ctx->Unpack,
827 0, GL_FALSE);
828
829 /* apply scale and bias */
830 {
831 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
832 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
833 GLint i;
834 for (i = 0; i < width; i++) {
835 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
836 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
837 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
838 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
839 r = r * scale[0] + bias[0];
840 g = g * scale[1] + bias[1];
841 b = b * scale[2] + bias[2];
842 a = a * scale[3] + bias[3];
843 ctx->Separable2D.Filter[i * 4 + 0] = r;
844 ctx->Separable2D.Filter[i * 4 + 1] = g;
845 ctx->Separable2D.Filter[i * 4 + 2] = b;
846 ctx->Separable2D.Filter[i * 4 + 3] = a;
847 }
848 }
849
850 /* unpack column filter */
851 _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
852 &ctx->Separable2D.Filter[colStart],
853 format, type, column, &ctx->Unpack,
854 0, GL_FALSE);
855
856 /* apply scale and bias */
857 {
858 const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
859 const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
860 GLint i;
861 for (i = 0; i < width; i++) {
862 GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
863 GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
864 GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
865 GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
866 r = r * scale[0] + bias[0];
867 g = g * scale[1] + bias[1];
868 b = b * scale[2] + bias[2];
869 a = a * scale[3] + bias[3];
870 ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
871 ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
872 ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
873 ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
874 }
875 }
Keith Whitwella96308c2000-10-30 13:31:59 +0000876
877 ctx->NewState |= _NEW_IMAGING;
Brian Paul147b0832000-08-23 14:31:25 +0000878}
879
880
881/**********************************************************************/
882/*** image convolution functions ***/
883/**********************************************************************/
884
Brian Pauld4b799b2000-08-21 14:24:30 +0000885static void
886convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
887 GLint filterWidth, const GLfloat filter[][4],
888 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000889{
Brian Paul7e708742000-08-22 18:54:25 +0000890 GLint dstWidth;
Brian Paulcc8e37f2000-07-12 13:00:09 +0000891 GLint i, n;
892
Brian Paul7e708742000-08-22 18:54:25 +0000893 if (filterWidth >= 1)
894 dstWidth = srcWidth - (filterWidth - 1);
895 else
896 dstWidth = srcWidth;
897
Brian Paulcc8e37f2000-07-12 13:00:09 +0000898 if (dstWidth <= 0)
899 return; /* null result */
900
901 for (i = 0; i < dstWidth; i++) {
902 GLfloat sumR = 0.0;
903 GLfloat sumG = 0.0;
904 GLfloat sumB = 0.0;
905 GLfloat sumA = 0.0;
906 for (n = 0; n < filterWidth; n++) {
907 sumR += src[i + n][RCOMP] * filter[n][RCOMP];
908 sumG += src[i + n][GCOMP] * filter[n][GCOMP];
909 sumB += src[i + n][BCOMP] * filter[n][BCOMP];
910 sumA += src[i + n][ACOMP] * filter[n][ACOMP];
911 }
912 dest[i][RCOMP] = sumR;
913 dest[i][GCOMP] = sumG;
914 dest[i][BCOMP] = sumB;
915 dest[i][ACOMP] = sumA;
916 }
917}
918
919
Brian Pauld4b799b2000-08-21 14:24:30 +0000920static void
921convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
922 GLint filterWidth, const GLfloat filter[][4],
923 GLfloat dest[][4],
924 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000925{
926 const GLint halfFilterWidth = filterWidth / 2;
927 GLint i, n;
928
929 for (i = 0; i < srcWidth; i++) {
930 GLfloat sumR = 0.0;
931 GLfloat sumG = 0.0;
932 GLfloat sumB = 0.0;
933 GLfloat sumA = 0.0;
934 for (n = 0; n < filterWidth; n++) {
935 if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
936 sumR += borderColor[RCOMP] * filter[n][RCOMP];
937 sumG += borderColor[GCOMP] * filter[n][GCOMP];
938 sumB += borderColor[BCOMP] * filter[n][BCOMP];
939 sumA += borderColor[ACOMP] * filter[n][ACOMP];
940 }
941 else {
942 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
943 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
944 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
945 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
946 }
947 }
948 dest[i][RCOMP] = sumR;
949 dest[i][GCOMP] = sumG;
950 dest[i][BCOMP] = sumB;
951 dest[i][ACOMP] = sumA;
952 }
953}
954
955
Brian Pauld4b799b2000-08-21 14:24:30 +0000956static void
957convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
958 GLint filterWidth, const GLfloat filter[][4],
959 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +0000960{
961 const GLint halfFilterWidth = filterWidth / 2;
962 GLint i, n;
963
964 for (i = 0; i < srcWidth; i++) {
965 GLfloat sumR = 0.0;
966 GLfloat sumG = 0.0;
967 GLfloat sumB = 0.0;
968 GLfloat sumA = 0.0;
969 for (n = 0; n < filterWidth; n++) {
970 if (i + n < halfFilterWidth) {
971 sumR += src[0][RCOMP] * filter[n][RCOMP];
972 sumG += src[0][GCOMP] * filter[n][GCOMP];
973 sumB += src[0][BCOMP] * filter[n][BCOMP];
974 sumA += src[0][ACOMP] * filter[n][ACOMP];
975 }
976 else if (i + n - halfFilterWidth >= srcWidth) {
977 sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
978 sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
979 sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
980 sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
981 }
982 else {
983 sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
984 sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
985 sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
986 sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
987 }
988 }
989 dest[i][RCOMP] = sumR;
990 dest[i][GCOMP] = sumG;
991 dest[i][BCOMP] = sumB;
992 dest[i][ACOMP] = sumA;
993 }
994}
995
996
Brian Pauld4b799b2000-08-21 14:24:30 +0000997static void
998convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
999 const GLfloat src[][4],
1000 GLint filterWidth, GLint filterHeight,
1001 const GLfloat filter[][4],
1002 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001003{
Brian Paul7e708742000-08-22 18:54:25 +00001004 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001005 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001006
Brian Paul7e708742000-08-22 18:54:25 +00001007 if (filterWidth >= 1)
1008 dstWidth = srcWidth - (filterWidth - 1);
1009 else
1010 dstWidth = srcWidth;
1011
1012 if (filterHeight >= 1)
1013 dstHeight = srcHeight - (filterHeight - 1);
1014 else
1015 dstHeight = srcHeight;
1016
Brian Pauld4b799b2000-08-21 14:24:30 +00001017 if (dstWidth <= 0 || dstHeight <= 0)
1018 return;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001019
Brian Pauld4b799b2000-08-21 14:24:30 +00001020 for (j = 0; j < dstHeight; j++) {
1021 for (i = 0; i < dstWidth; i++) {
1022 GLfloat sumR = 0.0;
1023 GLfloat sumG = 0.0;
1024 GLfloat sumB = 0.0;
1025 GLfloat sumA = 0.0;
1026 for (m = 0; m < filterHeight; m++) {
1027 for (n = 0; n < filterWidth; n++) {
1028 const GLint k = (j + m) * srcWidth + i + n;
1029 const GLint f = m * filterWidth + n;
1030 sumR += src[k][RCOMP] * filter[f][RCOMP];
1031 sumG += src[k][GCOMP] * filter[f][GCOMP];
1032 sumB += src[k][BCOMP] * filter[f][BCOMP];
1033 sumA += src[k][ACOMP] * filter[f][ACOMP];
1034 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001035 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001036 dest[j * dstWidth + i][RCOMP] = sumR;
1037 dest[j * dstWidth + i][GCOMP] = sumG;
1038 dest[j * dstWidth + i][BCOMP] = sumB;
1039 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001040 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001041 }
1042}
1043
1044
Brian Pauld4b799b2000-08-21 14:24:30 +00001045static void
1046convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1047 const GLfloat src[][4],
1048 GLint filterWidth, GLint filterHeight,
1049 const GLfloat filter[][4],
1050 GLfloat dest[][4],
1051 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001052{
1053 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001054 const GLint halfFilterHeight = filterHeight / 2;
1055 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001056
Brian Pauld4b799b2000-08-21 14:24:30 +00001057 for (j = 0; j < srcHeight; j++) {
1058 for (i = 0; i < srcWidth; i++) {
1059 GLfloat sumR = 0.0;
1060 GLfloat sumG = 0.0;
1061 GLfloat sumB = 0.0;
1062 GLfloat sumA = 0.0;
1063 for (m = 0; m < filterHeight; m++) {
1064 for (n = 0; n < filterWidth; n++) {
1065 const GLint f = m * filterWidth + n;
1066 const GLint is = i + n - halfFilterWidth;
1067 const GLint js = j + m - halfFilterHeight;
1068 if (is < 0 || is >= srcWidth ||
1069 js < 0 || js >= srcHeight) {
1070 sumR += borderColor[RCOMP] * filter[f][RCOMP];
1071 sumG += borderColor[GCOMP] * filter[f][GCOMP];
1072 sumB += borderColor[BCOMP] * filter[f][BCOMP];
1073 sumA += borderColor[ACOMP] * filter[f][ACOMP];
1074 }
1075 else {
1076 const GLint k = js * srcWidth + is;
1077 sumR += src[k][RCOMP] * filter[f][RCOMP];
1078 sumG += src[k][GCOMP] * filter[f][GCOMP];
1079 sumB += src[k][BCOMP] * filter[f][BCOMP];
1080 sumA += src[k][ACOMP] * filter[f][ACOMP];
1081 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001082 }
1083 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001084 dest[j * srcWidth + i][RCOMP] = sumR;
1085 dest[j * srcWidth + i][GCOMP] = sumG;
1086 dest[j * srcWidth + i][BCOMP] = sumB;
1087 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001088 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001089 }
1090}
1091
1092
Brian Pauld4b799b2000-08-21 14:24:30 +00001093static void
1094convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1095 const GLfloat src[][4],
1096 GLint filterWidth, GLint filterHeight,
1097 const GLfloat filter[][4],
1098 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001099{
1100 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001101 const GLint halfFilterHeight = filterHeight / 2;
1102 GLint i, j, n, m;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001103
Brian Pauld4b799b2000-08-21 14:24:30 +00001104 for (j = 0; j < srcHeight; j++) {
1105 for (i = 0; i < srcWidth; i++) {
1106 GLfloat sumR = 0.0;
1107 GLfloat sumG = 0.0;
1108 GLfloat sumB = 0.0;
1109 GLfloat sumA = 0.0;
1110 for (m = 0; m < filterHeight; m++) {
1111 for (n = 0; n < filterWidth; n++) {
1112 const GLint f = m * filterWidth + n;
1113 GLint is = i + n - halfFilterWidth;
1114 GLint js = j + m - halfFilterHeight;
1115 GLint k;
1116 if (is < 0)
1117 is = 0;
1118 else if (is >= srcWidth)
1119 is = srcWidth - 1;
1120 if (js < 0)
1121 js = 0;
1122 else if (js >= srcHeight)
1123 js = srcHeight - 1;
1124 k = js * srcWidth + is;
1125 sumR += src[k][RCOMP] * filter[f][RCOMP];
1126 sumG += src[k][GCOMP] * filter[f][GCOMP];
1127 sumB += src[k][BCOMP] * filter[f][BCOMP];
1128 sumA += src[k][ACOMP] * filter[f][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001129 }
1130 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001131 dest[j * srcWidth + i][RCOMP] = sumR;
1132 dest[j * srcWidth + i][GCOMP] = sumG;
1133 dest[j * srcWidth + i][BCOMP] = sumB;
1134 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001135 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001136 }
1137}
1138
1139
Brian Pauld4b799b2000-08-21 14:24:30 +00001140static void
1141convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1142 const GLfloat src[][4],
1143 GLint filterWidth, GLint filterHeight,
1144 const GLfloat rowFilt[][4],
1145 const GLfloat colFilt[][4],
1146 GLfloat dest[][4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001147{
Brian Paul7e708742000-08-22 18:54:25 +00001148 GLint dstWidth, dstHeight;
Brian Pauld4b799b2000-08-21 14:24:30 +00001149 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001150
1151 if (filterWidth >= 1)
1152 dstWidth = srcWidth - (filterWidth - 1);
1153 else
1154 dstWidth = srcWidth;
1155
1156 if (filterHeight >= 1)
1157 dstHeight = srcHeight - (filterHeight - 1);
1158 else
1159 dstHeight = srcHeight;
1160
1161 if (dstWidth <= 0 || dstHeight <= 0)
1162 return;
1163
1164 for (j = 0; j < dstHeight; j++) {
1165 for (i = 0; i < dstWidth; i++) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001166 GLfloat sumR = 0.0;
1167 GLfloat sumG = 0.0;
1168 GLfloat sumB = 0.0;
1169 GLfloat sumA = 0.0;
1170 for (m = 0; m < filterHeight; m++) {
1171 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001172 GLint k = (j + m) * srcWidth + i + n;
1173 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1174 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1175 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1176 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Paulcc8e37f2000-07-12 13:00:09 +00001177 }
1178 }
Brian Paul7e708742000-08-22 18:54:25 +00001179 dest[j * dstWidth + i][RCOMP] = sumR;
1180 dest[j * dstWidth + i][GCOMP] = sumG;
1181 dest[j * dstWidth + i][BCOMP] = sumB;
1182 dest[j * dstWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001183 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001184 }
Brian Paulcc8e37f2000-07-12 13:00:09 +00001185}
1186
1187
Brian Pauld4b799b2000-08-21 14:24:30 +00001188static void
1189convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1190 const GLfloat src[][4],
1191 GLint filterWidth, GLint filterHeight,
1192 const GLfloat rowFilt[][4],
1193 const GLfloat colFilt[][4],
1194 GLfloat dest[][4],
1195 const GLfloat borderColor[4])
Brian Paulcc8e37f2000-07-12 13:00:09 +00001196{
1197 const GLint halfFilterWidth = filterWidth / 2;
Brian Pauld4b799b2000-08-21 14:24:30 +00001198 const GLint halfFilterHeight = filterHeight / 2;
1199 GLint i, j, n, m;
Brian Paul7e708742000-08-22 18:54:25 +00001200
Brian Pauld4b799b2000-08-21 14:24:30 +00001201 for (j = 0; j < srcHeight; j++) {
1202 for (i = 0; i < srcWidth; i++) {
1203 GLfloat sumR = 0.0;
1204 GLfloat sumG = 0.0;
1205 GLfloat sumB = 0.0;
1206 GLfloat sumA = 0.0;
1207 for (m = 0; m < filterHeight; m++) {
1208 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001209 const GLint is = i + n - halfFilterWidth;
1210 const GLint js = j + m - halfFilterHeight;
1211 if (is < 0 || is >= srcWidth ||
1212 js < 0 || js >= srcHeight) {
Brian Pauld4b799b2000-08-21 14:24:30 +00001213 sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1214 sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1215 sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1216 sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1217 }
1218 else {
Brian Paul7e708742000-08-22 18:54:25 +00001219 GLint k = js * srcWidth + is;
Brian Pauld4b799b2000-08-21 14:24:30 +00001220 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1221 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1222 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1223 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1224 }
Brian Paul7e708742000-08-22 18:54:25 +00001225
Brian Paulcc8e37f2000-07-12 13:00:09 +00001226 }
1227 }
Brian Paul7e708742000-08-22 18:54:25 +00001228 dest[j * srcWidth + i][RCOMP] = sumR;
1229 dest[j * srcWidth + i][GCOMP] = sumG;
1230 dest[j * srcWidth + i][BCOMP] = sumB;
1231 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001232 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001233 }
Brian Pauld4b799b2000-08-21 14:24:30 +00001234}
1235
1236
1237static void
1238convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1239 const GLfloat src[][4],
1240 GLint filterWidth, GLint filterHeight,
1241 const GLfloat rowFilt[][4],
1242 const GLfloat colFilt[][4],
1243 GLfloat dest[][4])
1244{
1245 const GLint halfFilterWidth = filterWidth / 2;
1246 const GLint halfFilterHeight = filterHeight / 2;
1247 GLint i, j, n, m;
1248
1249 for (j = 0; j < srcHeight; j++) {
1250 for (i = 0; i < srcWidth; i++) {
1251 GLfloat sumR = 0.0;
1252 GLfloat sumG = 0.0;
1253 GLfloat sumB = 0.0;
1254 GLfloat sumA = 0.0;
1255 for (m = 0; m < filterHeight; m++) {
1256 for (n = 0; n < filterWidth; n++) {
Brian Paul7e708742000-08-22 18:54:25 +00001257 GLint is = i + n - halfFilterWidth;
1258 GLint js = j + m - halfFilterHeight;
1259 GLint k;
1260 if (is < 0)
1261 is = 0;
1262 else if (is >= srcWidth)
1263 is = srcWidth - 1;
1264 if (js < 0)
1265 js = 0;
1266 else if (js >= srcHeight)
1267 js = srcHeight - 1;
1268 k = js * srcWidth + is;
1269 sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1270 sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1271 sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1272 sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
Brian Pauld4b799b2000-08-21 14:24:30 +00001273 }
1274 }
Brian Paul7e708742000-08-22 18:54:25 +00001275 dest[j * srcWidth + i][RCOMP] = sumR;
1276 dest[j * srcWidth + i][GCOMP] = sumG;
1277 dest[j * srcWidth + i][BCOMP] = sumB;
1278 dest[j * srcWidth + i][ACOMP] = sumA;
Brian Pauld4b799b2000-08-21 14:24:30 +00001279 }
1280 }
1281}
1282
1283
1284
1285void
1286_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1287 const GLfloat *srcImage, GLfloat *dstImage)
1288{
1289 switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1290 case GL_REDUCE:
1291 convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1292 ctx->Convolution1D.Width,
1293 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1294 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001295 *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001296 break;
1297 case GL_CONSTANT_BORDER:
1298 convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1299 ctx->Convolution1D.Width,
1300 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1301 (GLfloat (*)[4]) dstImage,
1302 ctx->Pixel.ConvolutionBorderColor[0]);
1303 break;
1304 case GL_REPLICATE_BORDER:
1305 convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1306 ctx->Convolution1D.Width,
1307 (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1308 (GLfloat (*)[4]) dstImage);
1309 break;
1310 default:
1311 ;
1312 }
1313}
1314
1315
1316void
1317_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1318 const GLfloat *srcImage, GLfloat *dstImage)
1319{
1320 switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1321 case GL_REDUCE:
1322 convolve_2d_reduce(*width, *height,
1323 (const GLfloat (*)[4]) srcImage,
1324 ctx->Convolution2D.Width,
1325 ctx->Convolution2D.Height,
1326 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1327 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001328 *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1329 *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001330 break;
1331 case GL_CONSTANT_BORDER:
1332 convolve_2d_constant(*width, *height,
1333 (const GLfloat (*)[4]) srcImage,
1334 ctx->Convolution2D.Width,
1335 ctx->Convolution2D.Height,
1336 (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1337 (GLfloat (*)[4]) dstImage,
1338 ctx->Pixel.ConvolutionBorderColor[1]);
1339 break;
1340 case GL_REPLICATE_BORDER:
1341 convolve_2d_replicate(*width, *height,
1342 (const GLfloat (*)[4]) srcImage,
1343 ctx->Convolution2D.Width,
1344 ctx->Convolution2D.Height,
1345 (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1346 (GLfloat (*)[4]) dstImage);
1347 break;
1348 default:
1349 ;
1350 }
1351}
1352
1353
1354void
1355_mesa_convolve_sep_image(const GLcontext *ctx,
1356 GLsizei *width, GLsizei *height,
1357 const GLfloat *srcImage, GLfloat *dstImage)
1358{
1359 const GLfloat *rowFilter = ctx->Separable2D.Filter;
1360 const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1361
1362 switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1363 case GL_REDUCE:
1364 convolve_sep_reduce(*width, *height,
1365 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001366 ctx->Separable2D.Width,
1367 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001368 (const GLfloat (*)[4]) rowFilter,
1369 (const GLfloat (*)[4]) colFilter,
1370 (GLfloat (*)[4]) dstImage);
Brian Paul7e708742000-08-22 18:54:25 +00001371 *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1372 *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
Brian Pauld4b799b2000-08-21 14:24:30 +00001373 break;
1374 case GL_CONSTANT_BORDER:
1375 convolve_sep_constant(*width, *height,
1376 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001377 ctx->Separable2D.Width,
1378 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001379 (const GLfloat (*)[4]) rowFilter,
1380 (const GLfloat (*)[4]) colFilter,
1381 (GLfloat (*)[4]) dstImage,
1382 ctx->Pixel.ConvolutionBorderColor[2]);
1383 break;
1384 case GL_REPLICATE_BORDER:
1385 convolve_sep_replicate(*width, *height,
1386 (const GLfloat (*)[4]) srcImage,
Brian Paul7e708742000-08-22 18:54:25 +00001387 ctx->Separable2D.Width,
1388 ctx->Separable2D.Height,
Brian Pauld4b799b2000-08-21 14:24:30 +00001389 (const GLfloat (*)[4]) rowFilter,
1390 (const GLfloat (*)[4]) colFilter,
1391 (GLfloat (*)[4]) dstImage);
1392 break;
1393 default:
1394 ;
Brian Paulcc8e37f2000-07-12 13:00:09 +00001395 }
1396}