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