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