001 /* 002 * 003 004 Licensed under the Apache License, Version 2.0 (the "License"); 005 you may not use this file except in compliance with the License. 006 You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010 Unless required by applicable law or agreed to in writing, software 011 distributed under the License is distributed on an "AS IS" BASIS, 012 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 See the License for the specific language governing permissions and 014 limitations under the License. 015 */ 016 017 package railo.runtime.img.filter;import java.awt.Color; 018 import java.awt.Image; 019 import java.awt.Rectangle; 020 import java.awt.image.BufferedImage; 021 import java.awt.image.Kernel; 022 import java.util.Vector; 023 024 import railo.runtime.engine.ThreadLocalPageContext; 025 import railo.runtime.exp.FunctionException; 026 import railo.runtime.exp.PageException; 027 import railo.runtime.img.ImageUtil; 028 import railo.runtime.img.math.Function2D; 029 import railo.runtime.img.math.ImageFunction2D; 030 import railo.runtime.img.vecmath.Color4f; 031 import railo.runtime.img.vecmath.Vector3f; 032 import railo.runtime.type.KeyImpl; 033 import railo.runtime.type.Struct; 034 import railo.runtime.type.util.CollectionUtil; 035 036 /** 037 * A filter which produces lighting and embossing effects. 038 */ 039 public class LightFilter extends WholeImageFilter implements DynFiltering { 040 041 /** 042 * Take the output colors from the input image. 043 */ 044 public final static int COLORS_FROM_IMAGE = 0; 045 046 /** 047 * Use constant material color. 048 */ 049 public final static int COLORS_CONSTANT = 1; 050 051 /** 052 * Use the input image brightness as the bump map. 053 */ 054 public final static int BUMPS_FROM_IMAGE = 0; 055 056 /** 057 * Use the input image alpha as the bump map. 058 */ 059 public final static int BUMPS_FROM_IMAGE_ALPHA = 1; 060 061 /** 062 * Use a separate image alpha channel as the bump map. 063 */ 064 public final static int BUMPS_FROM_MAP = 2; 065 066 /** 067 * Use a custom function as the bump map. 068 */ 069 public final static int BUMPS_FROM_BEVEL = 3; 070 071 private float bumpHeight; 072 private float bumpSoftness; 073 private int bumpShape; 074 private float viewDistance = 10000.0f; 075 Material material; 076 private Vector lights; 077 private int colorSource = COLORS_FROM_IMAGE; 078 private int bumpSource = BUMPS_FROM_IMAGE; 079 private Function2D bumpFunction; 080 private Image environmentMap; 081 private int[] envPixels; 082 private int envWidth = 1, envHeight = 1; 083 084 // Temporary variables used to avoid per-pixel memory allocation while filtering 085 private Vector3f l; 086 private Vector3f v; 087 private Vector3f n; 088 private Color4f shadedColor; 089 private Color4f diffuse_color; 090 private Color4f specular_color; 091 private Vector3f tmpv, tmpv2; 092 093 public LightFilter() { 094 lights = new Vector(); 095 addLight(new DistantLight()); 096 bumpHeight = 1.0f; 097 bumpSoftness = 5.0f; 098 bumpShape = 0; 099 material = new Material(); 100 l = new Vector3f(); 101 v = new Vector3f(); 102 n = new Vector3f(); 103 shadedColor = new Color4f(); 104 diffuse_color = new Color4f(); 105 specular_color = new Color4f(); 106 tmpv = new Vector3f(); 107 tmpv2 = new Vector3f(); 108 } 109 110 public void setMaterial( Material material ) { 111 this.material = material; 112 } 113 114 public Material getMaterial() { 115 return material; 116 } 117 118 public void setBumpFunction(Function2D bumpFunction) { 119 this.bumpFunction = bumpFunction; 120 } 121 122 public Function2D getBumpFunction() { 123 return bumpFunction; 124 } 125 126 public void setBumpHeight(float bumpHeight) { 127 this.bumpHeight = bumpHeight; 128 } 129 130 public float getBumpHeight() { 131 return bumpHeight; 132 } 133 134 public void setBumpSoftness(float bumpSoftness) { 135 this.bumpSoftness = bumpSoftness; 136 } 137 138 public float getBumpSoftness() { 139 return bumpSoftness; 140 } 141 142 public void setBumpShape(int bumpShape) { 143 this.bumpShape = bumpShape; 144 } 145 146 public int getBumpShape() { 147 return bumpShape; 148 } 149 150 public void setViewDistance(float viewDistance) { 151 this.viewDistance = viewDistance; 152 } 153 154 public float getViewDistance() { 155 return viewDistance; 156 } 157 158 public void setEnvironmentMap(BufferedImage environmentMap) { 159 this.environmentMap = environmentMap; 160 if (environmentMap != null) { 161 envWidth = environmentMap.getWidth(); 162 envHeight = environmentMap.getHeight(); 163 envPixels = getRGB( environmentMap, 0, 0, envWidth, envHeight, null ); 164 } else { 165 envWidth = envHeight = 1; 166 envPixels = null; 167 } 168 } 169 170 public Image getEnvironmentMap() { 171 return environmentMap; 172 } 173 174 public void setColorSource(int colorSource) { 175 this.colorSource = colorSource; 176 } 177 178 public int getColorSource() { 179 return colorSource; 180 } 181 182 public void setBumpSource(int bumpSource) { 183 this.bumpSource = bumpSource; 184 } 185 186 public int getBumpSource() { 187 return bumpSource; 188 } 189 190 public void setDiffuseColor(int diffuseColor) { 191 material.diffuseColor = diffuseColor; 192 } 193 194 public int getDiffuseColor() { 195 return material.diffuseColor; 196 } 197 198 public void addLight(Light light) { 199 lights.addElement(light); 200 } 201 202 public void removeLight(Light light) { 203 lights.removeElement(light); 204 } 205 206 public Vector getLights() { 207 return lights; 208 } 209 210 protected final static float r255 = 1.0f/255.0f; 211 212 protected void setFromRGB( Color4f c, int argb ) { 213 c.set( ((argb >> 16) & 0xff) * r255, ((argb >> 8) & 0xff) * r255, (argb & 0xff) * r255, ((argb >> 24) & 0xff) * r255 ); 214 } 215 216 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 217 int index = 0; 218 int[] outPixels = new int[width * height]; 219 float width45 = Math.abs(6.0f * bumpHeight); 220 boolean invertBumps = bumpHeight < 0; 221 Vector3f position = new Vector3f(0.0f, 0.0f, 0.0f); 222 Vector3f viewpoint = new Vector3f(width / 2.0f, height / 2.0f, viewDistance); 223 Vector3f normal = new Vector3f(); 224 Color4f envColor = new Color4f(); 225 Color4f diffuseColor = new Color4f( new Color(material.diffuseColor) ); 226 Color4f specularColor = new Color4f( new Color(material.specularColor) ); 227 Function2D bump = bumpFunction; 228 229 // Apply the bump softness 230 if (bumpSource == BUMPS_FROM_IMAGE || bumpSource == BUMPS_FROM_IMAGE_ALPHA || bumpSource == BUMPS_FROM_MAP || bump == null) { 231 if ( bumpSoftness != 0 ) { 232 int bumpWidth = width; 233 int bumpHeight = height; 234 int[] bumpPixels = inPixels; 235 if ( bumpSource == BUMPS_FROM_MAP && bumpFunction instanceof ImageFunction2D ) { 236 ImageFunction2D if2d = (ImageFunction2D)bumpFunction; 237 bumpWidth = if2d.getWidth(); 238 bumpHeight = if2d.getHeight(); 239 bumpPixels = if2d.getPixels(); 240 } 241 int [] tmpPixels = new int[bumpWidth * bumpHeight]; 242 int [] softPixels = new int[bumpWidth * bumpHeight]; 243 /* 244 for (int i = 0; i < 3; i++ ) { 245 BoxBlurFilter.blur( bumpPixels, tmpPixels, bumpWidth, bumpHeight, (int)bumpSoftness ); 246 BoxBlurFilter.blur( tmpPixels, softPixels, bumpHeight, bumpWidth, (int)bumpSoftness ); 247 } 248 */ 249 Kernel kernel = GaussianFilter.makeKernel( bumpSoftness ); 250 GaussianFilter.convolveAndTranspose( kernel, bumpPixels, tmpPixels, bumpWidth, bumpHeight, true, false, false, GaussianFilter.WRAP_EDGES ); 251 GaussianFilter.convolveAndTranspose( kernel, tmpPixels, softPixels, bumpHeight, bumpWidth, true, false, false, GaussianFilter.WRAP_EDGES ); 252 bump = new ImageFunction2D(softPixels, bumpWidth, bumpHeight, ImageFunction2D.CLAMP, bumpSource == BUMPS_FROM_IMAGE_ALPHA); 253 final Function2D bbump = bump; 254 if ( bumpShape != 0 ) { 255 bump = new Function2D() { 256 private Function2D original = bbump; 257 258 public float evaluate(float x, float y) { 259 float v = original.evaluate( x, y ); 260 switch ( bumpShape ) { 261 case 1: 262 // v = v > 0.5f ? 0.5f : v; 263 v *= ImageMath.smoothStep( 0.45f, 0.55f, v ); 264 break; 265 case 2: 266 v = v < 0.5f ? 0.5f : v; 267 break; 268 case 3: 269 v = ImageMath.triangle( v ); 270 break; 271 case 4: 272 v = ImageMath.circleDown( v ); 273 break; 274 case 5: 275 v = ImageMath.gain( v, 0.75f ); 276 break; 277 } 278 return v; 279 } 280 }; 281 } 282 } else if ( bumpSource != BUMPS_FROM_MAP ) 283 bump = new ImageFunction2D(inPixels, width, height, ImageFunction2D.CLAMP, bumpSource == BUMPS_FROM_IMAGE_ALPHA); 284 } 285 286 float reflectivity = material.reflectivity; 287 float areflectivity = (1-reflectivity); 288 Vector3f v1 = new Vector3f(); 289 Vector3f v2 = new Vector3f(); 290 Vector3f n = new Vector3f(); 291 Light[] lightsArray = new Light[lights.size()]; 292 lights.copyInto(lightsArray); 293 for (int i = 0; i < lightsArray.length; i++) 294 lightsArray[i].prepare(width, height); 295 296 float[][] heightWindow = new float[3][width]; 297 for (int x = 0; x < width; x++) 298 heightWindow[1][x] = width45*bump.evaluate(x, 0); 299 300 // Loop through each source pixel 301 for (int y = 0; y < height; y++) { 302 boolean y0 = y > 0; 303 boolean y1 = y < height-1; 304 position.y = y; 305 for (int x = 0; x < width; x++) 306 heightWindow[2][x] = width45*bump.evaluate(x, y+1); 307 for (int x = 0; x < width; x++) { 308 boolean x0 = x > 0; 309 boolean x1 = x < width-1; 310 311 // Calculate the normal at this point 312 if (bumpSource != BUMPS_FROM_BEVEL) { 313 // Complicated and slower method 314 // Calculate four normals using the gradients in +/- X/Y directions 315 int count = 0; 316 normal.x = normal.y = normal.z = 0; 317 float m0 = heightWindow[1][x]; 318 float m1 = x0 ? heightWindow[1][x-1]-m0 : 0; 319 float m2 = y0 ? heightWindow[0][x]-m0 : 0; 320 float m3 = x1 ? heightWindow[1][x+1]-m0 : 0; 321 float m4 = y1 ? heightWindow[2][x]-m0 : 0; 322 323 if (x0 && y1) { 324 v1.x = -1.0f; v1.y = 0.0f; v1.z = m1; 325 v2.x = 0.0f; v2.y = 1.0f; v2.z = m4; 326 n.cross(v1, v2); 327 n.normalize(); 328 if (n.z < 0.0) 329 n.z = -n.z; 330 normal.add(n); 331 count++; 332 } 333 334 if (x0 && y0) { 335 v1.x = -1.0f; v1.y = 0.0f; v1.z = m1; 336 v2.x = 0.0f; v2.y = -1.0f; v2.z = m2; 337 n.cross(v1, v2); 338 n.normalize(); 339 if (n.z < 0.0) 340 n.z = -n.z; 341 normal.add(n); 342 count++; 343 } 344 345 if (y0 && x1) { 346 v1.x = 0.0f; v1.y = -1.0f; v1.z = m2; 347 v2.x = 1.0f; v2.y = 0.0f; v2.z = m3; 348 n.cross(v1, v2); 349 n.normalize(); 350 if (n.z < 0.0) 351 n.z = -n.z; 352 normal.add(n); 353 count++; 354 } 355 356 if (x1 && y1) { 357 v1.x = 1.0f; v1.y = 0.0f; v1.z = m3; 358 v2.x = 0.0f; v2.y = 1.0f; v2.z = m4; 359 n.cross(v1, v2); 360 n.normalize(); 361 if (n.z < 0.0) 362 n.z = -n.z; 363 normal.add(n); 364 count++; 365 } 366 367 // Average the four normals 368 normal.x /= count; 369 normal.y /= count; 370 normal.z /= count; 371 } 372 if (invertBumps) { 373 normal.x = -normal.x; 374 normal.y = -normal.y; 375 } 376 position.x = x; 377 378 if (normal.z >= 0) { 379 // Get the material colour at this point 380 if (colorSource == COLORS_FROM_IMAGE) 381 setFromRGB(diffuseColor, inPixels[index]); 382 else 383 setFromRGB(diffuseColor, material.diffuseColor); 384 if (reflectivity != 0 && environmentMap != null) { 385 //FIXME-too much normalizing going on here 386 tmpv2.set(viewpoint); 387 tmpv2.sub(position); 388 tmpv2.normalize(); 389 tmpv.set(normal); 390 tmpv.normalize(); 391 392 // Reflect 393 tmpv.scale( 2.0f*tmpv.dot(tmpv2) ); 394 tmpv.sub(v); 395 396 tmpv.normalize(); 397 setFromRGB(envColor, getEnvironmentMap(tmpv, inPixels, width, height));//FIXME-interpolate() 398 diffuseColor.x = reflectivity*envColor.x + areflectivity*diffuseColor.x; 399 diffuseColor.y = reflectivity*envColor.y + areflectivity*diffuseColor.y; 400 diffuseColor.z = reflectivity*envColor.z + areflectivity*diffuseColor.z; 401 } 402 // Shade the pixel 403 Color4f c = phongShade(position, viewpoint, normal, diffuseColor, specularColor, material, lightsArray); 404 int alpha = inPixels[index] & 0xff000000; 405 int rgb = ((int)(c.x * 255) << 16) | ((int)(c.y * 255) << 8) | (int)(c.z * 255); 406 outPixels[index++] = alpha | rgb; 407 } else 408 outPixels[index++] = 0; 409 } 410 float[] t = heightWindow[0]; 411 heightWindow[0] = heightWindow[1]; 412 heightWindow[1] = heightWindow[2]; 413 heightWindow[2] = t; 414 } 415 return outPixels; 416 } 417 418 protected Color4f phongShade(Vector3f position, Vector3f viewpoint, Vector3f normal, Color4f diffuseColor, Color4f specularColor, Material material, Light[] lightsArray) { 419 shadedColor.set(diffuseColor); 420 shadedColor.scale(material.ambientIntensity); 421 422 for (int i = 0; i < lightsArray.length; i++) { 423 Light light = lightsArray[i]; 424 n.set(normal); 425 l.set(light.position); 426 if (light.type != DISTANT) 427 l.sub(position); 428 l.normalize(); 429 float nDotL = n.dot(l); 430 if (nDotL >= 0.0) { 431 float dDotL = 0; 432 433 v.set(viewpoint); 434 v.sub(position); 435 v.normalize(); 436 437 // Spotlight 438 if (light.type == SPOT) { 439 dDotL = light.direction.dot(l); 440 if (dDotL < light.cosConeAngle) 441 continue; 442 } 443 444 n.scale(2.0f * nDotL); 445 n.sub(l); 446 float rDotV = n.dot(v); 447 448 float rv; 449 if (rDotV < 0.0) 450 rv = 0.0f; 451 else 452 // rv = (float)Math.pow(rDotV, material.highlight); 453 rv = rDotV / (material.highlight - material.highlight*rDotV + rDotV); // Fast approximation to pow 454 455 // Spotlight 456 if (light.type == SPOT) { 457 dDotL = light.cosConeAngle/dDotL; 458 float e = dDotL; 459 e *= e; 460 e *= e; 461 e *= e; 462 e = (float)Math.pow(dDotL, light.focus*10)*(1 - e); 463 rv *= e; 464 nDotL *= e; 465 } 466 467 diffuse_color.set(diffuseColor); 468 diffuse_color.scale(material.diffuseReflectivity); 469 diffuse_color.x *= light.realColor.x * nDotL; 470 diffuse_color.y *= light.realColor.y * nDotL; 471 diffuse_color.z *= light.realColor.z * nDotL; 472 specular_color.set(specularColor); 473 specular_color.scale(material.specularReflectivity); 474 specular_color.x *= light.realColor.x * rv; 475 specular_color.y *= light.realColor.y * rv; 476 specular_color.z *= light.realColor.z * rv; 477 diffuse_color.add(specular_color); 478 diffuse_color.clamp( 0, 1 ); 479 shadedColor.add(diffuse_color); 480 } 481 } 482 shadedColor.clamp( 0, 1 ); 483 return shadedColor; 484 } 485 486 private int getEnvironmentMap(Vector3f normal, int[] inPixels, int width, int height) { 487 if (environmentMap != null) { 488 float angle = (float)Math.acos(-normal.y); 489 490 float x, y; 491 y = angle/ImageMath.PI; 492 493 if (y == 0.0f || y == 1.0f) 494 x = 0.0f; 495 else { 496 float f = normal.x/(float)Math.sin(angle); 497 498 if (f > 1.0f) 499 f = 1.0f; 500 else if (f < -1.0f) 501 f = -1.0f; 502 503 x = (float)Math.acos(f)/ImageMath.PI; 504 } 505 // A bit of empirical scaling.... 506 x = ImageMath.clamp(x * envWidth, 0, envWidth-1); 507 y = ImageMath.clamp(y * envHeight, 0, envHeight-1); 508 int ix = (int)x; 509 int iy = (int)y; 510 511 float xWeight = x-ix; 512 float yWeight = y-iy; 513 int i = envWidth*iy + ix; 514 int dx = ix == envWidth-1 ? 0 : 1; 515 int dy = iy == envHeight-1 ? 0 : envWidth; 516 return ImageMath.bilinearInterpolate( xWeight, yWeight, envPixels[i], envPixels[i+dx], envPixels[i+dy], envPixels[i+dx+dy] ); 517 } 518 return 0; 519 } 520 521 public String toString() { 522 return "Stylize/Light Effects..."; 523 } 524 525 /** 526 * A class representing material properties. 527 */ 528 public static class Material { 529 int diffuseColor; 530 int specularColor; 531 float ambientIntensity; 532 float diffuseReflectivity; 533 float specularReflectivity; 534 float highlight; 535 float reflectivity; 536 float opacity = 1; 537 538 public Material() { 539 ambientIntensity = 0.5f; 540 diffuseReflectivity = 1.0f; 541 specularReflectivity = 1.0f; 542 highlight = 3.0f; 543 reflectivity = 0.0f; 544 diffuseColor = 0xff888888; 545 specularColor = 0xffffffff; 546 } 547 548 public void setDiffuseColor(int diffuseColor) { 549 this.diffuseColor = diffuseColor; 550 } 551 552 public int getDiffuseColor() { 553 return diffuseColor; 554 } 555 556 public void setOpacity( float opacity ) { 557 this.opacity = opacity; 558 } 559 560 public float getOpacity() { 561 return opacity; 562 } 563 564 } 565 566 public final static int AMBIENT = 0; 567 public final static int DISTANT = 1; 568 public final static int POINT = 2; 569 public final static int SPOT = 3; 570 571 /** 572 * A class representing a light. 573 */ 574 public static class Light implements Cloneable { 575 576 int type = AMBIENT; 577 Vector3f position; 578 Vector3f direction; 579 Color4f realColor = new Color4f(); 580 int color = 0xffffffff; 581 float intensity; 582 float azimuth; 583 float elevation; 584 float focus = 0.5f; 585 float centreX = 0.5f, centreY = 0.5f; 586 float coneAngle = ImageMath.PI/6; 587 float cosConeAngle; 588 float distance = 100.0f; 589 590 public Light() { 591 this(270*ImageMath.PI/180.0f, 0.5235987755982988f, 1.0f); 592 } 593 594 public Light(float azimuth, float elevation, float intensity) { 595 this.azimuth = azimuth; 596 this.elevation = elevation; 597 this.intensity = intensity; 598 } 599 600 public void setAzimuth(float azimuth) { 601 this.azimuth = azimuth; 602 } 603 604 public float getAzimuth() { 605 return azimuth; 606 } 607 608 public void setElevation(float elevation) { 609 this.elevation = elevation; 610 } 611 612 public float getElevation() { 613 return elevation; 614 } 615 616 public void setDistance(float distance) { 617 this.distance = distance; 618 } 619 620 public float getDistance() { 621 return distance; 622 } 623 624 public void setIntensity(float intensity) { 625 this.intensity = intensity; 626 } 627 628 public float getIntensity() { 629 return intensity; 630 } 631 632 public void setConeAngle(float coneAngle) { 633 this.coneAngle = coneAngle; 634 } 635 636 public float getConeAngle() { 637 return coneAngle; 638 } 639 640 public void setFocus(float focus) { 641 this.focus = focus; 642 } 643 644 public float getFocus() { 645 return focus; 646 } 647 648 public void setColor(int color) { 649 this.color = color; 650 } 651 652 public int getColor() { 653 return color; 654 } 655 656 /** 657 * Set the centre of the light in the X direction as a proportion of the image size. 658 * @param centreX the center 659 * @see #getCentreX 660 */ 661 public void setCentreX(float x) { 662 centreX = x; 663 } 664 665 /** 666 * Get the centre of the light in the X direction as a proportion of the image size. 667 * @return the center 668 * @see #setCentreX 669 */ 670 public float getCentreX() { 671 return centreX; 672 } 673 674 /** 675 * Set the centre of the light in the Y direction as a proportion of the image size. 676 * @param centreY the center 677 * @see #getCentreY 678 */ 679 public void setCentreY(float y) { 680 centreY = y; 681 } 682 683 /** 684 * Get the centre of the light in the Y direction as a proportion of the image size. 685 * @return the center 686 * @see #setCentreY 687 */ 688 public float getCentreY() { 689 return centreY; 690 } 691 692 /** 693 * Prepare the light for rendering. 694 * @param width the output image width 695 * @param height the output image height 696 */ 697 public void prepare(int width, int height) { 698 float lx = (float)(Math.cos(azimuth) * Math.cos(elevation)); 699 float ly = (float)(Math.sin(azimuth) * Math.cos(elevation)); 700 float lz = (float)Math.sin(elevation); 701 direction = new Vector3f(lx, ly, lz); 702 direction.normalize(); 703 if (type != DISTANT) { 704 lx *= distance; 705 ly *= distance; 706 lz *= distance; 707 lx += width * centreX; 708 ly += height * centreY; 709 } 710 position = new Vector3f(lx, ly, lz); 711 realColor.set( new Color(color) ); 712 realColor.scale(intensity); 713 cosConeAngle = (float)Math.cos(coneAngle); 714 } 715 716 public Object clone() { 717 try { 718 Light copy = (Light)super.clone(); 719 return copy; 720 } 721 catch (CloneNotSupportedException e) { 722 return null; 723 } 724 } 725 726 public String toString() { 727 return "Light"; 728 } 729 730 } 731 732 public class AmbientLight extends Light { 733 public String toString() { 734 return "Ambient Light"; 735 } 736 } 737 738 public class PointLight extends Light { 739 public PointLight() { 740 type = POINT; 741 } 742 743 public String toString() { 744 return "Point Light"; 745 } 746 } 747 748 public class DistantLight extends Light { 749 public DistantLight() { 750 type = DISTANT; 751 } 752 753 public String toString() { 754 return "Distant Light"; 755 } 756 } 757 758 public class SpotLight extends Light { 759 public SpotLight() { 760 type = SPOT; 761 } 762 763 public String toString() { 764 return "Spotlight"; 765 } 766 } 767 public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src); 768 Object o; 769 if((o=parameters.removeEL(KeyImpl.init("ColorSource")))!=null)setColorSource(ImageFilterUtil.toColorRGB(o,"ColorSource")); 770 if((o=parameters.removeEL(KeyImpl.init("Material")))!=null)setMaterial(ImageFilterUtil.toLightFilter$Material(o,"Material")); 771 if((o=parameters.removeEL(KeyImpl.init("BumpFunction")))!=null)setBumpFunction(ImageFilterUtil.toFunction2D(o,"BumpFunction")); 772 if((o=parameters.removeEL(KeyImpl.init("BumpHeight")))!=null)setBumpHeight(ImageFilterUtil.toFloatValue(o,"BumpHeight")); 773 if((o=parameters.removeEL(KeyImpl.init("BumpSoftness")))!=null)setBumpSoftness(ImageFilterUtil.toFloatValue(o,"BumpSoftness")); 774 if((o=parameters.removeEL(KeyImpl.init("BumpShape")))!=null)setBumpShape(ImageFilterUtil.toIntValue(o,"BumpShape")); 775 if((o=parameters.removeEL(KeyImpl.init("ViewDistance")))!=null)setViewDistance(ImageFilterUtil.toFloatValue(o,"ViewDistance")); 776 if((o=parameters.removeEL(KeyImpl.init("EnvironmentMap")))!=null)setEnvironmentMap(ImageFilterUtil.toBufferedImage(o,"EnvironmentMap")); 777 if((o=parameters.removeEL(KeyImpl.init("BumpSource")))!=null)setBumpSource(ImageFilterUtil.toIntValue(o,"BumpSource")); 778 if((o=parameters.removeEL(KeyImpl.init("DiffuseColor")))!=null)setDiffuseColor(ImageFilterUtil.toColorRGB(o,"DiffuseColor")); 779 780 // check for arguments not supported 781 if(parameters.size()>0) { 782 throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+CollectionUtil.getKeyList(parameters,", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [ColorSource, Material, BumpFunction, BumpHeight, BumpSoftness, BumpShape, ViewDistance, EnvironmentMap, BumpSource, DiffuseColor]"); 783 } 784 785 return filter(src, dst); 786 } 787 }