API Documentation
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_scene_glge_light.js.html, line: 145 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_scene_glge_light.js.html, line: 145 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_scene_glge_light.js.html, line: 479 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_scene_glge_light.js.html, line: 479 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_scene_glge_light.js.html, line: 498 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
Warning: DOMDocument::loadHTMLFile() [domdocument.loadhtmlfile]: htmlParseEntityRef: no name in jsdoc/symbols/src/src_scene_glge_light.js.html, line: 498 in /homepages/22/d163487924/htdocs/glge/wp-content/themes/glge/manual.php on line 29
1 /* 2 GLGE WebGL Graphics Engine 3 Copyright (c) 2010, Paul Brunt 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of GLGE nor the 14 names of its contributors may be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY 21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @fileOverview 31 * @name glge_light.js 32 * @author me@paulbrunt.co.uk 33 */ 34 35 36 (function(GLGE){ 37 38 39 40 /** 41 * @class Creates a new light source to be added to a scene 42 * @property {Boolean} diffuse Dose this light source effect diffuse shading 43 * @property {Boolean} specular Dose this light source effect specular shading 44 * @augments GLGE.Animatable 45 * @augments GLGE.Placeable 46 * @augments GLGE.QuickNotation 47 * @augments GLGE.JSONLoader 48 */ 49 GLGE.Light=function(uid){ 50 this.color={r:1,g:1,b:1}; 51 GLGE.Assets.registerAsset(this,uid); 52 } 53 GLGE.augment(GLGE.Placeable,GLGE.Light); 54 GLGE.augment(GLGE.Animatable,GLGE.Light); 55 GLGE.augment(GLGE.QuickNotation,GLGE.Light); 56 GLGE.augment(GLGE.JSONLoader,GLGE.Light); 57 GLGE.Light.prototype.className="Light"; 58 59 /** 60 * @name GLGE.Light#shaderupdate 61 * @event fires when a light has changed resulting in need to recompile shaders 62 * @param {object} data 63 */ 64 65 /** 66 * @constant 67 * @description Enumeration for an point light source 68 */ 69 GLGE.L_POINT=1; 70 /** 71 * @constant 72 * @description Enumeration for an directional light source 73 */ 74 GLGE.L_DIR=2; 75 /** 76 * @constant 77 * @description Enumeration for an spot light source 78 */ 79 GLGE.L_SPOT=3; 80 /** 81 * @constant 82 * @description Enumeration a light that is disabled 83 */ 84 GLGE.L_OFF=4; 85 86 GLGE.Light.prototype.constantAttenuation=1; 87 GLGE.Light.prototype.linearAttenuation=0.002; 88 GLGE.Light.prototype.quadraticAttenuation=0.0008; 89 GLGE.Light.prototype.spotCosCutOff=0.95; 90 GLGE.Light.prototype.spotCutOff=true; 91 GLGE.Light.prototype.spotPMatrix=null; 92 GLGE.Light.prototype.spotExponent=10; 93 GLGE.Light.prototype.color=null; 94 GLGE.Light.prototype.diffuse=true; 95 GLGE.Light.prototype.specular=true; 96 GLGE.Light.prototype.samples=0; 97 GLGE.Light.prototype.softness=0.01; 98 GLGE.Light.prototype.type=GLGE.L_POINT; 99 GLGE.Light.prototype.frameBuffer=null; 100 GLGE.Light.prototype.renderBuffer=null; 101 GLGE.Light.prototype.texture=null; 102 GLGE.Light.prototype.bufferHeight=256; 103 GLGE.Light.prototype.bufferWidth=256; 104 GLGE.Light.prototype.shadowBias=0.002; 105 GLGE.Light.prototype.castShadows=false; 106 GLGE.Light.prototype.cascadeLevels=3; 107 GLGE.Light.prototype.distance=500; 108 GLGE.Light.prototype.spotSoftness=0; 109 GLGE.Light.prototype.spotSoftnessDistance=0.3; 110 111 112 /** 113 * Gets the number of cascade levels to use for directional shadows 114 * @returns {number} the number of cascades 115 */ 116 GLGE.Light.prototype.getCascadeLevels=function(){ 117 return this.cascadeLevels; 118 } 119 /** 120 * Sets the number of cascade levels for directions shadows 121 * @param {number} cascadeLevels The number of cascade levels(higher slower better quailty) 122 */ 123 GLGE.Light.prototype.setCascadeLevels=function(cascadeLevels){ 124 this.cascadeLevels=+cascadeLevels; 125 this.fireEvent("shaderupdate",{}); 126 return this; 127 } 128 129 130 /** 131 * Gets the spot lights projection matrix 132 * @returns the lights spot projection matrix 133 * @private 134 */ 135 GLGE.Light.prototype.getPMatrix=function(cvp,invlight,projectedDistance,distance){ 136 if(!this.spotPMatrix){ 137 var far; 138 if(this.scene && this.scene.camera) far=this.scene.camera.far; 139 else far=1000; 140 if(this.type==GLGE.L_SPOT){ 141 this.spotPMatrix=GLGE.makePerspective(Math.acos(this.spotCosCutOff)/3.14159*360, 1.0, 0.1, far); 142 } 143 } 144 if(this.type==GLGE.L_DIR){ 145 this.spotPMatrix=GLGE.getDirLightProjection(cvp,invlight,projectedDistance,distance); 146 } 147 return this.spotPMatrix; 148 } 149 150 151 152 /** 153 * Sets the shadow casting flag 154 * @param {number} distance 155 */ 156 GLGE.Light.prototype.setDistance=function(value){ 157 this.distance=value; 158 this.fireEvent("shaderupdate",{}); 159 return this; 160 } 161 /** 162 * Gets the shadow casting distance 163 * @returns {number} distance 164 */ 165 GLGE.Light.prototype.getDistance=function(){ 166 return this.distance; 167 } 168 169 /** 170 * Sets negative shadow flag 171 * @param {boolean} negative shadow 172 */ 173 GLGE.Light.prototype.setNegativeShadow=function(value){ 174 this.negativeShadow=value; 175 this.fireEvent("shaderupdate",{}); 176 return this; 177 } 178 /** 179 * Gets negative shadow flag 180 * @param {boolean} negative shadow 181 */ 182 GLGE.Light.prototype.getNegative=function(){ 183 return this.negativeShadow; 184 } 185 186 /** 187 * Sets the shadow casting flag 188 * @param {number} value should cast shadows? 189 */ 190 GLGE.Light.prototype.setCastShadows=function(value){ 191 this.castShadows=value; 192 this.fireEvent("shaderupdate",{}); 193 return this; 194 } 195 /** 196 * Gets the shadow casting flag 197 * @returns {number} true if casts shadows 198 */ 199 GLGE.Light.prototype.getCastShadows=function(){ 200 return this.castShadows; 201 return this; 202 } 203 /** 204 * Sets the shadow bias 205 * @param {number} value The shadow bias 206 */ 207 GLGE.Light.prototype.setShadowBias=function(value){ 208 this.shadowBias=value; 209 return this; 210 } 211 /** 212 * Gets the shadow bias 213 * @returns {number} The shadow buffer bias 214 */ 215 GLGE.Light.prototype.getShadowBias=function(){ 216 return this.shadowBias; 217 } 218 219 /** 220 * Sets the number of samples for this shadow 221 * @param {number} value The number of samples to perform 222 */ 223 GLGE.Light.prototype.setShadowSamples=function(value){ 224 this.samples=value; 225 this.fireEvent("shaderupdate",{}); 226 return this; 227 } 228 /** 229 * Gets the number of samples for this shadow 230 * @returns {number} The number of samples 231 */ 232 GLGE.Light.prototype.getShadowSamples=function(){ 233 return this.samples; 234 } 235 /** 236 * Sets the shadow softness 237 * @param {number} value The number of samples to perform 238 */ 239 GLGE.Light.prototype.setShadowSoftness=function(value){ 240 this.softness=value; 241 this.fireEvent("shaderupdate",{}); 242 return this; 243 } 244 /** 245 * Gets the shadow softness 246 * @returns {number} The softness of the shadows 247 */ 248 GLGE.Light.prototype.getShadowSamples=function(){ 249 return this.softness; 250 } 251 /** 252 * Sets the shadow buffer width 253 * @param {number} value The shadow buffer width 254 */ 255 GLGE.Light.prototype.setBufferWidth=function(value){ 256 this.bufferWidth=value; 257 return this; 258 } 259 /** 260 * Gets the shadow buffer width 261 * @returns {number} The shadow buffer width 262 */ 263 GLGE.Light.prototype.getBufferHeight=function(){ 264 return this.bufferHeight; 265 } 266 /** 267 * Sets the shadow buffer width 268 * @param {number} value The shadow buffer width 269 */ 270 GLGE.Light.prototype.setBufferHeight=function(value){ 271 this.bufferHeight=value; 272 return this; 273 } 274 /** 275 * Gets the shadow buffer width 276 * @returns {number} The shadow buffer width 277 */ 278 GLGE.Light.prototype.getBufferWidth=function(){ 279 return this.bufferWidth; 280 } 281 /** 282 * Sets the spot light cut off 283 * @param {number} value The cos of the angle to limit 284 */ 285 GLGE.Light.prototype.setSpotCosCutOff=function(value){ 286 this.spotPMatrix=null; 287 this.spotCosCutOff=value; 288 return this; 289 } 290 /** 291 * Gets the spot light cut off 292 * @returns {number} The cos of the limiting angle 293 */ 294 GLGE.Light.prototype.getSpotCosCutOff=function(){ 295 return this.spotCosCutOff; 296 } 297 298 /** 299 * Sets the spot light cut off true results in circle spot light otherwise square 300 * @param {number} value The spot cutoff flag 301 */ 302 GLGE.Light.prototype.setSpotCutOff=function(value){ 303 this.spotCutOff=value; 304 this.fireEvent("shaderupdate",{}); 305 return this; 306 } 307 /** 308 * Gets the spot light cut off flag 309 * @returns {number} The spot cutoff flag 310 */ 311 GLGE.Light.prototype.getSpotCutOff=function(){ 312 return this.spotCutOff; 313 } 314 315 /** 316 * Sets the spot light exponent 317 * @param {number} value The spot lights exponent 318 */ 319 GLGE.Light.prototype.setSpotExponent=function(value){ 320 this.spotExponent=value; 321 return this; 322 } 323 /** 324 * Gets the spot light exponent 325 * @returns {number} The exponent of the spot light 326 */ 327 GLGE.Light.prototype.getSpotExponent=function(){ 328 return this.spotExponent; 329 } 330 /** 331 * Sets the light sources Attenuation 332 * @returns {Object} The components of the light sources attenuation 333 */ 334 GLGE.Light.prototype.getAttenuation=function(constant,linear,quadratic){ 335 var attenuation={}; 336 attenuation.constant=this.constantAttenuation; 337 attenuation.linear=this.linearAttenuation; 338 attenuation.quadratic=this.quadraticAttenuation; 339 return attenuation; 340 } 341 /** 342 * Sets the light sources Attenuation 343 * @param {Number} constant The constant part of the attenuation 344 * @param {Number} linear The linear part of the attenuation 345 * @param {Number} quadratic The quadratic part of the attenuation 346 */ 347 GLGE.Light.prototype.setAttenuation=function(constant,linear,quadratic){ 348 this.constantAttenuation=constant; 349 this.linearAttenuation=linear; 350 this.quadraticAttenuation=quadratic; 351 return this; 352 } 353 /** 354 * Sets the light sources constant attenuation 355 * @param {Number} value The constant part of the attenuation 356 */ 357 GLGE.Light.prototype.setAttenuationConstant=function(value){ 358 this.constantAttenuation=value; 359 return this; 360 } 361 /** 362 * Sets the light sources linear attenuation 363 * @param {Number} value The linear part of the attenuation 364 */ 365 GLGE.Light.prototype.setAttenuationLinear=function(value){ 366 this.linearAttenuation=value; 367 return this; 368 } 369 /** 370 * Sets the light sources quadratic attenuation 371 * @param {Number} value The quadratic part of the attenuation 372 */ 373 GLGE.Light.prototype.setAttenuationQuadratic=function(value){ 374 this.quadraticAttenuation=value; 375 return this; 376 } 377 378 /** 379 * Sets the color of the light source 380 * @param {string} color The color of the light 381 */ 382 GLGE.Light.prototype.setColor=function(color){ 383 color=GLGE.colorParse(color); 384 this.color={r:color.r,g:color.g,b:color.b}; 385 return this; 386 } 387 /** 388 * Sets the red color of the light source 389 * @param {Number} value The new red level 0-1 390 */ 391 GLGE.Light.prototype.setColorR=function(value){ 392 this.color.r=value; 393 return this; 394 } 395 /** 396 * Sets the green color of the light source 397 * @param {Number} value The new green level 0-1 398 */ 399 GLGE.Light.prototype.setColorG=function(value){ 400 this.color.g=value; 401 return this; 402 } 403 /** 404 * Sets the blue color of the light source 405 * @param {Number} value The new blue level 0-1 406 */ 407 GLGE.Light.prototype.setColorB=function(value){ 408 this.color.b=value; 409 return this; 410 } 411 /** 412 * Gets the current color of the light source 413 * @return {[r,g,b]} The current position 414 */ 415 GLGE.Light.prototype.getColor=function(){ 416 return this.color; 417 } 418 /** 419 420 * Gets the type of the light 421 * @return {Number} The type of the light source eg GLGE.L_POINT 422 */ 423 GLGE.Light.prototype.getType=function(){ 424 return this.type; 425 } 426 /** 427 * Sets the type of the light 428 * @param {Number} type The type of the light source eg GLGE.L_POINT 429 */ 430 GLGE.Light.prototype.setType=function(type){ 431 this.type=type; 432 this.fireEvent("shaderupdate",{}); 433 return this; 434 } 435 436 /** 437 * Gets the softness of the spot shadow 438 * @return {Number} The type of the light source eg GLGE.L_POINT 439 */ 440 GLGE.Light.prototype.getSpotSoftness=function(){ 441 return this.spotSoftness; 442 } 443 /** 444 * Sets the softness of the spot shadow 445 * @param {Number} spotSoftness The type of the light source eg GLGE.L_POINT 446 */ 447 GLGE.Light.prototype.setSpotSoftness=function(spotSoftness){ 448 this.spotSoftness=+spotSoftness; 449 if(this.gl) this.createSoftPrograms(this.gl); 450 this.fireEvent("shaderupdate",{}); 451 return this; 452 } 453 454 /** 455 * Gets the spotlights blur distance in pixels 456 * @return {Number} The blur distance for spot lights 457 */ 458 GLGE.Light.prototype.getSpotSoftDistance=function(){ 459 return this.spotSoftnessDistance; 460 } 461 /** 462 * Sets the spotlights variance cutoff used to reduce light bleed 463 * @param {Number} spotSoftnessDistance the spotlights variance cutoff 464 */ 465 GLGE.Light.prototype.setSpotSoftDistance=function(spotSoftnessDistance){ 466 this.spotSoftnessDistance=+spotSoftnessDistance; 467 this.fireEvent("shaderupdate",{}); 468 return this; 469 } 470 471 472 GLGE.Light.prototype.enableLight=function(){ 473 if (this.type == GLGE.L_OFF && this.old_type !== undefined) { 474 this.setType(this.old_type); 475 delete this.old_type; 476 } 477 }; 478 479 GLGE.Light.prototype.disableLight=function(){ 480 if (this.type != GLGE.L_OFF) { 481 this.old_type=this.type; 482 this.setType(GLGE.L_OFF); 483 } 484 }; 485 486 /** 487 * init for the rendering 488 * @private 489 */ 490 GLGE.Light.prototype.GLInit=function(gl){ 491 this.gl=gl; 492 if((this.type==GLGE.L_SPOT || this.type==GLGE.L_DIR) && !this.texture){ 493 this.createSpotBuffer(gl); 494 this.createSoftBuffer(gl); 495 this.createSoftPrograms(gl); 496 } 497 } 498 /** 499 * Sets up the WebGL needed to render the depth map for this light source. Only used for spot lights which produce shadows 500 * @private 501 */ 502 GLGE.Light.prototype.createSpotBuffer=function(gl){ 503 this.frameBuffer = gl.createFramebuffer(); 504 this.renderBuffer = gl.createRenderbuffer(); 505 this.texture = gl.createTexture(); 506 gl.bindTexture(gl.TEXTURE_2D, this.texture); 507 508 try { 509 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.bufferWidth, this.bufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 510 } catch (e) { 511 GLGE.error("incompatible texture creation method"); 512 var width=parseFloat(this.bufferWidth); 513 var height=parseFloat(this.bufferHeight); 514 var tex = new Uint8Array(width * height * 4); 515 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, tex); 516 } 517 518 gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); 519 gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); 520 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.bufferWidth, this.bufferHeight); 521 522 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); 523 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); 524 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 525 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 526 gl.bindTexture(gl.TEXTURE_2D, null); 527 } 528 529 /** 530 * Sets up the buffers needed for the gaussian blured shadow buffer 531 * @private 532 */ 533 GLGE.Light.prototype.createSoftBuffer=function(gl){ 534 this.frameBufferSf = gl.createFramebuffer(); 535 this.renderBufferSf = gl.createRenderbuffer(); 536 this.textureSf = gl.createTexture(); 537 gl.bindTexture(gl.TEXTURE_2D, this.textureSf); 538 539 try { 540 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.bufferWidth, this.bufferHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 541 } catch (e) { 542 GLGE.error("incompatible texture creation method"); 543 var width=parseFloat(this.bufferWidth); 544 var height=parseFloat(this.bufferHeight); 545 var tex = new Uint8Array(width * height * 4); 546 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, tex); 547 } 548 549 gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBufferSf); 550 gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBufferSf); 551 gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.bufferWidth, this.bufferHeight); 552 553 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.textureSf, 0); 554 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.renderBufferSf); 555 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 556 gl.bindRenderbuffer(gl.RENDERBUFFER, null); 557 gl.bindTexture(gl.TEXTURE_2D, null); 558 559 //create the vertex positions 560 if(!this.posBuffer) this.posBuffer = gl.createBuffer(); 561 gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer); 562 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1,1,0,-1,1,0,-1,-1,0,1,-1,0]), gl.STATIC_DRAW); 563 this.posBuffer.itemSize = 3; 564 this.posBuffer.numItems = 4; 565 //create the vertex uv coords 566 if(!this.uvBuffer) this.uvBuffer = gl.createBuffer(); 567 gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); 568 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1,1,0,1,0,0,1,0]), gl.STATIC_DRAW); 569 this.uvBuffer.itemSize = 2; 570 this.uvBuffer.numItems = 4; 571 //create the faces 572 if(!this.GLfaces) this.GLfaces = gl.createBuffer(); 573 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces); 574 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([2,1,0,0,3,2]), gl.STATIC_DRAW); 575 this.GLfaces.itemSize = 1; 576 this.GLfaces.numItems = 6; 577 } 578 579 /** 580 * Sets up the programs require to do the soft shadows 581 * @private 582 */ 583 GLGE.Light.prototype.createSoftPrograms=function(gl){ 584 if(this.GLShaderProgram) gl.deleteProgram(this.GLShaderProgram); 585 586 var vertexStr=""; 587 vertexStr+="attribute vec3 position;\n"; 588 vertexStr+="attribute vec2 uvcoord;\n"; 589 vertexStr+="varying vec2 texCoord;\n"; 590 vertexStr+="void main(void){\n"; 591 vertexStr+="texCoord=uvcoord;\n"; 592 vertexStr+="gl_Position = vec4(position,1.0);\n"; 593 vertexStr+="}\n"; 594 595 var SAMPLES=this.spotSoftness; 596 597 var fragStr="precision mediump float;\n"; 598 fragStr=fragStr+"uniform sampler2D TEXTURE;\n"; 599 fragStr=fragStr+"varying vec2 texCoord;\n"; 600 fragStr=fragStr+"uniform bool xpass;\n"; 601 fragStr=fragStr+"float blurSize = "+(1/this.bufferWidth).toFixed(10)+";\n"; 602 fragStr=fragStr+"float unpack(sampler2D TEX, vec2 co){;"; 603 fragStr=fragStr+"float value = dot(texture2D(TEX, co), vec4(0.000000059604644775390625,0.0000152587890625,0.00390625,1.0));"; 604 fragStr=fragStr+"return value;"; 605 fragStr=fragStr+"}"; 606 fragStr=fragStr+"vec2 unpack2(sampler2D TEX, vec2 co){;"; 607 fragStr=fragStr+"vec4 color = texture2D(TEX, co);"; 608 fragStr=fragStr+"float value1 = dot(color.rg, vec2(0.00390625,1.0));"; 609 fragStr=fragStr+"float value2 = dot(color.ba, vec2(0.00390625,1.0));"; 610 fragStr=fragStr+"return vec2(value1,value2);"; 611 fragStr=fragStr+"}"; 612 fragStr=fragStr+"vec4 pack(float value){;"; 613 fragStr=fragStr+"vec4 rgba=fract(value * vec4(16777216.0, 65536.0, 256.0, 1.0));\n"; 614 fragStr=fragStr+"return rgba-rgba.rrgb*vec4(0.0,0.00390625,0.00390625,0.00390625);"; 615 fragStr=fragStr+"}"; 616 fragStr=fragStr+"vec2 pack2(float value){;"; 617 fragStr=fragStr+"vec2 rg=fract(value * vec2(256.0, 1.0));\n"; 618 fragStr=fragStr+"return rg-rg.rr*vec2(0.0,0.00390625);"; 619 fragStr=fragStr+"}"; 620 fragStr=fragStr+"void main(void){\n"; 621 fragStr=fragStr+"float value = 0.0;"; 622 fragStr=fragStr+"vec2 value2;"; 623 fragStr=fragStr+"float mean = 0.0;"; 624 fragStr=fragStr+"float mean2 = 0.0;"; 625 fragStr=fragStr+"float color = 0.0;"; 626 fragStr=fragStr+"if(xpass){"; 627 for(var i=-SAMPLES;i<SAMPLES;i++){ 628 fragStr=fragStr+"value = unpack(TEXTURE, vec2(texCoord.x - "+(i+0.5).toFixed(1)+"*blurSize, texCoord.y));"; 629 fragStr=fragStr+"mean += value;"; 630 fragStr=fragStr+"mean2 += value*value;"; 631 } 632 fragStr=fragStr+"gl_FragColor = vec4(pack2(pow(mean2/"+(SAMPLES*2).toFixed(2)+",0.5)),pack2(mean/"+(SAMPLES*2).toFixed(2)+"));\n"; 633 fragStr=fragStr+"}else{"; 634 for(var i=-SAMPLES;i<SAMPLES;i++){ 635 fragStr=fragStr+"value2 = unpack2(TEXTURE, vec2(texCoord.x, texCoord.y - "+(i+0.5).toFixed(1)+"*blurSize));"; 636 fragStr=fragStr+"mean += value2.g;"; 637 fragStr=fragStr+"mean2 += pow(value2.r,2.0);"; 638 } 639 fragStr=fragStr+"gl_FragColor = vec4(pack2(pow(mean2/"+(SAMPLES*2).toFixed(2)+",0.5)),pack2(mean/"+(SAMPLES*2).toFixed(2)+"));\n"; 640 fragStr=fragStr+"}"; 641 642 fragStr=fragStr+"}\n"; 643 644 this.GLFragmentShader=gl.createShader(gl.FRAGMENT_SHADER); 645 this.GLVertexShader=gl.createShader(gl.VERTEX_SHADER); 646 647 gl.shaderSource(this.GLFragmentShader, fragStr); 648 gl.compileShader(this.GLFragmentShader); 649 if (!gl.getShaderParameter(this.GLFragmentShader, gl.COMPILE_STATUS)) { 650 GLGE.error(gl.getShaderInfoLog(this.GLFragmentShader)); 651 return; 652 } 653 654 gl.shaderSource(this.GLVertexShader, vertexStr); 655 gl.compileShader(this.GLVertexShader); 656 if (!gl.getShaderParameter(this.GLVertexShader, gl.COMPILE_STATUS)) { 657 GLGE.error(gl.getShaderInfoLog(this.GLVertexShader)); 658 return; 659 } 660 661 this.GLShaderProgram = gl.createProgram(); 662 gl.attachShader(this.GLShaderProgram, this.GLVertexShader); 663 gl.attachShader(this.GLShaderProgram, this.GLFragmentShader); 664 gl.linkProgram(this.GLShaderProgram); 665 } 666 667 /** 668 * Renders the blured shadow 669 * @private 670 */ 671 GLGE.Light.prototype.GLRenderSoft=function(gl){ 672 if(this.spotSoftness==0) return; 673 674 if(!this.gl){ 675 this.GLInit(gl); 676 } 677 678 gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBufferSf); 679 680 if(gl.program!=this.GLShaderProgram){ 681 gl.useProgram(this.GLShaderProgram); 682 gl.program=this.GLShaderProgram; 683 } 684 685 var attribslot; 686 for(var i=0; i<8; i++) gl.disableVertexAttribArray(i); 687 attribslot=GLGE.getAttribLocation(gl,this.GLShaderProgram, "position"); 688 689 gl.bindBuffer(gl.ARRAY_BUFFER, this.posBuffer); 690 gl.enableVertexAttribArray(attribslot); 691 gl.vertexAttribPointer(attribslot, this.posBuffer.itemSize, gl.FLOAT, false, 0, 0); 692 693 attribslot=GLGE.getAttribLocation(gl,this.GLShaderProgram, "uvcoord"); 694 gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); 695 gl.enableVertexAttribArray(attribslot); 696 gl.vertexAttribPointer(attribslot, this.uvBuffer.itemSize, gl.FLOAT, false, 0, 0); 697 698 gl.activeTexture(gl["TEXTURE0"]); 699 gl.bindTexture(gl.TEXTURE_2D, this.texture); 700 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 701 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 702 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 703 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 704 GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "TEXTURE"),0); 705 GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "xpass"),1); 706 707 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces); 708 709 gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); 710 gl.drawElements(gl.TRIANGLES, this.GLfaces.numItems, gl.UNSIGNED_SHORT, 0); 711 712 //gl.disable(gl.BLEND); 713 gl.activeTexture(gl["TEXTURE0"]); 714 gl.bindTexture(gl.TEXTURE_2D, this.textureSf); 715 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 716 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 717 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 718 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 719 GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "TEXTURE"),0); 720 GLGE.setUniform(gl,"1i",GLGE.getUniformLocation(gl,this.GLShaderProgram, "xpass"),0); 721 722 gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); 723 724 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.GLfaces); 725 gl.drawElements(gl.TRIANGLES, this.GLfaces.numItems, gl.UNSIGNED_SHORT, 0); 726 727 728 gl.bindTexture(gl.TEXTURE_2D, null); 729 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 730 } 731 732 733 })(GLGE); 734