Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
55 pj 1
/* $Id: convolve.c,v 1.1 2003-02-28 11:41:59 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  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
#include "glheader.h"
37
#include "colormac.h"
38
#include "convolve.h"
39
#include "context.h"
40
#include "image.h"
41
#include "mtypes.h"
42
#include "state.h"
43
 
44
 
45
/*
46
 * Given an internalFormat token passed to glConvolutionFilter
47
 * or glSeparableFilter, return the corresponding base format.
48
 * Return -1 if invalid token.
49
 */
50
static GLint
51
base_filter_format( GLenum format )
52
{
53
   switch (format) {
54
      case GL_ALPHA:
55
      case GL_ALPHA4:
56
      case GL_ALPHA8:
57
      case GL_ALPHA12:
58
      case GL_ALPHA16:
59
         return GL_ALPHA;
60
      case GL_LUMINANCE:
61
      case GL_LUMINANCE4:
62
      case GL_LUMINANCE8:
63
      case GL_LUMINANCE12:
64
      case GL_LUMINANCE16:
65
         return GL_LUMINANCE;
66
      case GL_LUMINANCE_ALPHA:
67
      case GL_LUMINANCE4_ALPHA4:
68
      case GL_LUMINANCE6_ALPHA2:
69
      case GL_LUMINANCE8_ALPHA8:
70
      case GL_LUMINANCE12_ALPHA4:
71
      case GL_LUMINANCE12_ALPHA12:
72
      case GL_LUMINANCE16_ALPHA16:
73
         return GL_LUMINANCE_ALPHA;
74
      case GL_INTENSITY:
75
      case GL_INTENSITY4:
76
      case GL_INTENSITY8:
77
      case GL_INTENSITY12:
78
      case GL_INTENSITY16:
79
         return GL_INTENSITY;
80
      case GL_RGB:
81
      case GL_R3_G3_B2:
82
      case GL_RGB4:
83
      case GL_RGB5:
84
      case GL_RGB8:
85
      case GL_RGB10:
86
      case GL_RGB12:
87
      case GL_RGB16:
88
         return GL_RGB;
89
      case 4:
90
      case GL_RGBA:
91
      case GL_RGBA2:
92
      case GL_RGBA4:
93
      case GL_RGB5_A1:
94
      case GL_RGBA8:
95
      case GL_RGB10_A2:
96
      case GL_RGBA12:
97
      case GL_RGBA16:
98
         return GL_RGBA;
99
      default:
100
         return -1;  /* error */
101
   }
102
}
103
 
104
 
105
void
106
_mesa_ConvolutionFilter1D(GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *image)
107
{
108
   GLint baseFormat;
109
   GET_CURRENT_CONTEXT(ctx);
110
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
111
 
112
   if (target != GL_CONVOLUTION_1D) {
113
      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(target)");
114
      return;
115
   }
116
 
117
   baseFormat = base_filter_format(internalFormat);
118
   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
119
      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(internalFormat)");
120
      return;
121
   }
122
 
123
   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
124
      _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter1D(width)");
125
      return;
126
   }
127
 
128
   if (!_mesa_is_legal_format_and_type(format, type)) {
129
      _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter1D(format or type)");
130
      return;
131
   }
132
 
133
   if (format == GL_COLOR_INDEX ||
134
       format == GL_STENCIL_INDEX ||
135
       format == GL_DEPTH_COMPONENT ||
136
       format == GL_INTENSITY ||
137
       type == GL_BITMAP) {
138
      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter1D(format or type)");
139
      return;
140
   }
141
 
142
   ctx->Convolution1D.Format = format;
143
   ctx->Convolution1D.InternalFormat = internalFormat;
144
   ctx->Convolution1D.Width = width;
145
   ctx->Convolution1D.Height = 1;
146
 
147
   /* unpack filter image */
148
   _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
149
                                 ctx->Convolution1D.Filter,
150
                                 format, type, image, &ctx->Unpack,
151
                                 0, GL_FALSE);
152
 
153
   /* apply scale and bias */
154
   {
155
      const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[0];
156
      const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[0];
157
      GLint i;
158
      for (i = 0; i < width; i++) {
159
         GLfloat r = ctx->Convolution1D.Filter[i * 4 + 0];
160
         GLfloat g = ctx->Convolution1D.Filter[i * 4 + 1];
161
         GLfloat b = ctx->Convolution1D.Filter[i * 4 + 2];
162
         GLfloat a = ctx->Convolution1D.Filter[i * 4 + 3];
163
         r = r * scale[0] + bias[0];
164
         g = g * scale[1] + bias[1];
165
         b = b * scale[2] + bias[2];
166
         a = a * scale[3] + bias[3];
167
         ctx->Convolution1D.Filter[i * 4 + 0] = r;
168
         ctx->Convolution1D.Filter[i * 4 + 1] = g;
169
         ctx->Convolution1D.Filter[i * 4 + 2] = b;
170
         ctx->Convolution1D.Filter[i * 4 + 3] = a;
171
      }
172
   }
173
 
174
   ctx->NewState |= _NEW_PIXEL;
175
}
176
 
177
 
178
void
179
_mesa_ConvolutionFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image)
180
{
181
   GLint baseFormat;
182
   GLint i, components;
183
   GET_CURRENT_CONTEXT(ctx);
184
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
185
 
186
   if (target != GL_CONVOLUTION_2D) {
187
      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(target)");
188
      return;
189
   }
190
 
191
   baseFormat = base_filter_format(internalFormat);
192
   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
193
      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(internalFormat)");
194
      return;
195
   }
196
 
197
   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
198
      _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(width)");
199
      return;
200
   }
201
   if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
202
      _mesa_error(ctx, GL_INVALID_VALUE, "glConvolutionFilter2D(height)");
203
      return;
204
   }
205
 
206
   if (!_mesa_is_legal_format_and_type(format, type)) {
207
      _mesa_error(ctx, GL_INVALID_OPERATION, "glConvolutionFilter2D(format or type)");
208
      return;
209
   }
210
   if (format == GL_COLOR_INDEX ||
211
       format == GL_STENCIL_INDEX ||
212
       format == GL_DEPTH_COMPONENT ||
213
       format == GL_INTENSITY ||
214
       type == GL_BITMAP) {
215
      _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionFilter2D(format or type)");
216
      return;
217
   }
218
 
219
   components = _mesa_components_in_format(format);
220
   assert(components > 0);  /* this should have been caught earlier */
221
 
222
   ctx->Convolution2D.Format = format;
223
   ctx->Convolution2D.InternalFormat = internalFormat;
224
   ctx->Convolution2D.Width = width;
225
   ctx->Convolution2D.Height = height;
226
 
227
   /* Unpack filter image.  We always store filters in RGBA format. */
228
   for (i = 0; i < height; i++) {
229
      const GLvoid *src = _mesa_image_address(&ctx->Unpack, image, width,
230
                                              height, format, type, 0, i, 0);
231
      GLfloat *dst = ctx->Convolution2D.Filter + i * width * 4;
232
      _mesa_unpack_float_color_span(ctx, width, GL_RGBA, dst,
233
                                    format, type, src, &ctx->Unpack,
234
                                    0, GL_FALSE);
235
   }
236
 
237
   /* apply scale and bias */
238
   {
239
      const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[1];
240
      const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[1];
241
      for (i = 0; i < width * height; i++) {
242
         GLfloat r = ctx->Convolution2D.Filter[i * 4 + 0];
243
         GLfloat g = ctx->Convolution2D.Filter[i * 4 + 1];
244
         GLfloat b = ctx->Convolution2D.Filter[i * 4 + 2];
245
         GLfloat a = ctx->Convolution2D.Filter[i * 4 + 3];
246
         r = r * scale[0] + bias[0];
247
         g = g * scale[1] + bias[1];
248
         b = b * scale[2] + bias[2];
249
         a = a * scale[3] + bias[3];
250
         ctx->Convolution2D.Filter[i * 4 + 0] = r;
251
         ctx->Convolution2D.Filter[i * 4 + 1] = g;
252
         ctx->Convolution2D.Filter[i * 4 + 2] = b;
253
         ctx->Convolution2D.Filter[i * 4 + 3] = a;
254
      }
255
   }
256
 
257
   ctx->NewState |= _NEW_PIXEL;
258
}
259
 
260
 
261
void
262
_mesa_ConvolutionParameterf(GLenum target, GLenum pname, GLfloat param)
263
{
264
   GET_CURRENT_CONTEXT(ctx);
265
   GLuint c;
266
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
267
 
268
   switch (target) {
269
      case GL_CONVOLUTION_1D:
270
         c = 0;
271
         break;
272
      case GL_CONVOLUTION_2D:
273
         c = 1;
274
         break;
275
      case GL_SEPARABLE_2D:
276
         c = 2;
277
         break;
278
      default:
279
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(target)");
280
         return;
281
   }
282
 
283
   switch (pname) {
284
      case GL_CONVOLUTION_BORDER_MODE:
285
         if (param == (GLfloat) GL_REDUCE ||
286
             param == (GLfloat) GL_CONSTANT_BORDER ||
287
             param == (GLfloat) GL_REPLICATE_BORDER) {
288
            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
289
         }
290
         else {
291
            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(params)");
292
            return;
293
         }
294
         break;
295
      default:
296
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterf(pname)");
297
         return;
298
   }
299
 
300
   ctx->NewState |= _NEW_PIXEL;
301
}
302
 
303
 
304
void
305
_mesa_ConvolutionParameterfv(GLenum target, GLenum pname, const GLfloat *params)
306
{
307
   GET_CURRENT_CONTEXT(ctx);
308
   struct gl_convolution_attrib *conv;
309
   GLuint c;
310
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
311
 
312
   switch (target) {
313
      case GL_CONVOLUTION_1D:
314
         c = 0;
315
         conv = &ctx->Convolution1D;
316
         break;
317
      case GL_CONVOLUTION_2D:
318
         c = 1;
319
         conv = &ctx->Convolution2D;
320
         break;
321
      case GL_SEPARABLE_2D:
322
         c = 2;
323
         conv = &ctx->Separable2D;
324
         break;
325
      default:
326
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(target)");
327
         return;
328
   }
329
 
330
   switch (pname) {
331
      case GL_CONVOLUTION_BORDER_COLOR:
332
         COPY_4V(ctx->Pixel.ConvolutionBorderColor[c], params);
333
         break;
334
      case GL_CONVOLUTION_BORDER_MODE:
335
         if (params[0] == (GLfloat) GL_REDUCE ||
336
             params[0] == (GLfloat) GL_CONSTANT_BORDER ||
337
             params[0] == (GLfloat) GL_REPLICATE_BORDER) {
338
            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) params[0];
339
         }
340
         else {
341
            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(params)");
342
            return;
343
         }
344
         break;
345
      case GL_CONVOLUTION_FILTER_SCALE:
346
         COPY_4V(ctx->Pixel.ConvolutionFilterScale[c], params);
347
         break;
348
      case GL_CONVOLUTION_FILTER_BIAS:
349
         COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params);
350
         break;
351
      default:
352
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameterfv(pname)");
353
         return;
354
   }
355
 
356
   ctx->NewState |= _NEW_PIXEL;
357
}
358
 
359
 
360
void
361
_mesa_ConvolutionParameteri(GLenum target, GLenum pname, GLint param)
362
{
363
   GET_CURRENT_CONTEXT(ctx);
364
   GLuint c;
365
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
366
 
367
   switch (target) {
368
      case GL_CONVOLUTION_1D:
369
         c = 0;
370
         break;
371
      case GL_CONVOLUTION_2D:
372
         c = 1;
373
         break;
374
      case GL_SEPARABLE_2D:
375
         c = 2;
376
         break;
377
      default:
378
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(target)");
379
         return;
380
   }
381
 
382
   switch (pname) {
383
      case GL_CONVOLUTION_BORDER_MODE:
384
         if (param == (GLint) GL_REDUCE ||
385
             param == (GLint) GL_CONSTANT_BORDER ||
386
             param == (GLint) GL_REPLICATE_BORDER) {
387
            ctx->Pixel.ConvolutionBorderMode[c] = (GLenum) param;
388
         }
389
         else {
390
            _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(params)");
391
            return;
392
         }
393
         break;
394
      default:
395
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteri(pname)");
396
         return;
397
   }
398
 
399
   ctx->NewState |= _NEW_PIXEL;
400
}
401
 
402
 
403
void
404
_mesa_ConvolutionParameteriv(GLenum target, GLenum pname, const GLint *params)
405
{
406
   GET_CURRENT_CONTEXT(ctx);
407
   struct gl_convolution_attrib *conv;
408
   GLuint c;
409
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
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
         _mesa_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
            _mesa_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
         /* need cast to prevent compiler warnings */  
450
         ctx->Pixel.ConvolutionFilterScale[c][0] = (GLfloat) params[0];
451
         ctx->Pixel.ConvolutionFilterScale[c][1] = (GLfloat) params[1];
452
         ctx->Pixel.ConvolutionFilterScale[c][2] = (GLfloat) params[2];
453
         ctx->Pixel.ConvolutionFilterScale[c][3] = (GLfloat) params[3];
454
         break;
455
      case GL_CONVOLUTION_FILTER_BIAS:
456
         /* COPY_4V(ctx->Pixel.ConvolutionFilterBias[c], params); */
457
         /* need cast to prevent compiler warnings */  
458
         ctx->Pixel.ConvolutionFilterBias[c][0] = (GLfloat) params[0];
459
         ctx->Pixel.ConvolutionFilterBias[c][1] = (GLfloat) params[1];
460
         ctx->Pixel.ConvolutionFilterBias[c][2] = (GLfloat) params[2];
461
         ctx->Pixel.ConvolutionFilterBias[c][3] = (GLfloat) params[3];
462
         break;
463
      default:
464
         _mesa_error(ctx, GL_INVALID_ENUM, "glConvolutionParameteriv(pname)");
465
         return;
466
   }
467
 
468
   ctx->NewState |= _NEW_PIXEL;
469
}
470
 
471
 
472
void
473
_mesa_CopyConvolutionFilter1D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width)
474
{
475
   GLint baseFormat;
476
   GET_CURRENT_CONTEXT(ctx);
477
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
478
 
479
   if (target != GL_CONVOLUTION_1D) {
480
      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(target)");
481
      return;
482
   }
483
 
484
   baseFormat = base_filter_format(internalFormat);
485
   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
486
      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter1D(internalFormat)");
487
      return;
488
   }
489
 
490
   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
491
      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter1D(width)");
492
      return;
493
   }
494
 
495
   ctx->Driver.CopyConvolutionFilter1D( ctx, target,
496
                                        internalFormat, x, y, width);
497
}
498
 
499
 
500
void
501
_mesa_CopyConvolutionFilter2D(GLenum target, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height)
502
{
503
   GLint baseFormat;
504
   GET_CURRENT_CONTEXT(ctx);
505
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
506
 
507
   if (target != GL_CONVOLUTION_2D) {
508
      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(target)");
509
      return;
510
   }
511
 
512
   baseFormat = base_filter_format(internalFormat);
513
   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
514
      _mesa_error(ctx, GL_INVALID_ENUM, "glCopyConvolutionFilter2D(internalFormat)");
515
      return;
516
   }
517
 
518
   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
519
      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(width)");
520
      return;
521
   }
522
   if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
523
      _mesa_error(ctx, GL_INVALID_VALUE, "glCopyConvolutionFilter2D(height)");
524
      return;
525
   }
526
 
527
   ctx->Driver.CopyConvolutionFilter2D( ctx, target, internalFormat, x, y,
528
                                        width, height );
529
 
530
}
531
 
532
 
533
void
534
_mesa_GetConvolutionFilter(GLenum target, GLenum format, GLenum type, GLvoid *image)
535
{
536
   const struct gl_convolution_attrib *filter;
537
   GLuint row;
538
   GET_CURRENT_CONTEXT(ctx);
539
   ASSERT_OUTSIDE_BEGIN_END(ctx);
540
 
541
   if (ctx->NewState) {
542
      _mesa_update_state(ctx);
543
   }
544
 
545
   if (!_mesa_is_legal_format_and_type(format, type)) {
546
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
547
      return;
548
   }
549
 
550
   if (format == GL_COLOR_INDEX ||
551
       format == GL_STENCIL_INDEX ||
552
       format == GL_DEPTH_COMPONENT ||
553
       format == GL_INTENSITY ||
554
       type == GL_BITMAP) {
555
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
556
      return;
557
   }
558
 
559
   switch (target) {
560
      case GL_CONVOLUTION_1D:
561
         filter = &(ctx->Convolution1D);
562
         break;
563
      case GL_CONVOLUTION_2D:
564
         filter = &(ctx->Convolution2D);
565
         break;
566
      default:
567
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(target)");
568
         return;
569
   }
570
 
571
   for (row = 0; row < filter->Height; row++) {
572
      GLvoid *dst = _mesa_image_address( &ctx->Pack, image, filter->Width,
573
                                         filter->Height, format, type,
574
                                         0, row, 0);
575
      const GLfloat *src = filter->Filter + row * filter->Width * 4;
576
      _mesa_pack_float_rgba_span(ctx, filter->Width,
577
                                 (const GLfloat (*)[4]) src,
578
                                 format, type, dst, &ctx->Pack, 0);
579
   }
580
}
581
 
582
 
583
void
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
   ASSERT_OUTSIDE_BEGIN_END(ctx);
590
 
591
   switch (target) {
592
      case GL_CONVOLUTION_1D:
593
         c = 0;
594
         conv = &ctx->Convolution1D;
595
         break;
596
      case GL_CONVOLUTION_2D:
597
         c = 1;
598
         conv = &ctx->Convolution2D;
599
         break;
600
      case GL_SEPARABLE_2D:
601
         c = 2;
602
         conv = &ctx->Separable2D;
603
         break;
604
      default:
605
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(target)");
606
         return;
607
   }
608
 
609
   switch (pname) {
610
      case GL_CONVOLUTION_BORDER_COLOR:
611
         COPY_4V(params, ctx->Pixel.ConvolutionBorderColor[c]);
612
         break;
613
      case GL_CONVOLUTION_BORDER_MODE:
614
         *params = (GLfloat) ctx->Pixel.ConvolutionBorderMode[c];
615
         break;
616
      case GL_CONVOLUTION_FILTER_SCALE:
617
         COPY_4V(params, ctx->Pixel.ConvolutionFilterScale[c]);
618
         break;
619
      case GL_CONVOLUTION_FILTER_BIAS:
620
         COPY_4V(params, ctx->Pixel.ConvolutionFilterBias[c]);
621
         break;
622
      case GL_CONVOLUTION_FORMAT:
623
         *params = (GLfloat) conv->Format;
624
         break;
625
      case GL_CONVOLUTION_WIDTH:
626
         *params = (GLfloat) conv->Width;
627
         break;
628
      case GL_CONVOLUTION_HEIGHT:
629
         *params = (GLfloat) conv->Height;
630
         break;
631
      case GL_MAX_CONVOLUTION_WIDTH:
632
         *params = (GLfloat) ctx->Const.MaxConvolutionWidth;
633
         break;
634
      case GL_MAX_CONVOLUTION_HEIGHT:
635
         *params = (GLfloat) ctx->Const.MaxConvolutionHeight;
636
         break;
637
      default:
638
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameterfv(pname)");
639
         return;
640
   }
641
}
642
 
643
 
644
void
645
_mesa_GetConvolutionParameteriv(GLenum target, GLenum pname, GLint *params)
646
{
647
   GET_CURRENT_CONTEXT(ctx);
648
   const struct gl_convolution_attrib *conv;
649
   GLuint c;
650
   ASSERT_OUTSIDE_BEGIN_END(ctx);
651
 
652
   switch (target) {
653
      case GL_CONVOLUTION_1D:
654
         c = 0;
655
         conv = &ctx->Convolution1D;
656
         break;
657
      case GL_CONVOLUTION_2D:
658
         c = 1;
659
         conv = &ctx->Convolution2D;
660
         break;
661
      case GL_SEPARABLE_2D:
662
         c = 2;
663
         conv = &ctx->Separable2D;
664
         break;
665
      default:
666
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(target)");
667
         return;
668
   }
669
 
670
   switch (pname) {
671
      case GL_CONVOLUTION_BORDER_COLOR:
672
         params[0] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][0]);
673
         params[1] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][1]);
674
         params[2] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][2]);
675
         params[3] = FLOAT_TO_INT(ctx->Pixel.ConvolutionBorderColor[c][3]);
676
         break;
677
      case GL_CONVOLUTION_BORDER_MODE:
678
         *params = (GLint) ctx->Pixel.ConvolutionBorderMode[c];
679
         break;
680
      case GL_CONVOLUTION_FILTER_SCALE:
681
         params[0] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][0];
682
         params[1] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][1];
683
         params[2] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][2];
684
         params[3] = (GLint) ctx->Pixel.ConvolutionFilterScale[c][3];
685
         break;
686
      case GL_CONVOLUTION_FILTER_BIAS:
687
         params[0] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][0];
688
         params[1] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][1];
689
         params[2] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][2];
690
         params[3] = (GLint) ctx->Pixel.ConvolutionFilterBias[c][3];
691
         break;
692
      case GL_CONVOLUTION_FORMAT:
693
         *params = (GLint) conv->Format;
694
         break;
695
      case GL_CONVOLUTION_WIDTH:
696
         *params = (GLint) conv->Width;
697
         break;
698
      case GL_CONVOLUTION_HEIGHT:
699
         *params = (GLint) conv->Height;
700
         break;
701
      case GL_MAX_CONVOLUTION_WIDTH:
702
         *params = (GLint) ctx->Const.MaxConvolutionWidth;
703
         break;
704
      case GL_MAX_CONVOLUTION_HEIGHT:
705
         *params = (GLint) ctx->Const.MaxConvolutionHeight;
706
         break;
707
      default:
708
         _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionParameteriv(pname)");
709
         return;
710
   }
711
}
712
 
713
 
714
void
715
_mesa_GetSeparableFilter(GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span)
716
{
717
   const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
718
   const struct gl_convolution_attrib *filter;
719
   GET_CURRENT_CONTEXT(ctx);
720
   ASSERT_OUTSIDE_BEGIN_END(ctx);
721
 
722
   if (ctx->NewState) {
723
      _mesa_update_state(ctx);
724
   }
725
 
726
   if (target != GL_SEPARABLE_2D) {
727
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetSeparableFilter(target)");
728
      return;
729
   }
730
 
731
   if (!_mesa_is_legal_format_and_type(format, type)) {
732
      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetConvolutionFilter(format or type)");
733
      return;
734
   }
735
 
736
   if (format == GL_COLOR_INDEX ||
737
       format == GL_STENCIL_INDEX ||
738
       format == GL_DEPTH_COMPONENT ||
739
       format == GL_INTENSITY ||
740
       type == GL_BITMAP) {
741
      _mesa_error(ctx, GL_INVALID_ENUM, "glGetConvolutionFilter(format or type)");
742
      return;
743
   }
744
 
745
   filter = &ctx->Separable2D;
746
 
747
   /* Row filter */
748
   {
749
      GLvoid *dst = _mesa_image_address( &ctx->Pack, row, filter->Width,
750
                                         filter->Height, format, type,
751
                                         0, 0, 0);
752
      _mesa_pack_float_rgba_span(ctx, filter->Width,
753
                                 (const GLfloat (*)[4]) filter->Filter,
754
                                 format, type, dst, &ctx->Pack, 0);
755
   }
756
 
757
   /* Column filter */
758
   {
759
      GLvoid *dst = _mesa_image_address( &ctx->Pack, column, filter->Width,
760
                                         1, format, type,
761
                                         0, 0, 0);
762
      const GLfloat *src = filter->Filter + colStart;
763
      _mesa_pack_float_rgba_span(ctx, filter->Height,
764
                                 (const GLfloat (*)[4]) src,
765
                                 format, type, dst, &ctx->Pack, 0);
766
   }
767
 
768
   (void) span;  /* unused at this time */
769
}
770
 
771
 
772
void
773
_mesa_SeparableFilter2D(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column)
774
{
775
   const GLint colStart = MAX_CONVOLUTION_WIDTH * 4;
776
   GLint baseFormat;
777
   GET_CURRENT_CONTEXT(ctx);
778
   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
779
 
780
   if (target != GL_SEPARABLE_2D) {
781
      _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(target)");
782
      return;
783
   }
784
 
785
   baseFormat = base_filter_format(internalFormat);
786
   if (baseFormat < 0 || baseFormat == GL_COLOR_INDEX) {
787
      _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(internalFormat)");
788
      return;
789
   }
790
 
791
   if (width < 0 || width > MAX_CONVOLUTION_WIDTH) {
792
      _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(width)");
793
      return;
794
   }
795
   if (height < 0 || height > MAX_CONVOLUTION_HEIGHT) {
796
      _mesa_error(ctx, GL_INVALID_VALUE, "glSeparableFilter2D(height)");
797
      return;
798
   }
799
 
800
   if (!_mesa_is_legal_format_and_type(format, type)) {
801
      _mesa_error(ctx, GL_INVALID_OPERATION, "glSeparableFilter2D(format or type)");
802
      return;
803
   }
804
 
805
   if (format == GL_COLOR_INDEX ||
806
       format == GL_STENCIL_INDEX ||
807
       format == GL_DEPTH_COMPONENT ||
808
       format == GL_INTENSITY ||
809
       type == GL_BITMAP) {
810
      _mesa_error(ctx, GL_INVALID_ENUM, "glSeparableFilter2D(format or type)");
811
      return;
812
   }
813
 
814
   ctx->Separable2D.Format = format;
815
   ctx->Separable2D.InternalFormat = internalFormat;
816
   ctx->Separable2D.Width = width;
817
   ctx->Separable2D.Height = height;
818
 
819
   /* unpack row filter */
820
   _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
821
                                 ctx->Separable2D.Filter,
822
                                 format, type, row, &ctx->Unpack,
823
                                 0, GL_FALSE);
824
 
825
   /* apply scale and bias */
826
   {
827
      const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
828
      const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
829
      GLint i;
830
      for (i = 0; i < width; i++) {
831
         GLfloat r = ctx->Separable2D.Filter[i * 4 + 0];
832
         GLfloat g = ctx->Separable2D.Filter[i * 4 + 1];
833
         GLfloat b = ctx->Separable2D.Filter[i * 4 + 2];
834
         GLfloat a = ctx->Separable2D.Filter[i * 4 + 3];
835
         r = r * scale[0] + bias[0];
836
         g = g * scale[1] + bias[1];
837
         b = b * scale[2] + bias[2];
838
         a = a * scale[3] + bias[3];
839
         ctx->Separable2D.Filter[i * 4 + 0] = r;
840
         ctx->Separable2D.Filter[i * 4 + 1] = g;
841
         ctx->Separable2D.Filter[i * 4 + 2] = b;
842
         ctx->Separable2D.Filter[i * 4 + 3] = a;
843
      }
844
   }
845
 
846
   /* unpack column filter */
847
   _mesa_unpack_float_color_span(ctx, width, GL_RGBA,
848
                                 &ctx->Separable2D.Filter[colStart],
849
                                 format, type, column, &ctx->Unpack,
850
                                 0, GL_FALSE);
851
 
852
   /* apply scale and bias */
853
   {
854
      const GLfloat *scale = ctx->Pixel.ConvolutionFilterScale[2];
855
      const GLfloat *bias = ctx->Pixel.ConvolutionFilterBias[2];
856
      GLint i;
857
      for (i = 0; i < width; i++) {
858
         GLfloat r = ctx->Separable2D.Filter[i * 4 + 0 + colStart];
859
         GLfloat g = ctx->Separable2D.Filter[i * 4 + 1 + colStart];
860
         GLfloat b = ctx->Separable2D.Filter[i * 4 + 2 + colStart];
861
         GLfloat a = ctx->Separable2D.Filter[i * 4 + 3 + colStart];
862
         r = r * scale[0] + bias[0];
863
         g = g * scale[1] + bias[1];
864
         b = b * scale[2] + bias[2];
865
         a = a * scale[3] + bias[3];
866
         ctx->Separable2D.Filter[i * 4 + 0 + colStart] = r;
867
         ctx->Separable2D.Filter[i * 4 + 1 + colStart] = g;
868
         ctx->Separable2D.Filter[i * 4 + 2 + colStart] = b;
869
         ctx->Separable2D.Filter[i * 4 + 3 + colStart] = a;
870
      }
871
   }
872
 
873
   ctx->NewState |= _NEW_PIXEL;
874
}
875
 
876
 
877
/**********************************************************************/
878
/***                   image convolution functions                  ***/
879
/**********************************************************************/
880
 
881
static void
882
convolve_1d_reduce(GLint srcWidth, const GLfloat src[][4],
883
                   GLint filterWidth, const GLfloat filter[][4],
884
                   GLfloat dest[][4])
885
{
886
   GLint dstWidth;
887
   GLint i, n;
888
 
889
   if (filterWidth >= 1)
890
      dstWidth = srcWidth - (filterWidth - 1);
891
   else
892
      dstWidth = srcWidth;
893
 
894
   if (dstWidth <= 0)
895
      return;  /* null result */
896
 
897
   for (i = 0; i < dstWidth; i++) {
898
      GLfloat sumR = 0.0;
899
      GLfloat sumG = 0.0;
900
      GLfloat sumB = 0.0;
901
      GLfloat sumA = 0.0;
902
      for (n = 0; n < filterWidth; n++) {
903
         sumR += src[i + n][RCOMP] * filter[n][RCOMP];
904
         sumG += src[i + n][GCOMP] * filter[n][GCOMP];
905
         sumB += src[i + n][BCOMP] * filter[n][BCOMP];
906
         sumA += src[i + n][ACOMP] * filter[n][ACOMP];
907
      }
908
      dest[i][RCOMP] = sumR;
909
      dest[i][GCOMP] = sumG;
910
      dest[i][BCOMP] = sumB;
911
      dest[i][ACOMP] = sumA;
912
   }
913
}
914
 
915
 
916
static void
917
convolve_1d_constant(GLint srcWidth, const GLfloat src[][4],
918
                     GLint filterWidth, const GLfloat filter[][4],
919
                     GLfloat dest[][4],
920
                     const GLfloat borderColor[4])
921
{
922
   const GLint halfFilterWidth = filterWidth / 2;
923
   GLint i, n;
924
 
925
   for (i = 0; i < srcWidth; i++) {
926
      GLfloat sumR = 0.0;
927
      GLfloat sumG = 0.0;
928
      GLfloat sumB = 0.0;
929
      GLfloat sumA = 0.0;
930
      for (n = 0; n < filterWidth; n++) {
931
         if (i + n < halfFilterWidth || i + n - halfFilterWidth >= srcWidth) {
932
            sumR += borderColor[RCOMP] * filter[n][RCOMP];
933
            sumG += borderColor[GCOMP] * filter[n][GCOMP];
934
            sumB += borderColor[BCOMP] * filter[n][BCOMP];
935
            sumA += borderColor[ACOMP] * filter[n][ACOMP];
936
         }
937
         else {
938
            sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
939
            sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
940
            sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
941
            sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
942
         }
943
      }
944
      dest[i][RCOMP] = sumR;
945
      dest[i][GCOMP] = sumG;
946
      dest[i][BCOMP] = sumB;
947
      dest[i][ACOMP] = sumA;
948
   }
949
}
950
 
951
 
952
static void
953
convolve_1d_replicate(GLint srcWidth, const GLfloat src[][4],
954
                      GLint filterWidth, const GLfloat filter[][4],
955
                      GLfloat dest[][4])
956
{
957
   const GLint halfFilterWidth = filterWidth / 2;
958
   GLint i, n;
959
 
960
   for (i = 0; i < srcWidth; i++) {
961
      GLfloat sumR = 0.0;
962
      GLfloat sumG = 0.0;
963
      GLfloat sumB = 0.0;
964
      GLfloat sumA = 0.0;
965
      for (n = 0; n < filterWidth; n++) {
966
         if (i + n < halfFilterWidth) {
967
            sumR += src[0][RCOMP] * filter[n][RCOMP];
968
            sumG += src[0][GCOMP] * filter[n][GCOMP];
969
            sumB += src[0][BCOMP] * filter[n][BCOMP];
970
            sumA += src[0][ACOMP] * filter[n][ACOMP];
971
         }
972
         else if (i + n - halfFilterWidth >= srcWidth) {
973
            sumR += src[srcWidth - 1][RCOMP] * filter[n][RCOMP];
974
            sumG += src[srcWidth - 1][GCOMP] * filter[n][GCOMP];
975
            sumB += src[srcWidth - 1][BCOMP] * filter[n][BCOMP];
976
            sumA += src[srcWidth - 1][ACOMP] * filter[n][ACOMP];
977
         }
978
         else {
979
            sumR += src[i + n - halfFilterWidth][RCOMP] * filter[n][RCOMP];
980
            sumG += src[i + n - halfFilterWidth][GCOMP] * filter[n][GCOMP];
981
            sumB += src[i + n - halfFilterWidth][BCOMP] * filter[n][BCOMP];
982
            sumA += src[i + n - halfFilterWidth][ACOMP] * filter[n][ACOMP];
983
         }
984
      }
985
      dest[i][RCOMP] = sumR;
986
      dest[i][GCOMP] = sumG;
987
      dest[i][BCOMP] = sumB;
988
      dest[i][ACOMP] = sumA;
989
   }
990
}
991
 
992
 
993
static void
994
convolve_2d_reduce(GLint srcWidth, GLint srcHeight,
995
                   const GLfloat src[][4],
996
                   GLint filterWidth, GLint filterHeight,
997
                   const GLfloat filter[][4],
998
                   GLfloat dest[][4])
999
{
1000
   GLint dstWidth, dstHeight;
1001
   GLint i, j, n, m;
1002
 
1003
   if (filterWidth >= 1)
1004
      dstWidth = srcWidth - (filterWidth - 1);
1005
   else
1006
      dstWidth = srcWidth;
1007
 
1008
   if (filterHeight >= 1)
1009
      dstHeight = srcHeight - (filterHeight - 1);
1010
   else
1011
      dstHeight = srcHeight;
1012
 
1013
   if (dstWidth <= 0 || dstHeight <= 0)
1014
      return;
1015
 
1016
   for (j = 0; j < dstHeight; j++) {
1017
      for (i = 0; i < dstWidth; i++) {
1018
         GLfloat sumR = 0.0;
1019
         GLfloat sumG = 0.0;
1020
         GLfloat sumB = 0.0;
1021
         GLfloat sumA = 0.0;
1022
         for (m = 0; m < filterHeight; m++) {
1023
            for (n = 0; n < filterWidth; n++) {
1024
               const GLint k = (j + m) * srcWidth + i + n;
1025
               const GLint f = m * filterWidth + n;
1026
               sumR += src[k][RCOMP] * filter[f][RCOMP];
1027
               sumG += src[k][GCOMP] * filter[f][GCOMP];
1028
               sumB += src[k][BCOMP] * filter[f][BCOMP];
1029
               sumA += src[k][ACOMP] * filter[f][ACOMP];
1030
            }
1031
         }
1032
         dest[j * dstWidth + i][RCOMP] = sumR;
1033
         dest[j * dstWidth + i][GCOMP] = sumG;
1034
         dest[j * dstWidth + i][BCOMP] = sumB;
1035
         dest[j * dstWidth + i][ACOMP] = sumA;
1036
      }
1037
   }
1038
}
1039
 
1040
 
1041
static void
1042
convolve_2d_constant(GLint srcWidth, GLint srcHeight,
1043
                     const GLfloat src[][4],
1044
                     GLint filterWidth, GLint filterHeight,
1045
                     const GLfloat filter[][4],
1046
                     GLfloat dest[][4],
1047
                     const GLfloat borderColor[4])
1048
{
1049
   const GLint halfFilterWidth = filterWidth / 2;
1050
   const GLint halfFilterHeight = filterHeight / 2;
1051
   GLint i, j, n, m;
1052
 
1053
   for (j = 0; j < srcHeight; j++) {
1054
      for (i = 0; i < srcWidth; i++) {
1055
         GLfloat sumR = 0.0;
1056
         GLfloat sumG = 0.0;
1057
         GLfloat sumB = 0.0;
1058
         GLfloat sumA = 0.0;
1059
         for (m = 0; m < filterHeight; m++) {
1060
            for (n = 0; n < filterWidth; n++) {
1061
               const GLint f = m * filterWidth + n;
1062
               const GLint is = i + n - halfFilterWidth;
1063
               const GLint js = j + m - halfFilterHeight;
1064
               if (is < 0 || is >= srcWidth ||
1065
                   js < 0 || js >= srcHeight) {
1066
                  sumR += borderColor[RCOMP] * filter[f][RCOMP];
1067
                  sumG += borderColor[GCOMP] * filter[f][GCOMP];
1068
                  sumB += borderColor[BCOMP] * filter[f][BCOMP];
1069
                  sumA += borderColor[ACOMP] * filter[f][ACOMP];
1070
               }
1071
               else {
1072
                  const GLint k = js * srcWidth + is;
1073
                  sumR += src[k][RCOMP] * filter[f][RCOMP];
1074
                  sumG += src[k][GCOMP] * filter[f][GCOMP];
1075
                  sumB += src[k][BCOMP] * filter[f][BCOMP];
1076
                  sumA += src[k][ACOMP] * filter[f][ACOMP];
1077
               }
1078
            }
1079
         }
1080
         dest[j * srcWidth + i][RCOMP] = sumR;
1081
         dest[j * srcWidth + i][GCOMP] = sumG;
1082
         dest[j * srcWidth + i][BCOMP] = sumB;
1083
         dest[j * srcWidth + i][ACOMP] = sumA;
1084
      }
1085
   }
1086
}
1087
 
1088
 
1089
static void
1090
convolve_2d_replicate(GLint srcWidth, GLint srcHeight,
1091
                      const GLfloat src[][4],
1092
                      GLint filterWidth, GLint filterHeight,
1093
                      const GLfloat filter[][4],
1094
                      GLfloat dest[][4])
1095
{
1096
   const GLint halfFilterWidth = filterWidth / 2;
1097
   const GLint halfFilterHeight = filterHeight / 2;
1098
   GLint i, j, n, m;
1099
 
1100
   for (j = 0; j < srcHeight; j++) {
1101
      for (i = 0; i < srcWidth; i++) {
1102
         GLfloat sumR = 0.0;
1103
         GLfloat sumG = 0.0;
1104
         GLfloat sumB = 0.0;
1105
         GLfloat sumA = 0.0;
1106
         for (m = 0; m < filterHeight; m++) {
1107
            for (n = 0; n < filterWidth; n++) {
1108
               const GLint f = m * filterWidth + n;
1109
               GLint is = i + n - halfFilterWidth;
1110
               GLint js = j + m - halfFilterHeight;
1111
               GLint k;
1112
               if (is < 0)
1113
                  is = 0;
1114
               else if (is >= srcWidth)
1115
                  is = srcWidth - 1;
1116
               if (js < 0)
1117
                  js = 0;
1118
               else if (js >= srcHeight)
1119
                  js = srcHeight - 1;
1120
               k = js * srcWidth + is;
1121
               sumR += src[k][RCOMP] * filter[f][RCOMP];
1122
               sumG += src[k][GCOMP] * filter[f][GCOMP];
1123
               sumB += src[k][BCOMP] * filter[f][BCOMP];
1124
               sumA += src[k][ACOMP] * filter[f][ACOMP];
1125
            }
1126
         }
1127
         dest[j * srcWidth + i][RCOMP] = sumR;
1128
         dest[j * srcWidth + i][GCOMP] = sumG;
1129
         dest[j * srcWidth + i][BCOMP] = sumB;
1130
         dest[j * srcWidth + i][ACOMP] = sumA;
1131
      }
1132
   }
1133
}
1134
 
1135
 
1136
static void
1137
convolve_sep_reduce(GLint srcWidth, GLint srcHeight,
1138
                    const GLfloat src[][4],
1139
                    GLint filterWidth, GLint filterHeight,
1140
                    const GLfloat rowFilt[][4],
1141
                    const GLfloat colFilt[][4],
1142
                    GLfloat dest[][4])
1143
{
1144
   GLint dstWidth, dstHeight;
1145
   GLint i, j, n, m;
1146
 
1147
   if (filterWidth >= 1)
1148
      dstWidth = srcWidth - (filterWidth - 1);
1149
   else
1150
      dstWidth = srcWidth;
1151
 
1152
   if (filterHeight >= 1)
1153
      dstHeight = srcHeight - (filterHeight - 1);
1154
   else
1155
      dstHeight = srcHeight;
1156
 
1157
   if (dstWidth <= 0 || dstHeight <= 0)
1158
      return;
1159
 
1160
   for (j = 0; j < dstHeight; j++) {
1161
      for (i = 0; i < dstWidth; i++) {
1162
         GLfloat sumR = 0.0;
1163
         GLfloat sumG = 0.0;
1164
         GLfloat sumB = 0.0;
1165
         GLfloat sumA = 0.0;
1166
         for (m = 0; m < filterHeight; m++) {
1167
            for (n = 0; n < filterWidth; n++) {
1168
               GLint k = (j + m) * srcWidth + i + n;
1169
               sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1170
               sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1171
               sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1172
               sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1173
            }
1174
         }
1175
         dest[j * dstWidth + i][RCOMP] = sumR;
1176
         dest[j * dstWidth + i][GCOMP] = sumG;
1177
         dest[j * dstWidth + i][BCOMP] = sumB;
1178
         dest[j * dstWidth + i][ACOMP] = sumA;
1179
      }
1180
   }
1181
}
1182
 
1183
 
1184
static void
1185
convolve_sep_constant(GLint srcWidth, GLint srcHeight,
1186
                      const GLfloat src[][4],
1187
                      GLint filterWidth, GLint filterHeight,
1188
                      const GLfloat rowFilt[][4],
1189
                      const GLfloat colFilt[][4],
1190
                      GLfloat dest[][4],
1191
                      const GLfloat borderColor[4])
1192
{
1193
   const GLint halfFilterWidth = filterWidth / 2;
1194
   const GLint halfFilterHeight = filterHeight / 2;
1195
   GLint i, j, n, m;
1196
 
1197
   for (j = 0; j < srcHeight; j++) {
1198
      for (i = 0; i < srcWidth; i++) {
1199
         GLfloat sumR = 0.0;
1200
         GLfloat sumG = 0.0;
1201
         GLfloat sumB = 0.0;
1202
         GLfloat sumA = 0.0;
1203
         for (m = 0; m < filterHeight; m++) {
1204
            for (n = 0; n < filterWidth; n++) {
1205
               const GLint is = i + n - halfFilterWidth;
1206
               const GLint js = j + m - halfFilterHeight;
1207
               if (is < 0 || is >= srcWidth ||
1208
                   js < 0 || js >= srcHeight) {
1209
                  sumR += borderColor[RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1210
                  sumG += borderColor[GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1211
                  sumB += borderColor[BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1212
                  sumA += borderColor[ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1213
               }
1214
               else {
1215
                  GLint k = js * srcWidth + is;
1216
                  sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1217
                  sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1218
                  sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1219
                  sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1220
               }
1221
 
1222
            }
1223
         }
1224
         dest[j * srcWidth + i][RCOMP] = sumR;
1225
         dest[j * srcWidth + i][GCOMP] = sumG;
1226
         dest[j * srcWidth + i][BCOMP] = sumB;
1227
         dest[j * srcWidth + i][ACOMP] = sumA;
1228
      }
1229
   }
1230
}
1231
 
1232
 
1233
static void
1234
convolve_sep_replicate(GLint srcWidth, GLint srcHeight,
1235
                       const GLfloat src[][4],
1236
                       GLint filterWidth, GLint filterHeight,
1237
                       const GLfloat rowFilt[][4],
1238
                       const GLfloat colFilt[][4],
1239
                       GLfloat dest[][4])
1240
{
1241
   const GLint halfFilterWidth = filterWidth / 2;
1242
   const GLint halfFilterHeight = filterHeight / 2;
1243
   GLint i, j, n, m;
1244
 
1245
   for (j = 0; j < srcHeight; j++) {
1246
      for (i = 0; i < srcWidth; i++) {
1247
         GLfloat sumR = 0.0;
1248
         GLfloat sumG = 0.0;
1249
         GLfloat sumB = 0.0;
1250
         GLfloat sumA = 0.0;
1251
         for (m = 0; m < filterHeight; m++) {
1252
            for (n = 0; n < filterWidth; n++) {
1253
               GLint is = i + n - halfFilterWidth;
1254
               GLint js = j + m - halfFilterHeight;
1255
               GLint k;
1256
               if (is < 0)
1257
                  is = 0;
1258
               else if (is >= srcWidth)
1259
                  is = srcWidth - 1;
1260
               if (js < 0)
1261
                  js = 0;
1262
               else if (js >= srcHeight)
1263
                  js = srcHeight - 1;
1264
               k = js * srcWidth + is;
1265
               sumR += src[k][RCOMP] * rowFilt[n][RCOMP] * colFilt[m][RCOMP];
1266
               sumG += src[k][GCOMP] * rowFilt[n][GCOMP] * colFilt[m][GCOMP];
1267
               sumB += src[k][BCOMP] * rowFilt[n][BCOMP] * colFilt[m][BCOMP];
1268
               sumA += src[k][ACOMP] * rowFilt[n][ACOMP] * colFilt[m][ACOMP];
1269
            }
1270
         }
1271
         dest[j * srcWidth + i][RCOMP] = sumR;
1272
         dest[j * srcWidth + i][GCOMP] = sumG;
1273
         dest[j * srcWidth + i][BCOMP] = sumB;
1274
         dest[j * srcWidth + i][ACOMP] = sumA;
1275
      }
1276
   }
1277
}
1278
 
1279
 
1280
 
1281
void
1282
_mesa_convolve_1d_image(const GLcontext *ctx, GLsizei *width,
1283
                        const GLfloat *srcImage, GLfloat *dstImage)
1284
{
1285
   switch (ctx->Pixel.ConvolutionBorderMode[0]) {
1286
      case GL_REDUCE:
1287
         convolve_1d_reduce(*width, (const GLfloat (*)[4]) srcImage,
1288
                            ctx->Convolution1D.Width,
1289
                            (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1290
                            (GLfloat (*)[4]) dstImage);
1291
         *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1292
         break;
1293
      case GL_CONSTANT_BORDER:
1294
         convolve_1d_constant(*width, (const GLfloat (*)[4]) srcImage,
1295
                              ctx->Convolution1D.Width,
1296
                              (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1297
                              (GLfloat (*)[4]) dstImage,
1298
                              ctx->Pixel.ConvolutionBorderColor[0]);
1299
         break;
1300
      case GL_REPLICATE_BORDER:
1301
         convolve_1d_replicate(*width, (const GLfloat (*)[4]) srcImage,
1302
                              ctx->Convolution1D.Width,
1303
                              (const GLfloat (*)[4]) ctx->Convolution1D.Filter,
1304
                              (GLfloat (*)[4]) dstImage);
1305
         break;
1306
      default:
1307
         ;
1308
   }
1309
}
1310
 
1311
 
1312
void
1313
_mesa_convolve_2d_image(const GLcontext *ctx, GLsizei *width, GLsizei *height,
1314
                        const GLfloat *srcImage, GLfloat *dstImage)
1315
{
1316
   switch (ctx->Pixel.ConvolutionBorderMode[1]) {
1317
      case GL_REDUCE:
1318
         convolve_2d_reduce(*width, *height,
1319
                            (const GLfloat (*)[4]) srcImage,
1320
                            ctx->Convolution2D.Width,
1321
                            ctx->Convolution2D.Height,
1322
                            (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1323
                            (GLfloat (*)[4]) dstImage);
1324
         *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1325
         *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1326
         break;
1327
      case GL_CONSTANT_BORDER:
1328
         convolve_2d_constant(*width, *height,
1329
                              (const GLfloat (*)[4]) srcImage,
1330
                              ctx->Convolution2D.Width,
1331
                              ctx->Convolution2D.Height,
1332
                              (const GLfloat (*)[4]) ctx->Convolution2D.Filter,
1333
                              (GLfloat (*)[4]) dstImage,
1334
                              ctx->Pixel.ConvolutionBorderColor[1]);
1335
         break;
1336
      case GL_REPLICATE_BORDER:
1337
         convolve_2d_replicate(*width, *height,
1338
                               (const GLfloat (*)[4]) srcImage,
1339
                               ctx->Convolution2D.Width,
1340
                               ctx->Convolution2D.Height,
1341
                               (const GLfloat (*)[4])ctx->Convolution2D.Filter,
1342
                               (GLfloat (*)[4]) dstImage);
1343
         break;
1344
      default:
1345
         ;
1346
      }
1347
}
1348
 
1349
 
1350
void
1351
_mesa_convolve_sep_image(const GLcontext *ctx,
1352
                         GLsizei *width, GLsizei *height,
1353
                         const GLfloat *srcImage, GLfloat *dstImage)
1354
{
1355
   const GLfloat *rowFilter = ctx->Separable2D.Filter;
1356
   const GLfloat *colFilter = rowFilter + 4 * MAX_CONVOLUTION_WIDTH;
1357
 
1358
   switch (ctx->Pixel.ConvolutionBorderMode[2]) {
1359
      case GL_REDUCE:
1360
         convolve_sep_reduce(*width, *height,
1361
                             (const GLfloat (*)[4]) srcImage,
1362
                             ctx->Separable2D.Width,
1363
                             ctx->Separable2D.Height,
1364
                             (const GLfloat (*)[4]) rowFilter,
1365
                             (const GLfloat (*)[4]) colFilter,
1366
                             (GLfloat (*)[4]) dstImage);
1367
         *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1368
         *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1369
         break;
1370
      case GL_CONSTANT_BORDER:
1371
         convolve_sep_constant(*width, *height,
1372
                               (const GLfloat (*)[4]) srcImage,
1373
                               ctx->Separable2D.Width,
1374
                               ctx->Separable2D.Height,
1375
                               (const GLfloat (*)[4]) rowFilter,
1376
                               (const GLfloat (*)[4]) colFilter,
1377
                               (GLfloat (*)[4]) dstImage,
1378
                               ctx->Pixel.ConvolutionBorderColor[2]);
1379
         break;
1380
      case GL_REPLICATE_BORDER:
1381
         convolve_sep_replicate(*width, *height,
1382
                                (const GLfloat (*)[4]) srcImage,
1383
                                ctx->Separable2D.Width,
1384
                                ctx->Separable2D.Height,
1385
                                (const GLfloat (*)[4]) rowFilter,
1386
                                (const GLfloat (*)[4]) colFilter,
1387
                                (GLfloat (*)[4]) dstImage);
1388
         break;
1389
      default:
1390
         ;
1391
   }
1392
}
1393
 
1394
 
1395
 
1396
/*
1397
 * This function computes an image's size after convolution.
1398
 * If the convolution border mode is GL_REDUCE, the post-convolution
1399
 * image will be smaller than the original.
1400
 */
1401
void
1402
_mesa_adjust_image_for_convolution(const GLcontext *ctx, GLuint dimensions,
1403
                                   GLsizei *width, GLsizei *height)
1404
{
1405
   if (ctx->Pixel.Convolution1DEnabled
1406
       && dimensions == 1
1407
       && ctx->Pixel.ConvolutionBorderMode[0] == GL_REDUCE) {
1408
      *width = *width - (MAX2(ctx->Convolution1D.Width, 1) - 1);
1409
   }
1410
   else if (ctx->Pixel.Convolution2DEnabled
1411
            && dimensions > 1
1412
            && ctx->Pixel.ConvolutionBorderMode[1] == GL_REDUCE) {
1413
      *width = *width - (MAX2(ctx->Convolution2D.Width, 1) - 1);
1414
      *height = *height - (MAX2(ctx->Convolution2D.Height, 1) - 1);
1415
   }
1416
   else if (ctx->Pixel.Separable2DEnabled
1417
            && dimensions > 1
1418
            && ctx->Pixel.ConvolutionBorderMode[2] == GL_REDUCE) {
1419
      *width = *width - (MAX2(ctx->Separable2D.Width, 1) - 1);
1420
      *height = *height - (MAX2(ctx->Separable2D.Height, 1) - 1);
1421
   }
1422
}