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