From 98a32b3b51cce4173c580abbda8399cce8e51789 Mon Sep 17 00:00:00 2001 From: Tarek Sherif Date: Thu, 4 Jun 2015 13:49:50 -0400 Subject: [PATCH 01/14] Removed precision directive from vertex shader --- api/latest/scenejs.js | 7 +------ src/core/display/programSourceFactory.js | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/api/latest/scenejs.js b/api/latest/scenejs.js index d75f22de..0aeda825 100644 --- a/api/latest/scenejs.js +++ b/api/latest/scenejs.js @@ -15589,9 +15589,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._composePickingVertexShader = function (states) { var morphing = !!states.morphGeometry.targets; var src = [ - - "precision mediump float;", - "attribute vec3 SCENEJS_aVertex;", "uniform mat4 SCENEJS_uMMatrix;", "uniform mat4 SCENEJS_uVMatrix;", @@ -15756,9 +15753,7 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; var morphing = !!states.morphGeometry.targets; - var src = [ - "precision mediump float;" - ]; + var src = []; src.push("uniform mat4 SCENEJS_uMMatrix;"); // Model matrix src.push("uniform mat4 SCENEJS_uVMatrix;"); // View matrix diff --git a/src/core/display/programSourceFactory.js b/src/core/display/programSourceFactory.js index 858ff303..82f5fff5 100644 --- a/src/core/display/programSourceFactory.js +++ b/src/core/display/programSourceFactory.js @@ -43,9 +43,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._composePickingVertexShader = function (states) { var morphing = !!states.morphGeometry.targets; var src = [ - - "precision mediump float;", - "attribute vec3 SCENEJS_aVertex;", "uniform mat4 SCENEJS_uMMatrix;", "uniform mat4 SCENEJS_uVMatrix;", @@ -210,9 +207,7 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; var morphing = !!states.morphGeometry.targets; - var src = [ - "precision mediump float;" - ]; + var src = []; src.push("uniform mat4 SCENEJS_uMMatrix;"); // Model matrix src.push("uniform mat4 SCENEJS_uVMatrix;"); // View matrix From b00f3ace0ba3a4360b721fbfe2f61a90b10487c1 Mon Sep 17 00:00:00 2001 From: Tarek Sherif Date: Thu, 4 Jun 2015 17:09:15 -0400 Subject: [PATCH 02/14] Set fragment shader float precision to max available. --- api/latest/scenejs.js | 25 +++++++++++++++++++++--- src/core/display/programSourceFactory.js | 25 +++++++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/api/latest/scenejs.js b/api/latest/scenejs.js index 0aeda825..c3f26640 100644 --- a/api/latest/scenejs.js +++ b/api/latest/scenejs.js @@ -15552,7 +15552,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._sourceCache = {}; // Source codes are shared across all scenes - /** * Get sourcecode for a program to render the given states */ @@ -15631,8 +15630,10 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = [ - "precision mediump float;" + "precision " + floatPrecision + " float;" ]; src.push("varying vec4 SCENEJS_vWorldVertex;"); @@ -16050,9 +16051,11 @@ var SceneJS_ProgramSourceFactory = new (function () { var tangents = this._hasTangents(states); var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = ["\n"]; - src.push("precision mediump float;"); + src.push("precision " + floatPrecision + " float;"); if (clipping) { @@ -16447,6 +16450,22 @@ var SceneJS_ProgramSourceFactory = new (function () { return false; } + function getFSFloatPrecision(gl) { + if (!gl.getShaderPrecisionFormat) { + return "mediump"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) { + return "highp"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) { + return "mediump"; + } + + return "lowp"; + } + })();/** * @class Source code for pick and draw shader programs, to be compiled into one or more {@link SceneJS_Program}s * @private diff --git a/src/core/display/programSourceFactory.js b/src/core/display/programSourceFactory.js index 82f5fff5..85786fb3 100644 --- a/src/core/display/programSourceFactory.js +++ b/src/core/display/programSourceFactory.js @@ -6,7 +6,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._sourceCache = {}; // Source codes are shared across all scenes - /** * Get sourcecode for a program to render the given states */ @@ -85,8 +84,10 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = [ - "precision mediump float;" + "precision " + floatPrecision + " float;" ]; src.push("varying vec4 SCENEJS_vWorldVertex;"); @@ -504,9 +505,11 @@ var SceneJS_ProgramSourceFactory = new (function () { var tangents = this._hasTangents(states); var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = ["\n"]; - src.push("precision mediump float;"); + src.push("precision " + floatPrecision + " float;"); if (clipping) { @@ -901,4 +904,20 @@ var SceneJS_ProgramSourceFactory = new (function () { return false; } + function getFSFloatPrecision(gl) { + if (!gl.getShaderPrecisionFormat) { + return "mediump"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) { + return "highp"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) { + return "mediump"; + } + + return "lowp"; + } + })(); \ No newline at end of file From e5679311c8593ad6c4f5df20beac319a5afe916a Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 20:28:57 +0200 Subject: [PATCH 03/14] Better uniform caching --- src/core/display/chunks/cameraChunk.js | 24 ++--- src/core/display/chunks/clipsChunk.js | 18 ++-- src/core/display/chunks/drawChunk.js | 11 ++- src/core/display/chunks/flagsChunk.js | 14 +-- src/core/display/chunks/geometryChunk.js | 8 +- src/core/display/chunks/lightsChunk.js | 22 ++--- src/core/display/chunks/lookAtChunk.js | 16 +-- src/core/display/chunks/materialChunk.js | 49 ++++----- src/core/display/chunks/nameChunk.js | 8 +- src/core/display/chunks/programChunk.js | 18 ++-- src/core/display/chunks/xformChunk.js | 18 ++-- src/core/display/display.js | 1 - src/core/display/program.js | 5 - src/core/webgl/uniform.js | 121 ++++++++++++++++++----- 14 files changed, 199 insertions(+), 134 deletions(-) diff --git a/src/core/display/chunks/cameraChunk.js b/src/core/display/chunks/cameraChunk.js index b6c54623..b4127306 100644 --- a/src/core/display/chunks/cameraChunk.js +++ b/src/core/display/chunks/cameraChunk.js @@ -4,13 +4,13 @@ SceneJS_ChunkFactory.createChunkType({ build : function() { - this._uPMatrixDraw = this.program.draw.getUniformLocation("SCENEJS_uPMatrix"); - this._uZNearDraw = this.program.draw.getUniformLocation("SCENEJS_uZNear"); - this._uZFarDraw = this.program.draw.getUniformLocation("SCENEJS_uZFar"); + this._uPMatrixDraw = this.program.draw.getUniform("SCENEJS_uPMatrix"); + this._uZNearDraw = this.program.draw.getUniform("SCENEJS_uZNear"); + this._uZFarDraw = this.program.draw.getUniform("SCENEJS_uZFar"); - this._uPMatrixPick = this.program.pick.getUniformLocation("SCENEJS_uPMatrix"); - this._uZNearPick = this.program.pick.getUniformLocation("SCENEJS_uZNear"); - this._uZFarPick = this.program.pick.getUniformLocation("SCENEJS_uZFar"); + this._uPMatrixPick = this.program.pick.getUniform("SCENEJS_uPMatrix"); + this._uZNearPick = this.program.pick.getUniform("SCENEJS_uZNear"); + this._uZFarPick = this.program.pick.getUniform("SCENEJS_uZFar"); }, draw : function(frameCtx) { @@ -22,15 +22,15 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uPMatrixDraw) { - gl.uniformMatrix4fv(this._uPMatrixDraw, gl.FALSE, this.core.mat); + this._uPMatrixDraw.setValue(this.core.mat); } if (this._uZNearDraw) { - gl.uniform1f(this._uZNearDraw, this.core.optics.near); + this._uZNearDraw.setValue(this.core.optics.near); } if (this._uZFarDraw) { - gl.uniform1f(this._uZFarDraw, this.core.optics.far); + this._uZFarDraw.setValue(this.core.optics.far); } frameCtx.cameraMat = this.core.mat; // Query only in draw pass @@ -46,17 +46,17 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uPMatrixPick) { - gl.uniformMatrix4fv(this._uPMatrixPick, gl.FALSE, this.core.mat); + this._uPMatrixPick.setValue(this.core.mat); } if (frameCtx.rayPick) { // Z-pick pass: feed near and far clip planes into shader if (this._uZNearPick) { - gl.uniform1f(this._uZNearPick, this.core.optics.near); + this._uZNearPick.setValue(this.core.optics.near); } if (this._uZFarPick) { - gl.uniform1f(this._uZFarPick, this.core.optics.far); + this._uZFarPick.setValue(this.core.optics.far); } } diff --git a/src/core/display/chunks/clipsChunk.js b/src/core/display/chunks/clipsChunk.js index 7cd8c084..c051d708 100644 --- a/src/core/display/chunks/clipsChunk.js +++ b/src/core/display/chunks/clipsChunk.js @@ -13,8 +13,8 @@ SceneJS_ChunkFactory.createChunkType({ for (var i = 0, len = this.core.clips.length; i < len; i++) { this._draw[i] = { - uClipMode :draw.getUniformLocation("SCENEJS_uClipMode" + i), - uClipNormalAndDist: draw.getUniformLocation("SCENEJS_uClipNormalAndDist" + i) + uClipMode :draw.getUniform("SCENEJS_uClipMode" + i), + uClipNormalAndDist: draw.getUniform("SCENEJS_uClipNormalAndDist" + i) }; } @@ -24,8 +24,8 @@ SceneJS_ChunkFactory.createChunkType({ for (var i = 0, len = this.core.clips.length; i < len; i++) { this._pick[i] = { - uClipMode :pick.getUniformLocation("SCENEJS_uClipMode" + i), - uClipNormalAndDist: pick.getUniformLocation("SCENEJS_uClipNormalAndDist" + i) + uClipMode :pick.getUniform("SCENEJS_uClipMode" + i), + uClipNormalAndDist: pick.getUniform("SCENEJS_uClipNormalAndDist" + i) }; } }, @@ -56,16 +56,16 @@ SceneJS_ChunkFactory.createChunkType({ if (clip.mode == "inside") { - gl.uniform1f(mode, 2); - gl.uniform4fv(normalAndDist, clip.normalAndDist); + mode.setValue(2); + normalAndDist.setValue(clip.normalAndDist); } else if (clip.mode == "outside") { - gl.uniform1f(mode, 1); - gl.uniform4fv(normalAndDist, clip.normalAndDist); + mode.setValue(1); + normalAndDist.setValue(clip.normalAndDist); } else { // disabled - gl.uniform1f(mode, 0); + mode.setValue(0); } } } diff --git a/src/core/display/chunks/drawChunk.js b/src/core/display/chunks/drawChunk.js index ae03679b..92484c7f 100644 --- a/src/core/display/chunks/drawChunk.js +++ b/src/core/display/chunks/drawChunk.js @@ -15,15 +15,20 @@ SceneJS_ChunkFactory.createChunkType({ unique:true, build:function () { - this._depthModeDraw = this.program.draw.getUniformLocation("SCENEJS_uDepthMode"); - this._depthModePick = this.program.pick.getUniformLocation("SCENEJS_uDepthMode"); + this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); + this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); }, drawAndPick:function (frameCtx) { + var gl = this.program.gl; + var indexType = this.program.UINT_INDEX_ENABLED ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT; - gl.uniform1i(frameCtx.pick ? this._depthModePick : this._depthModeDraw, frameCtx.depthMode); + + (frameCtx.pick ? this._depthModePick : this._depthModeDraw).setValue(frameCtx.depthMode); + gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, indexType, 0); + //frameCtx.textureUnit = 0; } }); diff --git a/src/core/display/chunks/flagsChunk.js b/src/core/display/chunks/flagsChunk.js index dd0350c4..eca83cd2 100644 --- a/src/core/display/chunks/flagsChunk.js +++ b/src/core/display/chunks/flagsChunk.js @@ -9,11 +9,11 @@ SceneJS_ChunkFactory.createChunkType({ var draw = this.program.draw; - this._uClippingDraw = draw.getUniformLocation("SCENEJS_uClipping"); + this._uClippingDraw = draw.getUniform("SCENEJS_uClipping"); var pick = this.program.pick; - this._uClippingPick = pick.getUniformLocation("SCENEJS_uClipping"); + this._uClippingPick = pick.getUniform("SCENEJS_uClipping"); }, drawAndPick: function (frameCtx) { @@ -66,13 +66,13 @@ SceneJS_ChunkFactory.createChunkType({ } if (frameCtx.pick) { - gl.uniform1i(this._uClippingPick, this.core.clipping); + if (this._uClippingPick) { + this._uClippingPick.setValue(this.core.clipping); + } } else { - var drawUniforms = (this.core.clipping ? 1 : 0); - if (this.program.drawUniformFlags != drawUniforms) { - gl.uniform1i(this._uClippingDraw, this.core.clipping); - this.program.drawUniformFlags = drawUniforms; + if (this._uClippingDraw) { + this._uClippingDraw.setValue(this.core.clipping); } } } diff --git a/src/core/display/chunks/geometryChunk.js b/src/core/display/chunks/geometryChunk.js index f091031a..25cfaa00 100644 --- a/src/core/display/chunks/geometryChunk.js +++ b/src/core/display/chunks/geometryChunk.js @@ -18,13 +18,13 @@ SceneJS_ChunkFactory.createChunkType({ this._aMorphVertexDraw = draw.getAttribute("SCENEJS_aMorphVertex"); this._aMorphNormalDraw = draw.getAttribute("SCENEJS_aMorphNormal"); - this._uMorphFactorDraw = draw.getUniformLocation("SCENEJS_uMorphFactor"); + this._uMorphFactorDraw = draw.getUniform("SCENEJS_uMorphFactor"); var pick = this.program.pick; this._aVertexPick = pick.getAttribute("SCENEJS_aVertex"); this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); - this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); + this._uMorphFactorPick = pick.getUniform("SCENEJS_uMorphFactor"); this.VAO = null; this.VAOMorphKey1 = 0; @@ -80,7 +80,7 @@ SceneJS_ChunkFactory.createChunkType({ setDrawMorphFactor:function () { if (this._uMorphFactorDraw) { - this.program.gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor + this._uMorphFactorDraw.setValue*(this.core.factor); // Bind LERP factor } }, @@ -176,7 +176,7 @@ SceneJS_ChunkFactory.createChunkType({ } if (this._uMorphFactorPick) { - this.program.gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor + this._uMorphFactorPick.setValue(this.core.factor); // Bind LERP factor } }, diff --git a/src/core/display/chunks/lightsChunk.js b/src/core/display/chunks/lightsChunk.js index f7851aea..cac96e98 100644 --- a/src/core/display/chunks/lightsChunk.js +++ b/src/core/display/chunks/lightsChunk.js @@ -23,20 +23,20 @@ SceneJS_ChunkFactory.createChunkType({ switch (lights[i].mode) { case "ambient": - this._uAmbientColor[i] = (program.draw.getUniformLocation("SCENEJS_uAmbientColor")); + this._uAmbientColor[i] = (program.draw.getUniform("SCENEJS_uAmbientColor")); break; case "dir": - this._uLightColor[i] = program.draw.getUniformLocation("SCENEJS_uLightColor" + i); + this._uLightColor[i] = program.draw.getUniform("SCENEJS_uLightColor" + i); this._uLightPos[i] = null; - this._uLightDir[i] = program.draw.getUniformLocation("SCENEJS_uLightDir" + i); + this._uLightDir[i] = program.draw.getUniform("SCENEJS_uLightDir" + i); break; case "point": - this._uLightColor[i] = program.draw.getUniformLocation("SCENEJS_uLightColor" + i); - this._uLightPos[i] = program.draw.getUniformLocation("SCENEJS_uLightPos" + i); + this._uLightColor[i] = program.draw.getUniform("SCENEJS_uLightColor" + i); + this._uLightPos[i] = program.draw.getUniform("SCENEJS_uLightPos" + i); this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.draw.getUniformLocation("SCENEJS_uLightAttenuation" + i); + this._uLightAttenuation[i] = program.draw.getUniform("SCENEJS_uLightAttenuation" + i); break; } } @@ -58,24 +58,24 @@ SceneJS_ChunkFactory.createChunkType({ light = lights[i]; if (this._uAmbientColor[i]) { - gl.uniform3fv(this._uAmbientColor[i], light.color); + this._uAmbientColor[i].setValue(light.color); } else { if (this._uLightColor[i]) { - gl.uniform3fv(this._uLightColor[i], light.color); + this._uLightColor[i].setValue(light.color); } if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); + this._uLightPos[i].setValue(light.pos); if (this._uLightAttenuation[i]) { - gl.uniform3fv(this._uLightAttenuation[i], light.attenuation); + this._uLightAttenuation[i].setValue(light.attenuation); } } if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); + this._uLightDir[i].setValue(light.dir); } } } diff --git a/src/core/display/chunks/lookAtChunk.js b/src/core/display/chunks/lookAtChunk.js index 91c13adf..be5ffae2 100644 --- a/src/core/display/chunks/lookAtChunk.js +++ b/src/core/display/chunks/lookAtChunk.js @@ -7,11 +7,11 @@ SceneJS_ChunkFactory.createChunkType({ build : function() { - this._uvMatrixDraw = this.program.draw.getUniformLocation("SCENEJS_uVMatrix"); - this._uVNMatrixDraw = this.program.draw.getUniformLocation("SCENEJS_uVNMatrix"); - this._uWorldEyeDraw = this.program.draw.getUniformLocation("SCENEJS_uWorldEye"); + this._uvMatrixDraw = this.program.draw.getUniform("SCENEJS_uVMatrix"); + this._uVNMatrixDraw = this.program.draw.getUniform("SCENEJS_uVNMatrix"); + this._uWorldEyeDraw = this.program.draw.getUniform("SCENEJS_uWorldEye"); - this._uvMatrixPick = this.program.pick.getUniformLocation("SCENEJS_uVMatrix"); + this._uvMatrixPick = this.program.pick.getUniform("SCENEJS_uVMatrix"); }, draw : function(frameCtx) { @@ -23,15 +23,15 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uvMatrixDraw) { - gl.uniformMatrix4fv(this._uvMatrixDraw, gl.FALSE, this.core.mat); + this._uvMatrixDraw.setValue(this.core.mat); } if (this._uVNMatrixDraw) { - gl.uniformMatrix4fv(this._uVNMatrixDraw, gl.FALSE, this.core.normalMat); + this._uVNMatrixDraw.setValue(this.core.normalMat); } if (this._uWorldEyeDraw) { - gl.uniform3fv(this._uWorldEyeDraw, this.core.lookAt.eye); + this._uWorldEyeDraw.setValue(this.core.lookAt.eye); } frameCtx.viewMat = this.core.mat; @@ -42,7 +42,7 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uvMatrixPick) { - gl.uniformMatrix4fv(this._uvMatrixPick, gl.FALSE, this.core.mat); + this._uvMatrixPick.setValue(this.core.mat); } frameCtx.viewMat = this.core.mat; diff --git a/src/core/display/chunks/materialChunk.js b/src/core/display/chunks/materialChunk.js index 791e7f0d..404c8f71 100644 --- a/src/core/display/chunks/materialChunk.js +++ b/src/core/display/chunks/materialChunk.js @@ -5,55 +5,44 @@ SceneJS_ChunkFactory.createChunkType({ type: "material", - build : function() { + build: function () { var draw = this.program.draw; - this._uMaterialBaseColor = draw.getUniformLocation("SCENEJS_uMaterialColor"); - this._uMaterialSpecularColor = draw.getUniformLocation("SCENEJS_uMaterialSpecularColor"); - this._uMaterialSpecular = draw.getUniformLocation("SCENEJS_uMaterialSpecular"); - this._uMaterialShine = draw.getUniformLocation("SCENEJS_uMaterialShine"); - this._uMaterialEmit = draw.getUniformLocation("SCENEJS_uMaterialEmit"); - this._uMaterialAlpha = draw.getUniformLocation("SCENEJS_uMaterialAlpha"); + this._uMaterialBaseColor = draw.getUniform("SCENEJS_uMaterialColor"); + this._uMaterialSpecularColor = draw.getUniform("SCENEJS_uMaterialSpecularColor"); + this._uMaterialSpecular = draw.getUniform("SCENEJS_uMaterialSpecular"); + this._uMaterialShine = draw.getUniform("SCENEJS_uMaterialShine"); + this._uMaterialEmit = draw.getUniform("SCENEJS_uMaterialEmit"); + this._uMaterialAlpha = draw.getUniform("SCENEJS_uMaterialAlpha"); }, - draw : function() { + draw: function () { var gl = this.program.gl; - var materialSettings = this.program.draw.materialSettings; if (this._uMaterialBaseColor) { - gl.uniform3fv(this._uMaterialBaseColor, this.core.baseColor); + this._uMaterialBaseColor.setValue(this.core.baseColor); } - if (this._uMaterialSpecularColor && - (materialSettings.specularColor[0] != this.core.specularColor[0] || - materialSettings.specularColor[1] != this.core.specularColor[1] || - materialSettings.specularColor[2] != this.core.specularColor[2])) { - gl.uniform3fv(this._uMaterialSpecularColor, this.core.specularColor); - materialSettings.specularColor[0] = this.core.specularColor[0]; - materialSettings.specularColor[1] = this.core.specularColor[1]; - materialSettings.specularColor[2] = this.core.specularColor[2]; + if (this._uMaterialSpecularColor) { + this._uMaterialSpecularColor.setValue(this.core.specularColor); } - if (this._uMaterialSpecular && materialSettings.specular != this.core.specular) { - gl.uniform1f(this._uMaterialSpecular, this.core.specular); - materialSettings.specular = this.core.specular; + if (this._uMaterialSpecular) { + this._uMaterialSpecular.setValue(this.core.specular); } - if (this._uMaterialShine && materialSettings.shine != this.core.shine) { - gl.uniform1f(this._uMaterialShine, this.core.shine); - materialSettings.shine = this.core.shine; + if (this._uMaterialShine) { + this._uMaterialShine.setValue(this.core.shine); } - if (this._uMaterialEmit && materialSettings.emit != this.core.emit) { - gl.uniform1f(this._uMaterialEmit, this.core.emit); - materialSettings.emit = this.core.emit; + if (this._uMaterialEmit) { + this._uMaterialEmit.setValue(this.core.emit); } - if (this._uMaterialAlpha && materialSettings.alpha != this.core.alpha) { - gl.uniform1f(this._uMaterialAlpha, this.core.alpha); - materialSettings.alpha = this.core.alpha; + if (this._uMaterialAlpha) { + this._uMaterialAlpha.setValue(this.core.alpha); } } }); diff --git a/src/core/display/chunks/nameChunk.js b/src/core/display/chunks/nameChunk.js index a3bd7b83..18cdc652 100644 --- a/src/core/display/chunks/nameChunk.js +++ b/src/core/display/chunks/nameChunk.js @@ -5,11 +5,11 @@ SceneJS_ChunkFactory.createChunkType({ type: "name", - build : function() { - this._uPickColor = this.program.pick.getUniformLocation("SCENEJS_uPickColor"); + build: function () { + this._uPickColor = this.program.pick.getUniform("SCENEJS_uPickColor"); }, - pick : function(frameCtx) { + pick: function (frameCtx) { if (this._uPickColor && this.core.name) { @@ -19,7 +19,7 @@ SceneJS_ChunkFactory.createChunkType({ var g = frameCtx.pickIndex >> 8 & 0xFF; var r = frameCtx.pickIndex & 0xFF; - this.program.gl.uniform3fv(this._uPickColor, [r / 255, g / 255, b / 255]); + this._uPickColor.setValue([r / 255, g / 255, b / 255]); } } }); \ No newline at end of file diff --git a/src/core/display/chunks/programChunk.js b/src/core/display/chunks/programChunk.js index dbbac5cf..c1085044 100644 --- a/src/core/display/chunks/programChunk.js +++ b/src/core/display/chunks/programChunk.js @@ -5,9 +5,9 @@ SceneJS_ChunkFactory.createChunkType({ build : function() { // Note that "program" chunks are always after "renderTarget" chunks - this._depthModeDraw = this.program.draw.getUniformLocation("SCENEJS_uDepthMode"); - this._depthModePick = this.program.pick.getUniformLocation("SCENEJS_uDepthMode"); - this._rayPickMode = this.program.pick.getUniformLocation("SCENEJS_uRayPickMode"); + this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); + this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); + this._rayPickMode = this.program.pick.getUniform("SCENEJS_uRayPickMode"); }, draw : function(frameCtx) { @@ -15,7 +15,9 @@ SceneJS_ChunkFactory.createChunkType({ drawProgram.bind(); frameCtx.textureUnit = 0; var gl = this.program.gl; - gl.uniform1i(this._depthModeDraw, frameCtx.depthMode); + if (this._depthModeDraw) { + this._depthModeDraw.setValue(frameCtx.depthMode); + } if (!frameCtx.VAO) { for (var i = 0; i < 10; i++) { gl.disableVertexAttribArray(i); @@ -29,8 +31,12 @@ SceneJS_ChunkFactory.createChunkType({ var pickProgram = this.program.pick; pickProgram.bind(); var gl = this.program.gl; - gl.uniform1i(this._rayPickMode, frameCtx.rayPick); - gl.uniform1i(this._depthModePick, frameCtx.depthMode); + if (this._rayPickMode) { + this._rayPickMode.setValue(frameCtx.rayPick); + } + if (this._depthModePick) { + this._depthModePick.setValue(frameCtx.depthMode); + } frameCtx.textureUnit = 0; for (var i = 0; i < 10; i++) { gl.disableVertexAttribArray(i); diff --git a/src/core/display/chunks/xformChunk.js b/src/core/display/chunks/xformChunk.js index 529ab5a5..08e135f5 100644 --- a/src/core/display/chunks/xformChunk.js +++ b/src/core/display/chunks/xformChunk.js @@ -2,19 +2,19 @@ SceneJS_ChunkFactory.createChunkType({ type: "xform", - build : function() { + build: function () { var draw = this.program.draw; - this._uMatLocationDraw = draw.getUniformLocation("SCENEJS_uMMatrix"); - this._uNormalMatLocationDraw = draw.getUniformLocation("SCENEJS_uMNMatrix"); + this._uMatLocationDraw = draw.getUniform("SCENEJS_uMMatrix"); + this._uNormalMatLocationDraw = draw.getUniform("SCENEJS_uMNMatrix"); var pick = this.program.pick; - this._uMatLocationPick = pick.getUniformLocation("SCENEJS_uMMatrix"); + this._uMatLocationPick = pick.getUniform("SCENEJS_uMMatrix"); }, - draw : function(frameCtx) { + draw: function (frameCtx) { /* Rebuild core's matrix from matrices at cores on path up to root */ @@ -25,17 +25,17 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uMatLocationDraw) { - gl.uniformMatrix4fv(this._uMatLocationDraw, gl.FALSE, this.core.mat); + this._uMatLocationDraw.setValue(this.core.mat); } if (this._uNormalMatLocationDraw) { - gl.uniformMatrix4fv(this._uNormalMatLocationDraw, gl.FALSE, this.core.normalMat); + this._uNormalMatLocationDraw.setValue(this.core.normalMat); } frameCtx.modelMat = this.core.mat; }, - pick : function(frameCtx) { + pick: function (frameCtx) { /* Rebuild core's matrix from matrices at cores on path up to root */ @@ -46,7 +46,7 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uMatLocationPick) { - gl.uniformMatrix4fv(this._uMatLocationPick, gl.FALSE, this.core.mat); + this._uMatLocationPick.setValue(this.core.mat); } frameCtx.modelMat = this.core.mat; diff --git a/src/core/display/display.js b/src/core/display/display.js index 2d36c6c3..86dfe8ee 100644 --- a/src/core/display/display.js +++ b/src/core/display/display.js @@ -1036,7 +1036,6 @@ SceneJS_Display.prototype._doDrawList = function (params) { var VAO = gl.getExtension("OES_vertex_array_object"); frameCtx.VAO = (VAO) ? VAO : null; - frameCtx.VAO = null; gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); diff --git a/src/core/display/program.js b/src/core/display/program.js index 0eaac1ed..c5e5d905 100644 --- a/src/core/display/program.js +++ b/src/core/display/program.js @@ -65,11 +65,6 @@ var SceneJS_Program = function(id, hash, source, gl) { * This is also re-called to re-create them after WebGL context loss. */ SceneJS_Program.prototype.build = function(gl) { - /** - * Current draw uniform state cached as a bitfield to avoid costly extra uniform1i calls - * @type Number - */ - this.drawUniformFlags = 0; this.gl = gl; this.draw = new SceneJS._webgl.Program(gl, [this.source.drawVertexSrc.join("\n")], [this.source.drawFragmentSrc.join("\n")]); diff --git a/src/core/webgl/uniform.js b/src/core/webgl/uniform.js index 01482908..62049c0e 100644 --- a/src/core/webgl/uniform.js +++ b/src/core/webgl/uniform.js @@ -1,82 +1,153 @@ - SceneJS._webgl.Uniform = function (gl, program, name, type, size, location, index, logging) { var func = null; - this.numberValue = false; - if (type == gl.BOOL) { - this.numberValue = true; + + var value = null; + + if (type === gl.BOOL) { + func = function (v) { + if (value === v) { + return; + } + value = v; gl.uniform1i(location, v); }; - } else if (type == gl.BOOL_VEC2) { + + } else if (type === gl.BOOL_VEC2) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; gl.uniform2iv(location, v); }; - } else if (type == gl.BOOL_VEC3) { + + } else if (type === gl.BOOL_VEC3) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; gl.uniform3iv(location, v); }; - } else if (type == gl.BOOL_VEC4) { + + } else if (type === gl.BOOL_VEC4) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; gl.uniform4iv(location, v); }; - } else if (type == gl.INT) { - this.numberValue = true; + + } else if (type === gl.INT) { + func = function (v) { + if (value === v) { + return; + } + value = v; gl.uniform1iv(location, v); }; - } else if (type == gl.INT_VEC2) { + + } else if (type === gl.INT_VEC2) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; gl.uniform2iv(location, v); }; - } else if (type == gl.INT_VEC3) { + + } else if (type === gl.INT_VEC3) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; gl.uniform3iv(location, v); }; - } else if (type == gl.INT_VEC4) { + + } else if (type === gl.INT_VEC4) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; gl.uniform4iv(location, v); }; - } else if (type == gl.FLOAT) { - this.numberValue = true; + + } else if (type === gl.FLOAT) { + func = function (v) { + if (value === v) { + return; + } + value = v; gl.uniform1f(location, v); }; - } else if (type == gl.FLOAT_VEC2) { + + } else if (type === gl.FLOAT_VEC2) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; gl.uniform2fv(location, v); }; - } else if (type == gl.FLOAT_VEC3) { + + } else if (type === gl.FLOAT_VEC3) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; gl.uniform3fv(location, v); }; - } else if (type == gl.FLOAT_VEC4) { + + } else if (type === gl.FLOAT_VEC4) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; gl.uniform4fv(location, v); }; - } else if (type == gl.FLOAT_MAT2) { + + } else if (type === gl.FLOAT_MAT2) { + func = function (v) { gl.uniformMatrix2fv(location, gl.FALSE, v); }; - } else if (type == gl.FLOAT_MAT3) { + + } else if (type === gl.FLOAT_MAT3) { + func = function (v) { gl.uniformMatrix3fv(location, gl.FALSE, v); }; - } else if (type == gl.FLOAT_MAT4) { + + } else if (type === gl.FLOAT_MAT4) { + func = function (v) { gl.uniformMatrix4fv(location, gl.FALSE, v); }; + } else { throw "Unsupported shader uniform type: " + type; } this.setValue = func; - - this.getValue = function () { - return gl.getUniform(program, location); - }; - this.getLocation = function () { return location; }; From 466880b04944e57138e6fcbb4ad4fd2108ced72a Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 20:32:01 +0200 Subject: [PATCH 04/14] Fix MorphGeometry #getFactor --- src/core/scene/morphGeometry.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/scene/morphGeometry.js b/src/core/scene/morphGeometry.js index d2c98432..40a138ef 100644 --- a/src/core/scene/morphGeometry.js +++ b/src/core/scene/morphGeometry.js @@ -321,6 +321,8 @@ new (function () { */ core.factor = (factor - keys[key1]) / (keys[key2] - keys[key1]); + this._factor = factor; + var morphUpdate = frameUpdate || oldFactor != core.factor; core.key1 = key1; @@ -338,7 +340,7 @@ new (function () { }; SceneJS.MorphGeometry.prototype.getFactor = function () { - return this._core.factor; + return this._factor; }; SceneJS.MorphGeometry.prototype.getKeys = function () { From 7fc9b2b0369f2f0d484ec51cbb247991ed848f39 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 22:35:44 +0200 Subject: [PATCH 05/14] Fix draw chunk uniform --- src/core/display/chunks/drawChunk.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/core/display/chunks/drawChunk.js b/src/core/display/chunks/drawChunk.js index 92484c7f..95b9e3a4 100644 --- a/src/core/display/chunks/drawChunk.js +++ b/src/core/display/chunks/drawChunk.js @@ -3,7 +3,7 @@ */ SceneJS_ChunkFactory.createChunkType({ - type:"draw", + type: "draw", /** * As we apply a list of state chunks in a {@link SceneJS_Display}, we track the ID of each chunk @@ -12,20 +12,28 @@ SceneJS_ChunkFactory.createChunkType({ * We don't want that for draw chunks however, because they contain GL drawElements calls, * which we need to do for each object. */ - unique:true, + unique: true, - build:function () { + build: function () { this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); }, - drawAndPick:function (frameCtx) { + drawAndPick: function (frameCtx) { var gl = this.program.gl; var indexType = this.program.UINT_INDEX_ENABLED ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT; - (frameCtx.pick ? this._depthModePick : this._depthModeDraw).setValue(frameCtx.depthMode); + if (frameCtx.pick) { + if (this._depthModePick) { + this._depthModePick.setValue(frameCtx.depthMode); + } + } else { + if (this._depthModeDraw) { + this._depthModeDraw.setValue(frameCtx.depthMode); + } + } gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, indexType, 0); From a93563b2f05b1cd0802a5f2582741100f1f13c48 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 22:36:48 +0200 Subject: [PATCH 06/14] Added a "solid" Flags node attribute --- src/core/display/chunks/flagsChunk.js | 7 +++++ src/core/display/programSourceFactory.js | 20 ++++++++++++-- src/core/scene/flags.js | 35 ++++++++++++++++++++---- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/src/core/display/chunks/flagsChunk.js b/src/core/display/chunks/flagsChunk.js index eca83cd2..94685b2c 100644 --- a/src/core/display/chunks/flagsChunk.js +++ b/src/core/display/chunks/flagsChunk.js @@ -10,6 +10,7 @@ SceneJS_ChunkFactory.createChunkType({ var draw = this.program.draw; this._uClippingDraw = draw.getUniform("SCENEJS_uClipping"); + this._uSolidDraw = draw.getUniform("SCENEJS_uSolid"); var pick = this.program.pick; @@ -66,14 +67,20 @@ SceneJS_ChunkFactory.createChunkType({ } if (frameCtx.pick) { + if (this._uClippingPick) { this._uClippingPick.setValue(this.core.clipping); } } else { + if (this._uClippingDraw) { this._uClippingDraw.setValue(this.core.clipping); } + + if (this._uSolidDraw) { + this._uSolidDraw.setValue(this.core.solid); + } } } }); diff --git a/src/core/display/programSourceFactory.js b/src/core/display/programSourceFactory.js index 858ff303..fa249cb0 100644 --- a/src/core/display/programSourceFactory.js +++ b/src/core/display/programSourceFactory.js @@ -506,6 +506,7 @@ var SceneJS_ProgramSourceFactory = new (function () { var texturing = this._isTexturing(states); var cubeMapping = this._isCubeMapping(states); var normals = this._hasNormals(states); + var solid = states.flags.solid; var tangents = this._hasTangents(states); var clipping = states.clips.clips.length > 0; @@ -564,10 +565,13 @@ var SceneJS_ProgramSourceFactory = new (function () { } } - /* True when lighting - */ + // True when lighting src.push("uniform bool SCENEJS_uClipping;"); + // True when interior surfaces of solid cross-sections + // are to be rendered without texture and shading + src.push("uniform bool SCENEJS_uSolid;"); + // Added in v4.0 to support depth targets src.push("uniform bool SCENEJS_uDepthMode;"); @@ -630,6 +634,18 @@ var SceneJS_ProgramSourceFactory = new (function () { src.push("}"); } + if (normals) { + + if (solid) { + + src.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"); + src.push(" if (a < 0.0) {"); + src.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"); + src.push(" return;"); + src.push(" }"); + } + } + src.push(" vec3 ambient= SCENEJS_uAmbientColor;"); if (texturing && states.geometry.uvBuf && fragmentHooks.texturePos) { diff --git a/src/core/scene/flags.js b/src/core/scene/flags.js index 99503d75..379e8ecf 100644 --- a/src/core/scene/flags.js +++ b/src/core/scene/flags.js @@ -15,7 +15,8 @@ backfaces: true, // Show backfaces frontface: "ccw", // Default vertex winding for front face reflective: true, // Reflects reflection node cubemap, if it exists, by default. - hash: "refl" + solid: true, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect + hash: "refl;s;" }; var coreStack = []; @@ -45,7 +46,8 @@ this._core.backfaces = true; // Show backfaces this._core.frontface = "ccw"; // Default vertex winding for front face this._core.reflective = true; // Reflects reflection node cubemap, if it exists, by default. - if (params.flags) { // 'flags' property is actually optional in the node definition + this._core.solid = true; // Renders backfaces without texture or shading, for a cheap solid cross-section effect + if (params.flags) { // 'flags' property is actually optional in the node definition this.setFlags(params.flags); } } @@ -89,8 +91,14 @@ core.reflective = flags.reflective; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); - this._engine.display.imageDirty = true; } + + if (flags.solid != undefined) { + core.solid = flags.solid; + core.hash = core.reflective ? "refl" : ""; + this._engine.branchDirty(this); + } + return this; }; @@ -117,7 +125,8 @@ transparent: core.transparent, backfaces: core.backfaces, frontface: core.frontface, - reflective: core.reflective + reflective: core.reflective, + solid: core.solid }; }; @@ -202,9 +211,8 @@ reflective = !!reflective; if (this._core.reflective != reflective) { this._core.reflective = reflective; - this._core.hash = reflective ? "refl" : ""; + this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";"; this._engine.branchDirty(this); - this._engine.display.imageDirty = true; } return this; }; @@ -213,6 +221,21 @@ return this._core.reflective; }; + SceneJS.Flags.prototype.setSolid = function(solid) { + solid = !!solid; + if (this._core.solid != solid) { + this._core.solid = solid; + this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s" : ";"; + this._engine.branchDirty(this); + } + return this; + }; + + SceneJS.Flags.prototype.getSolid = function() { + return this._core.solid; + }; + + SceneJS.Flags.prototype._compile = function(ctx) { this._engine.display.flags = coreStack[stackLen++] = this._core; this._compileNodes(ctx); From 3c8b1a4752d161d25c81e9c11466ce37ec740518 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 22:37:56 +0200 Subject: [PATCH 07/14] Build fix - deploy snapshots to api/latest --- Gruntfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 3cba60ae..01bccb11 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -44,11 +44,11 @@ module.exports = function (grunt) { copy: { minified: { src: '<%= build_dir %>/<%= PROJECT_NAME %>-<%= ENGINE_VERSION %>.min.js', - dest: 'build/<%= PROJECT_NAME %>.min.js' + dest: 'api/latest/<%= PROJECT_NAME %>.min.js' }, unminified: { src: '<%= build_dir %>/<%= PROJECT_NAME %>-<%= ENGINE_VERSION %>.js', - dest: 'build/<%= PROJECT_NAME %>.js' + dest: 'api/latest/<%= PROJECT_NAME %>.js' } } }); From 144ebfca4301c43d2f52adb4acd22fa93075b58f Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 22:38:32 +0200 Subject: [PATCH 08/14] Bump to v4.2.0 --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 97edd207..7b5c281b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "scenejs", "title": "SceneJS", - "version": "4.1.0", + "version": "4.2.0", "description": "A WebGL-based 3D scene graph from xeoLabs", "homepage": "http://scenejs.org/", "author": { @@ -19,9 +19,9 @@ "devDependencies": { "grunt": "~0.4.5", "grunt-contrib-concat": "~0.5.1", - "grunt-contrib-uglify": "~0.8.0", + "grunt-contrib-uglify": "~0.9.1", "grunt-contrib-yuidoc": "~0.7.0", - "grunt-contrib-jshint": "~0.11.1", + "grunt-contrib-jshint": "~0.11.2", "grunt-contrib-clean": "~0.6.0", "grunt-contrib-copy": "~0.8.0", "grunt-contrib-jasmine": "~0.8.2", From 40c9dc4e06c0cb7fb93e9fd1e9f1a25be08e7ee5 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Wed, 10 Jun 2015 22:39:11 +0200 Subject: [PATCH 09/14] Build --- api/latest/scenejs.js | 626 +- api/latest/scenejs.min.js | 22 + build/4.2.0/scenejs-4.2.0.js | 18308 +++++++++++++++++++++++++++++ build/4.2.0/scenejs-4.2.0.min.js | 22 + 4 files changed, 18732 insertions(+), 246 deletions(-) create mode 100644 api/latest/scenejs.min.js create mode 100644 build/4.2.0/scenejs-4.2.0.js create mode 100644 build/4.2.0/scenejs-4.2.0.min.js diff --git a/api/latest/scenejs.js b/api/latest/scenejs.js index d75f22de..6f3ef137 100644 --- a/api/latest/scenejs.js +++ b/api/latest/scenejs.js @@ -1,3 +1,17 @@ +/* + * SceneJS V4.2.0 + * + * A WebGL-based 3D scene graph from xeoLabs + * http://scenejs.org/ + * + * Built on 2015-06-10 + * + * MIT License + * Copyright 2015, Lindsay Kay + * http://xeolabs.com/ + * + */ + /* * SceneJS Latest * @@ -10,8 +24,8 @@ * */ -// Only define RequireJS if not already present -if (undefined === require) {/* +;// Only define RequireJS if not already present +if (undefined === require) {;/* RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. Available via the MIT or new BSD license. see: http://github.com/jrburke/requirejs for details @@ -46,7 +60,7 @@ var requirejs,require,define; "html:script"):document.createElement("script"),g.type=h.scriptType||"text/javascript",g.charset="utf-8",g.async=!0,g.setAttribute("data-requirecontext",b.contextName),g.setAttribute("data-requiremodule",c),g.attachEvent&&!(g.attachEvent.toString&&0>g.attachEvent.toString().indexOf("[native code"))&&!Z?(Q=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=d,M=g,E?y.insertBefore(g,E):y.appendChild(g), M=null,g;if(ea)try{importScripts(d),b.completeLoad(c)}catch(l){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,l,[c]))}};A&&O(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(L=b.getAttribute("data-main"))return s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0});define=function(b,c,d){var h,g;"string"!==typeof b&&(d=c,c=b,b=null); K(c)||(d=c,c=null);!c&&J(d)&&(c=[],d.length&&(d.toString().replace(ma,"").replace(na,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(Q){if(!(h=M))R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return R=b}),h=R;h&&(b||(b=h.getAttribute("data-requiremodule")),g=G[h.getAttribute("data-requirecontext")])}(g?g.defQueue:U).push([b,c,d])};define.amd={jQuery:!0};h.exec=function(b){return eval(b)}; - h(u)}})(this);} + h(u)}})(this);;}; WebGLDebugUtils = function() { /** @@ -885,7 +899,7 @@ return { }; }(); -/** +;/** * @class Generic map of IDs to items - can generate own IDs or accept given IDs. IDs should be strings in order to not * clash with internally generated IDs, which are numbers. * @private @@ -949,7 +963,7 @@ var SceneJS_Map = function(items, _baseId) { this.removeItem = function(id) { delete this.items[id]; }; -};/** +};;/** * The SceneJS object. */ var SceneJS = new (function () { @@ -1285,7 +1299,7 @@ var SceneJS = new (function () { }; })(); -// Configure RequireJS to find plugins relative to plugins location +;// Configure RequireJS to find plugins relative to plugins location (function () { var pluginPath; @@ -1302,7 +1316,7 @@ var SceneJS = new (function () { }); } }); -})();/** +})();;/** * @private */ var SceneJS_eventManager = function () { @@ -1395,7 +1409,7 @@ SceneJS_eventManager.prototype.unEvent = function (handlerId) { delete handlers[handlerId]; this.typeHandlers[type].numSubs--; }; -/** +;/** * SceneJS plugin registry */ SceneJS.Plugins = new (function () { @@ -1521,7 +1535,7 @@ SceneJS.Plugins = new (function () { document.getElementsByTagName("head")[0].appendChild(script); } -})();/** +})();;/** * @private */ var SceneJS_events = new (function () { @@ -1704,7 +1718,7 @@ SceneJS.off = SceneJS.unEvent; -/** +;/** * */ var SceneJS_Canvas = function (id, canvasId, contextAttr, options) { @@ -1824,7 +1838,7 @@ SceneJS_Canvas.prototype.setSSAAMultiplier = function (ssaaMultiplier) { }; -/** +;/** * @class A container for a scene graph and its display * * @@ -2476,7 +2490,7 @@ if (!self.Int32Array) { clearTimeout(id); }; }()); -/** +;/** * Backend module that provides single point through which exceptions may be raised * * @class SceneJS_error @@ -2561,7 +2575,7 @@ SceneJS.errors._getErrorName = function(code) { return null; }; -/** +;/** * Backend that manages configurations. * * @class SceneJS_configsModule @@ -2656,7 +2670,7 @@ SceneJS.getConfigs = SceneJS.getDebugConfigs = function (path) { return SceneJS_configsModule.getConfigs(path); }; -/** +;/** * @class Manages logging * @private */ @@ -2755,7 +2769,7 @@ SceneJS.log = new (function() { return funcs; }; -})();/* +})();;/* * Optimizations made based on glMatrix by Brandon Jones */ @@ -4864,7 +4878,7 @@ var SceneJS_math_angleAxisFromQuaternion = function(q) { }; } }; -/** +;/** * Backend that tracks statistics on loading states of nodes during scene traversal. * * This supports the "loading-status" events that we can listen for on scene nodes. @@ -5057,8 +5071,8 @@ var SceneJS_sceneStatusModule = new (function () { function failPopup(element) { element.style.background = "#FFAAAA"; } -})();SceneJS._webgl = {}; -/** Buffer for vertices and indices +})();;SceneJS._webgl = {}; +;/** Buffer for vertices and indices * * @private * @param gl WebGL gl @@ -5164,7 +5178,7 @@ SceneJS._webgl.ArrayBuffer.prototype.bind = function () { }; - +; /** An attribute within a shader */ SceneJS._webgl.Attribute = function (gl, program, name, type, size, location) { @@ -5185,7 +5199,7 @@ SceneJS._webgl.Attribute.prototype.bindInterleavedFloatArrayBuffer = function (c this.gl.enableVertexAttribArray(this.location); this.gl.vertexAttribPointer(this.location, components, this.gl.FLOAT, false, stride, byteOffset); // Vertices are not homogeneous - no w-element }; - +; /** Maps SceneJS node parameter names to WebGL enum names * @private */ @@ -5241,7 +5255,7 @@ SceneJS._webgl.enumMap = { unsignedByte: "UNSIGNED_BYTE" }; -SceneJS._webgl.RenderBuffer = function (cfg) { +;SceneJS._webgl.RenderBuffer = function (cfg) { /** * True as soon as this buffer is allocated and ready to go @@ -5432,7 +5446,7 @@ SceneJS._webgl.RenderBuffer.prototype.destroy = function () { this.buf = null; this.bound = false; } -};/** +};;/** * @class Wrapper for a WebGL program * * @param hash SceneJS-managed ID for program @@ -5621,7 +5635,7 @@ SceneJS._webgl.Program.prototype.setUniform = function (name, value) { } } }; -SceneJS._webgl.Sampler = function (gl, program, name, type, size, location) { +;SceneJS._webgl.Sampler = function (gl, program, name, type, size, location) { this.bindTexture = function (texture, unit) { if (texture.bind(unit)) { @@ -5631,7 +5645,7 @@ SceneJS._webgl.Sampler = function (gl, program, name, type, size, location) { return false; }; }; -/** +;/** * A vertex/fragment shader in a program * * @private @@ -5677,7 +5691,7 @@ SceneJS._webgl.Shader = function (gl, type, source) { this.allocated = true; }; - +; SceneJS._webgl.Texture2D = function (gl, cfg) { /** * True as soon as this texture is allocated and ready to go @@ -5816,85 +5830,156 @@ SceneJS._webgl.nextHighestPowerOfTwo = function (x) { return x + 1; }; - -SceneJS._webgl.Uniform = function (gl, program, name, type, size, location, index, logging) { +;SceneJS._webgl.Uniform = function (gl, program, name, type, size, location, index, logging) { var func = null; - this.numberValue = false; - if (type == gl.BOOL) { - this.numberValue = true; + + var value = null; + + if (type === gl.BOOL) { + func = function (v) { + if (value === v) { + return; + } + value = v; gl.uniform1i(location, v); }; - } else if (type == gl.BOOL_VEC2) { + + } else if (type === gl.BOOL_VEC2) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; gl.uniform2iv(location, v); }; - } else if (type == gl.BOOL_VEC3) { + + } else if (type === gl.BOOL_VEC3) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; gl.uniform3iv(location, v); }; - } else if (type == gl.BOOL_VEC4) { + + } else if (type === gl.BOOL_VEC4) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; gl.uniform4iv(location, v); }; - } else if (type == gl.INT) { - this.numberValue = true; + + } else if (type === gl.INT) { + func = function (v) { + if (value === v) { + return; + } + value = v; gl.uniform1iv(location, v); }; - } else if (type == gl.INT_VEC2) { + + } else if (type === gl.INT_VEC2) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; gl.uniform2iv(location, v); }; - } else if (type == gl.INT_VEC3) { + + } else if (type === gl.INT_VEC3) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; gl.uniform3iv(location, v); }; - } else if (type == gl.INT_VEC4) { + + } else if (type === gl.INT_VEC4) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; gl.uniform4iv(location, v); }; - } else if (type == gl.FLOAT) { - this.numberValue = true; + + } else if (type === gl.FLOAT) { + func = function (v) { + if (value === v) { + return; + } + value = v; gl.uniform1f(location, v); }; - } else if (type == gl.FLOAT_VEC2) { + + } else if (type === gl.FLOAT_VEC2) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; gl.uniform2fv(location, v); }; - } else if (type == gl.FLOAT_VEC3) { + + } else if (type === gl.FLOAT_VEC3) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; gl.uniform3fv(location, v); }; - } else if (type == gl.FLOAT_VEC4) { + + } else if (type === gl.FLOAT_VEC4) { + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; gl.uniform4fv(location, v); }; - } else if (type == gl.FLOAT_MAT2) { + + } else if (type === gl.FLOAT_MAT2) { + func = function (v) { gl.uniformMatrix2fv(location, gl.FALSE, v); }; - } else if (type == gl.FLOAT_MAT3) { + + } else if (type === gl.FLOAT_MAT3) { + func = function (v) { gl.uniformMatrix3fv(location, gl.FALSE, v); }; - } else if (type == gl.FLOAT_MAT4) { + + } else if (type === gl.FLOAT_MAT4) { + func = function (v) { gl.uniformMatrix4fv(location, gl.FALSE, v); }; + } else { throw "Unsupported shader uniform type: " + type; } this.setValue = func; - - this.getValue = function () { - return gl.getUniform(program, location); - }; - this.getLocation = function () { return location; }; @@ -5912,7 +5997,7 @@ SceneJS._webgl.Uniform = function (gl, program, name, type, size, location, inde -/** +;/** * Manages scene node event listeners * @private */ @@ -6009,7 +6094,7 @@ var SceneJS_nodeEventsModule = new (function () { })(); -/** +;/** * @class Holds state for one or more {@link SceneJS.Node}s. * *

Each {@link SceneJS.Node} has a state core to hold its state, and the core may be shared by other @@ -6051,7 +6136,7 @@ var SceneJS_Core = function(type) { * Count of {@link SceneJS.Node} instances this core holds state for */ this.useCount = 0; -};/** +};;/** * @class Manages creation, recycle and destruction of {@link SceneJS_Core} instances * @private */ @@ -6223,7 +6308,7 @@ SceneJS_CoreFactory.prototype.webglRestored = function () { } } }; -/** +;/** * @class The basic scene graph node type */ SceneJS.Node = function () { @@ -7621,7 +7706,7 @@ SceneJS.Node.prototype._doDestroy = function () { } return this; -};SceneJS_PubSubProxy = function (scene, proxy) { +};;SceneJS_PubSubProxy = function (scene, proxy) { this.scene = scene; this.proxy = proxy; @@ -7629,7 +7714,7 @@ SceneJS.Node.prototype._doDestroy = function () { -/** +;/** * @class Manages creation, recycle and destruction of {@link SceneJS.Node} instances * @private */ @@ -7776,7 +7861,7 @@ SceneJS_NodeFactory.prototype._loadScript = function (url, error) { SceneJS_NodeFactory.prototype.putNode = function (node) { this.nodes.removeItem(node.id); }; -(function () { +;(function () { var defaultMatrix = SceneJS_math_perspectiveMatrix4( 45, // fovy @@ -7989,7 +8074,7 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { SceneJS.Camera.prototype._destroy = function () { this.getScene().off(this._canvasSizeSub); }; -})();(function() { +})();;(function() { /** * The default state core singleton for {@link SceneJS.Clips} nodes @@ -8086,7 +8171,7 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { }; -})();(function () { +})();;(function () { // The default state core singleton for {@link SceneJS.Enable} nodes var defaultCore = { @@ -8139,7 +8224,7 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { this._engine.display.enable = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();(function() { +})();;(function() { /** * The default state core singleton for {@link SceneJS.Flags} nodes @@ -8156,7 +8241,8 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { backfaces: true, // Show backfaces frontface: "ccw", // Default vertex winding for front face reflective: true, // Reflects reflection node cubemap, if it exists, by default. - hash: "refl" + solid: true, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect + hash: "refl;s;" }; var coreStack = []; @@ -8186,7 +8272,8 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { this._core.backfaces = true; // Show backfaces this._core.frontface = "ccw"; // Default vertex winding for front face this._core.reflective = true; // Reflects reflection node cubemap, if it exists, by default. - if (params.flags) { // 'flags' property is actually optional in the node definition + this._core.solid = true; // Renders backfaces without texture or shading, for a cheap solid cross-section effect + if (params.flags) { // 'flags' property is actually optional in the node definition this.setFlags(params.flags); } } @@ -8230,8 +8317,14 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { core.reflective = flags.reflective; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); - this._engine.display.imageDirty = true; } + + if (flags.solid != undefined) { + core.solid = flags.solid; + core.hash = core.reflective ? "refl" : ""; + this._engine.branchDirty(this); + } + return this; }; @@ -8258,7 +8351,8 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { transparent: core.transparent, backfaces: core.backfaces, frontface: core.frontface, - reflective: core.reflective + reflective: core.reflective, + solid: core.solid }; }; @@ -8343,9 +8437,8 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { reflective = !!reflective; if (this._core.reflective != reflective) { this._core.reflective = reflective; - this._core.hash = reflective ? "refl" : ""; + this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";"; this._engine.branchDirty(this); - this._engine.display.imageDirty = true; } return this; }; @@ -8354,6 +8447,21 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { return this._core.reflective; }; + SceneJS.Flags.prototype.setSolid = function(solid) { + solid = !!solid; + if (this._core.solid != solid) { + this._core.solid = solid; + this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s" : ";"; + this._engine.branchDirty(this); + } + return this; + }; + + SceneJS.Flags.prototype.getSolid = function() { + return this._core.solid; + }; + + SceneJS.Flags.prototype._compile = function(ctx) { this._engine.display.flags = coreStack[stackLen++] = this._core; this._compileNodes(ctx); @@ -8361,7 +8469,7 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { }; })(); -new (function () { +;new (function () { var defaultCore = { type: "renderTarget", @@ -8424,7 +8532,7 @@ new (function () { delete nodeCoreMap[this._core.coreId]; } }; -})();new (function () { +})();;new (function () { var defaultCore = { type: "renderTarget", @@ -8487,7 +8595,7 @@ new (function () { delete nodeCoreMap[this._core.coreId]; } }; -})();new (function () { +})();;new (function () { var coreStack = []; var stackLen = 0; @@ -9248,7 +9356,7 @@ new (function () { }; })(); -(function() { +;(function() { /** * The default state core singleton for {@link SceneJS.Stage} nodes @@ -9321,7 +9429,7 @@ new (function () { })(); -(function () { +;(function () { /** * The default state core singleton for {@link SceneJS.Layer} nodes @@ -9404,7 +9512,7 @@ new (function () { })(); -/** +;/** * @class Scene graph node which assigns nodes in its subgraph to a library * @extends SceneJS.Node */ @@ -9412,7 +9520,7 @@ SceneJS.Library = SceneJS_NodeFactory.createNodeType("library"); SceneJS.Library.prototype._compile = function(ctx) { // Bypass child nodes }; -(function () { +;(function () { /** * The default state core singleton for {@link SceneJS.Lights} nodes @@ -9677,7 +9785,7 @@ SceneJS.Library.prototype._compile = function(ctx) { // Bypass child nodes this._engine.display.lights = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();(function () { +})();;(function () { var defaultMatrix = SceneJS_math_lookAtMat4c(0, 0, 10, 0, 0, 0, 0, 1, 0); var defaultMat = new Float32Array(defaultMatrix); @@ -10084,7 +10192,7 @@ SceneJS.Library.prototype._compile = function(ctx) { // Bypass child nodes this.getScene().off(this._tick); }; -})();/* +})();;/* TODO: material system from virtualworldframework: @@ -10238,7 +10346,7 @@ new (function () { this._engine.display.material = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();new (function () { +})();;new (function () { /** * The default state core singleton for {@link SceneJS.MorphGeometry} nodes @@ -10561,6 +10669,8 @@ new (function () { */ core.factor = (factor - keys[key1]) / (keys[key2] - keys[key1]); + this._factor = factor; + var morphUpdate = frameUpdate || oldFactor != core.factor; core.key1 = key1; @@ -10578,7 +10688,7 @@ new (function () { }; SceneJS.MorphGeometry.prototype.getFactor = function () { - return this._core.factor; + return this._factor; }; SceneJS.MorphGeometry.prototype.getKeys = function () { @@ -10657,7 +10767,7 @@ new (function () { } }; -})();(function () { +})();;(function () { /** * The default state core singleton for {@link SceneJS.Name} nodes @@ -10716,7 +10826,7 @@ new (function () { this._compileNodes(ctx); this._engine.display.name = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();new (function () { +})();;new (function () { /** * The default state core singleton for {@link SceneJS.Renderer} nodes @@ -11504,7 +11614,7 @@ new (function () { this._compileNodes(ctx); this._engine.display.renderer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();(function () { +})();;(function () { var lookup = { less:"LESS", @@ -11674,7 +11784,7 @@ new (function () { this._engine.display.depthBuffer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();(function () { +})();;(function () { // The default state core singleton for {@link SceneJS.ColorBuffer} nodes var defaultCore = { @@ -11760,7 +11870,7 @@ new (function () { this._engine.display.imageDirty = true; }; -})();(function () { +})();;(function () { // The default state core singleton for {@link SceneJS.View} nodes var defaultCore = { @@ -11833,7 +11943,7 @@ new (function () { this._engine.display.view = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();/** +})();;/** * @class The root node of a scenegraph * @extends SceneJS.Node * @@ -12124,7 +12234,7 @@ SceneJS.Scene.prototype.getStatus = function () { } return SceneJS._shallowClone(sceneStatus); }; -new (function() { +;new (function() { /** * The default state core singleton for {@link SceneJS.Shader} nodes @@ -12317,7 +12427,7 @@ new (function() { dirty = true; }; -})();new (function() { +})();;new (function() { /** * The default state core singleton for {@link SceneJS.ShaderParams} nodes @@ -12413,7 +12523,7 @@ new (function() { dirty = true; }; -})();(function () { +})();;(function () { // The default state core singleton for {@link SceneJS.Line} nodes var defaultCore = { @@ -12476,7 +12586,7 @@ new (function() { this._engine.display.style = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();(function() { +})();;(function() { /** * The default state core singleton for {@link SceneJS.Tag} nodes @@ -12535,7 +12645,7 @@ new (function() { this._compileNodes(ctx); this._engine.display.tag = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; }; -})();/** +})();;/** * @class Scene graph node which defines textures to apply to the objects in its subgraph *

This is the deprecated node type from SceneJS v3.2, which has been replaced by the "texture" node in ./texture.js

* @extends SceneJS.Node @@ -13030,7 +13140,7 @@ new (function () { } }; -})();/** +})();;/** * @class Scene graph node which defines textures to apply to the objects in its subgraph * @extends SceneJS.Node */ @@ -13402,7 +13512,7 @@ new (function () { } }; -})();(function () { +})();;(function () { // The default state core singleton for {@link SceneJS.ColorBuf} nodes var defaultCore = { @@ -13565,7 +13675,7 @@ new (function () { } } -})();/** +})();;/** * @class Scene graph node which defines the modelling transform to apply to the objects in its subgraph * @extends SceneJS.Node */ @@ -13645,7 +13755,7 @@ SceneJS.XForm.prototype._compile = function (ctx) { this._compileNodes(ctx); SceneJS_modelXFormStack.pop(); }; - +; /** * @class Scene graph node which defines a modelling transform matrix to apply to the objects in its subgraph * @extends SceneJS.Node @@ -13730,7 +13840,7 @@ SceneJS.Matrix.prototype._compile = function(ctx) { this._compileNodes(ctx); SceneJS_modelXFormStack.pop(); }; -/** +;/** * @class Scene graph node which defines a rotation modelling transform to apply to the objects in its subgraph * @extends SceneJS.Node */ @@ -13878,7 +13988,7 @@ SceneJS.Rotate.prototype._compile = function(ctx) { this._compileNodes(ctx); SceneJS_modelXFormStack.pop(); }; -/** +;/** * @class Scene graph node which defines a translation modelling transform to apply to the objects in its subgraph * @extends SceneJS.Node */ @@ -14036,7 +14146,7 @@ SceneJS.Translate.prototype._compile = function(ctx) { this._compileNodes(ctx); SceneJS_modelXFormStack.pop(); }; -/** +;/** * @class Scene graph node which defines a rotation modelling transform to apply to the objects in its subgraph * @extends SceneJS.Node */ @@ -14183,7 +14293,7 @@ SceneJS.Scale.prototype._compile = function (ctx) { this._compileNodes(ctx); SceneJS_modelXFormStack.pop(); }; -/** +;/** * Provides a model transform stack in front of the renderer. * Nodes peek push and pop to the stack, while the renderer peeks at * the transform on the top of the stack whenever it builds a renderer node. @@ -14399,7 +14509,7 @@ var SceneJS_modelXFormStack = new (function () { }; })(); -/** +;/** * Container for custom node types */ SceneJS.Types = new (function () { @@ -14452,7 +14562,7 @@ SceneJS.Types = new (function () { }; })(); -/** +;/** * @class Display compiled from a {@link SceneJS.Scene}, providing methods to render and pick. * @private * @@ -15490,7 +15600,6 @@ SceneJS_Display.prototype._doDrawList = function (params) { var VAO = gl.getExtension("OES_vertex_array_object"); frameCtx.VAO = (VAO) ? VAO : null; - frameCtx.VAO = null; gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); @@ -15544,7 +15653,7 @@ SceneJS_Display.prototype._doDrawList = function (params) { SceneJS_Display.prototype.destroy = function () { this._programFactory.destroy(); }; -/** +;/** * @class Manages creation, sharing and recycle of {@link SceneJS_ProgramSource} instances * @private */ @@ -16052,6 +16161,7 @@ var SceneJS_ProgramSourceFactory = new (function () { var texturing = this._isTexturing(states); var cubeMapping = this._isCubeMapping(states); var normals = this._hasNormals(states); + var solid = states.flags.solid; var tangents = this._hasTangents(states); var clipping = states.clips.clips.length > 0; @@ -16110,10 +16220,13 @@ var SceneJS_ProgramSourceFactory = new (function () { } } - /* True when lighting - */ + // True when lighting src.push("uniform bool SCENEJS_uClipping;"); + // True when interior surfaces of solid cross-sections + // are to be rendered without texture and shading + src.push("uniform bool SCENEJS_uSolid;"); + // Added in v4.0 to support depth targets src.push("uniform bool SCENEJS_uDepthMode;"); @@ -16176,6 +16289,18 @@ var SceneJS_ProgramSourceFactory = new (function () { src.push("}"); } + if (normals) { + + if (solid) { + + src.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"); + src.push(" if (a < 0.0) {"); + src.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"); + src.push(" return;"); + src.push(" }"); + } + } + src.push(" vec3 ambient= SCENEJS_uAmbientColor;"); if (texturing && states.geometry.uvBuf && fragmentHooks.texturePos) { @@ -16452,7 +16577,7 @@ var SceneJS_ProgramSourceFactory = new (function () { return false; } -})();/** +})();;/** * @class Source code for pick and draw shader programs, to be compiled into one or more {@link SceneJS_Program}s * @private * @@ -16501,7 +16626,7 @@ var SceneJS_ProgramSource = function(hash, pickVertexSrc, pickFragmentSrc, drawV this.useCount = 0; }; -/** +;/** * @class Manages creation, sharing and recycle of {@link SceneJS_Program} instances * @private */ @@ -16574,7 +16699,7 @@ SceneJS_ProgramFactory.prototype.webglRestored = function() { */ SceneJS_ProgramFactory.prototype.destroy = function() { }; -/** +;/** * @class Vertex and fragment shaders for pick and draw * @private * @@ -16641,17 +16766,12 @@ var SceneJS_Program = function(id, hash, source, gl) { * This is also re-called to re-create them after WebGL context loss. */ SceneJS_Program.prototype.build = function(gl) { - /** - * Current draw uniform state cached as a bitfield to avoid costly extra uniform1i calls - * @type Number - */ - this.drawUniformFlags = 0; this.gl = gl; this.draw = new SceneJS._webgl.Program(gl, [this.source.drawVertexSrc.join("\n")], [this.source.drawFragmentSrc.join("\n")]); this.pick = new SceneJS._webgl.Program(gl, [this.source.pickVertexSrc.join("\n")], [this.source.pickFragmentSrc.join("\n")]); }; -/** +;/** * @class Manages creation and recycle of {@link SceneJS_Object} instances * @private */ @@ -16697,7 +16817,7 @@ SceneJS_ObjectFactory.prototype.getObject = function(id) { SceneJS_ObjectFactory.prototype.putObject = function (object) { this._freeObjects[this._numFreeObjects++] = object; -};/** +};;/** * @class An object within a {@link SceneJS_Display} * @private */ @@ -16758,7 +16878,7 @@ var SceneJS_Object = function(id) { * State core for the {@link SceneJS.Tag} that this object was compiled from, used for visibility cull */ this.tag = null; -};/** +};;/** * @class A facade which exposes internal scene rendering state to "rendered" event listeners bound to scene graph nodes with {@link SceneJS.Node#bind}. * *

The listener is fired for each {@link SceneJS.Geometry} that is rendered within the subgraph of the bound node. @@ -16846,7 +16966,7 @@ SceneJS.RenderContext.prototype.getWorldPos = function(offset) { this._wc = SceneJS_math_transformPoint3(this._frameCtx.modelMat, offset || [0,0,0]); return { x: this._wc[0], y: this._wc[1], z: this._wc[2], w: this._wc[3] }; }; -/** +;/** * @class A chunk of WebGL state changes to render a {@link SceneJS_Core} for drawing and picking (if applicable to the core type). * *

Instances of this class are created and recycled by a {@link SceneJS_ChunkFactory}.

@@ -16878,7 +16998,7 @@ SceneJS_Chunk.prototype.init = function(id, program, core, core2) { this.build(); } }; -/** +;/** * @class Manages creation, reuse and destruction of {@link SceneJS_Chunk}s for the nodes within a single {@link SceneJS_Display}. * @private */ @@ -17026,19 +17146,19 @@ SceneJS_ChunkFactory.prototype.webglRestored = function () { } } }; -SceneJS_ChunkFactory.createChunkType({ +;SceneJS_ChunkFactory.createChunkType({ type: "camera", build : function() { - this._uPMatrixDraw = this.program.draw.getUniformLocation("SCENEJS_uPMatrix"); - this._uZNearDraw = this.program.draw.getUniformLocation("SCENEJS_uZNear"); - this._uZFarDraw = this.program.draw.getUniformLocation("SCENEJS_uZFar"); + this._uPMatrixDraw = this.program.draw.getUniform("SCENEJS_uPMatrix"); + this._uZNearDraw = this.program.draw.getUniform("SCENEJS_uZNear"); + this._uZFarDraw = this.program.draw.getUniform("SCENEJS_uZFar"); - this._uPMatrixPick = this.program.pick.getUniformLocation("SCENEJS_uPMatrix"); - this._uZNearPick = this.program.pick.getUniformLocation("SCENEJS_uZNear"); - this._uZFarPick = this.program.pick.getUniformLocation("SCENEJS_uZFar"); + this._uPMatrixPick = this.program.pick.getUniform("SCENEJS_uPMatrix"); + this._uZNearPick = this.program.pick.getUniform("SCENEJS_uZNear"); + this._uZFarPick = this.program.pick.getUniform("SCENEJS_uZFar"); }, draw : function(frameCtx) { @@ -17050,15 +17170,15 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uPMatrixDraw) { - gl.uniformMatrix4fv(this._uPMatrixDraw, gl.FALSE, this.core.mat); + this._uPMatrixDraw.setValue(this.core.mat); } if (this._uZNearDraw) { - gl.uniform1f(this._uZNearDraw, this.core.optics.near); + this._uZNearDraw.setValue(this.core.optics.near); } if (this._uZFarDraw) { - gl.uniform1f(this._uZFarDraw, this.core.optics.far); + this._uZFarDraw.setValue(this.core.optics.far); } frameCtx.cameraMat = this.core.mat; // Query only in draw pass @@ -17074,23 +17194,23 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uPMatrixPick) { - gl.uniformMatrix4fv(this._uPMatrixPick, gl.FALSE, this.core.mat); + this._uPMatrixPick.setValue(this.core.mat); } if (frameCtx.rayPick) { // Z-pick pass: feed near and far clip planes into shader if (this._uZNearPick) { - gl.uniform1f(this._uZNearPick, this.core.optics.near); + this._uZNearPick.setValue(this.core.optics.near); } if (this._uZFarPick) { - gl.uniform1f(this._uZFarPick, this.core.optics.far); + this._uZFarPick.setValue(this.core.optics.far); } } frameCtx.cameraMat = this.core.mat; // Query only in draw pass } -});/** +});;/** * Create display state chunk type for draw and pick render of user clipping planes */ SceneJS_ChunkFactory.createChunkType({ @@ -17105,8 +17225,8 @@ SceneJS_ChunkFactory.createChunkType({ for (var i = 0, len = this.core.clips.length; i < len; i++) { this._draw[i] = { - uClipMode :draw.getUniformLocation("SCENEJS_uClipMode" + i), - uClipNormalAndDist: draw.getUniformLocation("SCENEJS_uClipNormalAndDist" + i) + uClipMode :draw.getUniform("SCENEJS_uClipMode" + i), + uClipNormalAndDist: draw.getUniform("SCENEJS_uClipNormalAndDist" + i) }; } @@ -17116,8 +17236,8 @@ SceneJS_ChunkFactory.createChunkType({ for (var i = 0, len = this.core.clips.length; i < len; i++) { this._pick[i] = { - uClipMode :pick.getUniformLocation("SCENEJS_uClipMode" + i), - uClipNormalAndDist: pick.getUniformLocation("SCENEJS_uClipNormalAndDist" + i) + uClipMode :pick.getUniform("SCENEJS_uClipMode" + i), + uClipNormalAndDist: pick.getUniform("SCENEJS_uClipNormalAndDist" + i) }; } }, @@ -17148,26 +17268,26 @@ SceneJS_ChunkFactory.createChunkType({ if (clip.mode == "inside") { - gl.uniform1f(mode, 2); - gl.uniform4fv(normalAndDist, clip.normalAndDist); + mode.setValue(2); + normalAndDist.setValue(clip.normalAndDist); } else if (clip.mode == "outside") { - gl.uniform1f(mode, 1); - gl.uniform4fv(normalAndDist, clip.normalAndDist); + mode.setValue(1); + normalAndDist.setValue(clip.normalAndDist); } else { // disabled - gl.uniform1f(mode, 0); + mode.setValue(0); } } } } -});/** +});;/** * */ SceneJS_ChunkFactory.createChunkType({ - type:"draw", + type: "draw", /** * As we apply a list of state chunks in a {@link SceneJS_Display}, we track the ID of each chunk @@ -17176,22 +17296,35 @@ SceneJS_ChunkFactory.createChunkType({ * We don't want that for draw chunks however, because they contain GL drawElements calls, * which we need to do for each object. */ - unique:true, + unique: true, - build:function () { - this._depthModeDraw = this.program.draw.getUniformLocation("SCENEJS_uDepthMode"); - this._depthModePick = this.program.pick.getUniformLocation("SCENEJS_uDepthMode"); + build: function () { + this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); + this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); }, - drawAndPick:function (frameCtx) { + drawAndPick: function (frameCtx) { + var gl = this.program.gl; + var indexType = this.program.UINT_INDEX_ENABLED ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT; - gl.uniform1i(frameCtx.pick ? this._depthModePick : this._depthModeDraw, frameCtx.depthMode); + + if (frameCtx.pick) { + if (this._depthModePick) { + this._depthModePick.setValue(frameCtx.depthMode); + } + } else { + if (this._depthModeDraw) { + this._depthModeDraw.setValue(frameCtx.depthMode); + } + } + gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, indexType, 0); + //frameCtx.textureUnit = 0; } }); -/** +;/** * Create display state chunk type for draw and pick render of flags */ SceneJS_ChunkFactory.createChunkType({ @@ -17202,11 +17335,12 @@ SceneJS_ChunkFactory.createChunkType({ var draw = this.program.draw; - this._uClippingDraw = draw.getUniformLocation("SCENEJS_uClipping"); + this._uClippingDraw = draw.getUniform("SCENEJS_uClipping"); + this._uSolidDraw = draw.getUniform("SCENEJS_uSolid"); var pick = this.program.pick; - this._uClippingPick = pick.getUniformLocation("SCENEJS_uClipping"); + this._uClippingPick = pick.getUniform("SCENEJS_uClipping"); }, drawAndPick: function (frameCtx) { @@ -17259,18 +17393,24 @@ SceneJS_ChunkFactory.createChunkType({ } if (frameCtx.pick) { - gl.uniform1i(this._uClippingPick, this.core.clipping); + + if (this._uClippingPick) { + this._uClippingPick.setValue(this.core.clipping); + } } else { - var drawUniforms = (this.core.clipping ? 1 : 0); - if (this.program.drawUniformFlags != drawUniforms) { - gl.uniform1i(this._uClippingDraw, this.core.clipping); - this.program.drawUniformFlags = drawUniforms; + + if (this._uClippingDraw) { + this._uClippingDraw.setValue(this.core.clipping); + } + + if (this._uSolidDraw) { + this._uSolidDraw.setValue(this.core.solid); } } } }); -/** +;/** * Create display state chunk type for draw and pick render of renderTarget */ SceneJS_ChunkFactory.createChunkType({ @@ -17319,7 +17459,7 @@ SceneJS_ChunkFactory.createChunkType({ frameCtx.renderBuf = renderBuf; } -});/** +});;/** * Create display state chunk type for draw and pick render of geometry */ SceneJS_ChunkFactory.createChunkType({ @@ -17339,13 +17479,13 @@ SceneJS_ChunkFactory.createChunkType({ this._aMorphVertexDraw = draw.getAttribute("SCENEJS_aMorphVertex"); this._aMorphNormalDraw = draw.getAttribute("SCENEJS_aMorphNormal"); - this._uMorphFactorDraw = draw.getUniformLocation("SCENEJS_uMorphFactor"); + this._uMorphFactorDraw = draw.getUniform("SCENEJS_uMorphFactor"); var pick = this.program.pick; this._aVertexPick = pick.getAttribute("SCENEJS_aVertex"); this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); - this._uMorphFactorPick = pick.getUniformLocation("SCENEJS_uMorphFactor"); + this._uMorphFactorPick = pick.getUniform("SCENEJS_uMorphFactor"); this.VAO = null; this.VAOMorphKey1 = 0; @@ -17401,7 +17541,7 @@ SceneJS_ChunkFactory.createChunkType({ setDrawMorphFactor:function () { if (this._uMorphFactorDraw) { - this.program.gl.uniform1f(this._uMorphFactorDraw, this.core.factor); // Bind LERP factor + this._uMorphFactorDraw.setValue*(this.core.factor); // Bind LERP factor } }, @@ -17497,7 +17637,7 @@ SceneJS_ChunkFactory.createChunkType({ } if (this._uMorphFactorPick) { - this.program.gl.uniform1f(this._uMorphFactorPick, this.core.factor); // Bind LERP factor + this._uMorphFactorPick.setValue(this.core.factor); // Bind LERP factor } }, @@ -17517,7 +17657,7 @@ SceneJS_ChunkFactory.createChunkType({ this.core2.indexBuf.bind(); } }); -/** +;/** * Create display state chunk type for draw render of lights projection */ SceneJS_ChunkFactory.createChunkType({ @@ -17542,20 +17682,20 @@ SceneJS_ChunkFactory.createChunkType({ switch (lights[i].mode) { case "ambient": - this._uAmbientColor[i] = (program.draw.getUniformLocation("SCENEJS_uAmbientColor")); + this._uAmbientColor[i] = (program.draw.getUniform("SCENEJS_uAmbientColor")); break; case "dir": - this._uLightColor[i] = program.draw.getUniformLocation("SCENEJS_uLightColor" + i); + this._uLightColor[i] = program.draw.getUniform("SCENEJS_uLightColor" + i); this._uLightPos[i] = null; - this._uLightDir[i] = program.draw.getUniformLocation("SCENEJS_uLightDir" + i); + this._uLightDir[i] = program.draw.getUniform("SCENEJS_uLightDir" + i); break; case "point": - this._uLightColor[i] = program.draw.getUniformLocation("SCENEJS_uLightColor" + i); - this._uLightPos[i] = program.draw.getUniformLocation("SCENEJS_uLightPos" + i); + this._uLightColor[i] = program.draw.getUniform("SCENEJS_uLightColor" + i); + this._uLightPos[i] = program.draw.getUniform("SCENEJS_uLightPos" + i); this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.draw.getUniformLocation("SCENEJS_uLightAttenuation" + i); + this._uLightAttenuation[i] = program.draw.getUniform("SCENEJS_uLightAttenuation" + i); break; } } @@ -17577,29 +17717,29 @@ SceneJS_ChunkFactory.createChunkType({ light = lights[i]; if (this._uAmbientColor[i]) { - gl.uniform3fv(this._uAmbientColor[i], light.color); + this._uAmbientColor[i].setValue(light.color); } else { if (this._uLightColor[i]) { - gl.uniform3fv(this._uLightColor[i], light.color); + this._uLightColor[i].setValue(light.color); } if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); + this._uLightPos[i].setValue(light.pos); if (this._uLightAttenuation[i]) { - gl.uniform3fv(this._uLightAttenuation[i], light.attenuation); + this._uLightAttenuation[i].setValue(light.attenuation); } } if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); + this._uLightDir[i].setValue(light.dir); } } } } -});/** +});;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17623,7 +17763,7 @@ SceneJS_ChunkFactory.createChunkType({ } } } -});/** +});;/** * Create display state chunk type for draw and pick render of lookAt transform */ SceneJS_ChunkFactory.createChunkType({ @@ -17632,11 +17772,11 @@ SceneJS_ChunkFactory.createChunkType({ build : function() { - this._uvMatrixDraw = this.program.draw.getUniformLocation("SCENEJS_uVMatrix"); - this._uVNMatrixDraw = this.program.draw.getUniformLocation("SCENEJS_uVNMatrix"); - this._uWorldEyeDraw = this.program.draw.getUniformLocation("SCENEJS_uWorldEye"); + this._uvMatrixDraw = this.program.draw.getUniform("SCENEJS_uVMatrix"); + this._uVNMatrixDraw = this.program.draw.getUniform("SCENEJS_uVNMatrix"); + this._uWorldEyeDraw = this.program.draw.getUniform("SCENEJS_uWorldEye"); - this._uvMatrixPick = this.program.pick.getUniformLocation("SCENEJS_uVMatrix"); + this._uvMatrixPick = this.program.pick.getUniform("SCENEJS_uVMatrix"); }, draw : function(frameCtx) { @@ -17648,15 +17788,15 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uvMatrixDraw) { - gl.uniformMatrix4fv(this._uvMatrixDraw, gl.FALSE, this.core.mat); + this._uvMatrixDraw.setValue(this.core.mat); } if (this._uVNMatrixDraw) { - gl.uniformMatrix4fv(this._uVNMatrixDraw, gl.FALSE, this.core.normalMat); + this._uVNMatrixDraw.setValue(this.core.normalMat); } if (this._uWorldEyeDraw) { - gl.uniform3fv(this._uWorldEyeDraw, this.core.lookAt.eye); + this._uWorldEyeDraw.setValue(this.core.lookAt.eye); } frameCtx.viewMat = this.core.mat; @@ -17667,82 +17807,71 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uvMatrixPick) { - gl.uniformMatrix4fv(this._uvMatrixPick, gl.FALSE, this.core.mat); + this._uvMatrixPick.setValue(this.core.mat); } frameCtx.viewMat = this.core.mat; } -});/** +});;/** * Create display state chunk type for draw render of material transform */ SceneJS_ChunkFactory.createChunkType({ type: "material", - build : function() { + build: function () { var draw = this.program.draw; - this._uMaterialBaseColor = draw.getUniformLocation("SCENEJS_uMaterialColor"); - this._uMaterialSpecularColor = draw.getUniformLocation("SCENEJS_uMaterialSpecularColor"); - this._uMaterialSpecular = draw.getUniformLocation("SCENEJS_uMaterialSpecular"); - this._uMaterialShine = draw.getUniformLocation("SCENEJS_uMaterialShine"); - this._uMaterialEmit = draw.getUniformLocation("SCENEJS_uMaterialEmit"); - this._uMaterialAlpha = draw.getUniformLocation("SCENEJS_uMaterialAlpha"); + this._uMaterialBaseColor = draw.getUniform("SCENEJS_uMaterialColor"); + this._uMaterialSpecularColor = draw.getUniform("SCENEJS_uMaterialSpecularColor"); + this._uMaterialSpecular = draw.getUniform("SCENEJS_uMaterialSpecular"); + this._uMaterialShine = draw.getUniform("SCENEJS_uMaterialShine"); + this._uMaterialEmit = draw.getUniform("SCENEJS_uMaterialEmit"); + this._uMaterialAlpha = draw.getUniform("SCENEJS_uMaterialAlpha"); }, - draw : function() { + draw: function () { var gl = this.program.gl; - var materialSettings = this.program.draw.materialSettings; if (this._uMaterialBaseColor) { - gl.uniform3fv(this._uMaterialBaseColor, this.core.baseColor); + this._uMaterialBaseColor.setValue(this.core.baseColor); } - if (this._uMaterialSpecularColor && - (materialSettings.specularColor[0] != this.core.specularColor[0] || - materialSettings.specularColor[1] != this.core.specularColor[1] || - materialSettings.specularColor[2] != this.core.specularColor[2])) { - gl.uniform3fv(this._uMaterialSpecularColor, this.core.specularColor); - materialSettings.specularColor[0] = this.core.specularColor[0]; - materialSettings.specularColor[1] = this.core.specularColor[1]; - materialSettings.specularColor[2] = this.core.specularColor[2]; + if (this._uMaterialSpecularColor) { + this._uMaterialSpecularColor.setValue(this.core.specularColor); } - if (this._uMaterialSpecular && materialSettings.specular != this.core.specular) { - gl.uniform1f(this._uMaterialSpecular, this.core.specular); - materialSettings.specular = this.core.specular; + if (this._uMaterialSpecular) { + this._uMaterialSpecular.setValue(this.core.specular); } - if (this._uMaterialShine && materialSettings.shine != this.core.shine) { - gl.uniform1f(this._uMaterialShine, this.core.shine); - materialSettings.shine = this.core.shine; + if (this._uMaterialShine) { + this._uMaterialShine.setValue(this.core.shine); } - if (this._uMaterialEmit && materialSettings.emit != this.core.emit) { - gl.uniform1f(this._uMaterialEmit, this.core.emit); - materialSettings.emit = this.core.emit; + if (this._uMaterialEmit) { + this._uMaterialEmit.setValue(this.core.emit); } - if (this._uMaterialAlpha && materialSettings.alpha != this.core.alpha) { - gl.uniform1f(this._uMaterialAlpha, this.core.alpha); - materialSettings.alpha = this.core.alpha; + if (this._uMaterialAlpha) { + this._uMaterialAlpha.setValue(this.core.alpha); } } }); -/** +;/** * Create display state chunk type for draw render of material transform */ SceneJS_ChunkFactory.createChunkType({ type: "name", - build : function() { - this._uPickColor = this.program.pick.getUniformLocation("SCENEJS_uPickColor"); + build: function () { + this._uPickColor = this.program.pick.getUniform("SCENEJS_uPickColor"); }, - pick : function(frameCtx) { + pick: function (frameCtx) { if (this._uPickColor && this.core.name) { @@ -17752,19 +17881,19 @@ SceneJS_ChunkFactory.createChunkType({ var g = frameCtx.pickIndex >> 8 & 0xFF; var r = frameCtx.pickIndex & 0xFF; - this.program.gl.uniform3fv(this._uPickColor, [r / 255, g / 255, b / 255]); + this._uPickColor.setValue([r / 255, g / 255, b / 255]); } } -});SceneJS_ChunkFactory.createChunkType({ +});;SceneJS_ChunkFactory.createChunkType({ type: "program", build : function() { // Note that "program" chunks are always after "renderTarget" chunks - this._depthModeDraw = this.program.draw.getUniformLocation("SCENEJS_uDepthMode"); - this._depthModePick = this.program.pick.getUniformLocation("SCENEJS_uDepthMode"); - this._rayPickMode = this.program.pick.getUniformLocation("SCENEJS_uRayPickMode"); + this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); + this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); + this._rayPickMode = this.program.pick.getUniform("SCENEJS_uRayPickMode"); }, draw : function(frameCtx) { @@ -17772,7 +17901,9 @@ SceneJS_ChunkFactory.createChunkType({ drawProgram.bind(); frameCtx.textureUnit = 0; var gl = this.program.gl; - gl.uniform1i(this._depthModeDraw, frameCtx.depthMode); + if (this._depthModeDraw) { + this._depthModeDraw.setValue(frameCtx.depthMode); + } if (!frameCtx.VAO) { for (var i = 0; i < 10; i++) { gl.disableVertexAttribArray(i); @@ -17786,8 +17917,12 @@ SceneJS_ChunkFactory.createChunkType({ var pickProgram = this.program.pick; pickProgram.bind(); var gl = this.program.gl; - gl.uniform1i(this._rayPickMode, frameCtx.rayPick); - gl.uniform1i(this._depthModePick, frameCtx.depthMode); + if (this._rayPickMode) { + this._rayPickMode.setValue(frameCtx.rayPick); + } + if (this._depthModePick) { + this._depthModePick.setValue(frameCtx.depthMode); + } frameCtx.textureUnit = 0; for (var i = 0; i < 10; i++) { gl.disableVertexAttribArray(i); @@ -17797,7 +17932,7 @@ SceneJS_ChunkFactory.createChunkType({ -/** +;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17819,7 +17954,7 @@ SceneJS_ChunkFactory.createChunkType({ } } }); -/** +;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17863,7 +17998,7 @@ SceneJS_ChunkFactory.createChunkType({ } } }); -/** +;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17898,7 +18033,7 @@ SceneJS_ChunkFactory.createChunkType({ } } }); -/** +;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17926,7 +18061,7 @@ SceneJS_ChunkFactory.createChunkType({ } } }); -/** +;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17956,7 +18091,7 @@ SceneJS_ChunkFactory.createChunkType({ } } } -});/** +});;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -17986,7 +18121,7 @@ SceneJS_ChunkFactory.createChunkType({ } } } -});/** +});;/** * */ SceneJS_ChunkFactory.createChunkType({ @@ -18007,7 +18142,7 @@ SceneJS_ChunkFactory.createChunkType({ } } }); -SceneJS_ChunkFactory.createChunkType({ +;SceneJS_ChunkFactory.createChunkType({ type: "texture", @@ -18078,7 +18213,7 @@ SceneJS_ChunkFactory.createChunkType({ frameCtx.textureUnit = 0; } } -});SceneJS_ChunkFactory.createChunkType({ +});;SceneJS_ChunkFactory.createChunkType({ type: "cubemap", @@ -18117,23 +18252,23 @@ SceneJS_ChunkFactory.createChunkType({ frameCtx.textureUnit = 0; } } -});SceneJS_ChunkFactory.createChunkType({ +});;SceneJS_ChunkFactory.createChunkType({ type: "xform", - build : function() { + build: function () { var draw = this.program.draw; - this._uMatLocationDraw = draw.getUniformLocation("SCENEJS_uMMatrix"); - this._uNormalMatLocationDraw = draw.getUniformLocation("SCENEJS_uMNMatrix"); + this._uMatLocationDraw = draw.getUniform("SCENEJS_uMMatrix"); + this._uNormalMatLocationDraw = draw.getUniform("SCENEJS_uMNMatrix"); var pick = this.program.pick; - this._uMatLocationPick = pick.getUniformLocation("SCENEJS_uMMatrix"); + this._uMatLocationPick = pick.getUniform("SCENEJS_uMMatrix"); }, - draw : function(frameCtx) { + draw: function (frameCtx) { /* Rebuild core's matrix from matrices at cores on path up to root */ @@ -18144,17 +18279,17 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uMatLocationDraw) { - gl.uniformMatrix4fv(this._uMatLocationDraw, gl.FALSE, this.core.mat); + this._uMatLocationDraw.setValue(this.core.mat); } if (this._uNormalMatLocationDraw) { - gl.uniformMatrix4fv(this._uNormalMatLocationDraw, gl.FALSE, this.core.normalMat); + this._uNormalMatLocationDraw.setValue(this.core.normalMat); } frameCtx.modelMat = this.core.mat; }, - pick : function(frameCtx) { + pick: function (frameCtx) { /* Rebuild core's matrix from matrices at cores on path up to root */ @@ -18165,10 +18300,9 @@ SceneJS_ChunkFactory.createChunkType({ var gl = this.program.gl; if (this._uMatLocationPick) { - gl.uniformMatrix4fv(this._uMatLocationPick, gl.FALSE, this.core.mat); + this._uMatLocationPick.setValue(this.core.mat); } frameCtx.modelMat = this.core.mat; } }); -SceneJS.configure({ pluginPath: "http://scenejs.org/api/latest/plugins" }); \ No newline at end of file diff --git a/api/latest/scenejs.min.js b/api/latest/scenejs.min.js new file mode 100644 index 00000000..5db1ccc7 --- /dev/null +++ b/api/latest/scenejs.min.js @@ -0,0 +1,22 @@ +/* + * SceneJS V4.2.0 + * + * A WebGL-based 3D scene graph from xeoLabs + * http://scenejs.org/ + * + * Built on 2015-06-10 + * + * MIT License + * Copyright 2015, Lindsay Kay + * http://xeolabs.com/ + * + */ + +if(void 0===require){var requirejs,require,define;!function(ba){function J(a){return"[object Function]"===N.call(a)}function K(a){return"[object Array]"===N.call(a)}function z(a,b){if(a){var c;for(c=0;c-1&&(!a[c]||!b(a[c],c,a));c-=1);}}function t(a,b){return ha.call(a,b)}function m(a,b){return t(a,b)&&a[b]}function H(a,b){for(var c in a)if(t(a,c)&&b(a[c],c))break}function S(a,b,c,d){return b&&H(b,function(b,e){(c||!t(a,e))&&(d&&"string"!=typeof b?(a[e]||(a[e]={}),S(a[e],b,c,d)):a[e]=b)}),a}function v(a,b){return function(){return b.apply(a,arguments)}}function ca(a){throw a}function da(a){if(!a)return a;var b=ba;return z(a.split("."),function(a){b=b[a]}),b}function B(a,b,c,d){return b=Error(b+"\nhttp://requirejs.org/docs/errors.html#"+a),b.requireType=a,b.requireModules=d,c&&(b.originalError=c),b}function ia(a){function b(a,b,c){var d,e,f,g,h,i,j,k=b&&b.split("/");d=k;var l=C.map,n=l&&l["*"];if(a&&"."===a.charAt(0))if(b){for(d=m(C.pkgs,b)?k=[b]:k.slice(0,k.length-1),b=a=d.concat(a.split("/")),d=0;b[d];d+=1)if(e=b[d],"."===e)b.splice(d,1),d-=1;else if(".."===e){if(1===d&&(".."===b[2]||".."===b[0]))break;d>0&&(b.splice(d-1,2),d-=2)}d=m(C.pkgs,b=a[0]),a=a.join("/"),d&&a===b+"/"+d.main&&(a=b)}else 0===a.indexOf("./")&&(a=a.substring(2));if(c&&l&&(k||n)){for(b=a.split("/"),d=b.length;d>0;d-=1){if(f=b.slice(0,d).join("/"),k)for(e=k.length;e>0;e-=1)if((c=m(l,k.slice(0,e).join("/")))&&(c=m(c,f))){g=c,h=d;break}if(g)break;!i&&n&&m(n,f)&&(i=m(n,f),j=d)}!g&&i&&(g=i,h=j),g&&(b.splice(0,h,g),a=b.join("/"))}return a}function c(a){A&&z(document.getElementsByTagName("script"),function(b){return b.getAttribute("data-requiremodule")===a&&b.getAttribute("data-requirecontext")===w.contextName?(b.parentNode.removeChild(b),!0):void 0})}function d(a){var b=m(C.paths,a);return b&&K(b)&&1-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function f(a,c,d,f){var g,h,i=null,j=c?c.name:null,k=a,l=!0,n="";return a||(l=!1,a="_@r"+(M+=1)),a=e(a),i=a[0],a=a[1],i&&(i=b(i,j,f),h=m(I,i)),a&&(i?n=h&&h.normalize?h.normalize(a,function(a){return b(a,j,f)}):b(a,j,f):(n=b(a,j,f),a=e(n),i=a[0],n=a[1],d=!0,g=w.nameToUrl(n))),d=!i||h||d?"":"_unnormalized"+(N+=1),{prefix:i,name:n,parentMap:c,unnormalized:!!d,url:g,originalName:k,isDefine:l,id:(i?i+"!"+n:n)+d}}function g(a){var b=a.id,c=m(D,b);return c||(c=D[b]=new w.Module(a)),c}function i(a,b,c){var d=a.id,e=m(D,d);!t(I,d)||e&&!e.defineEmitComplete?(e=g(a),e.error&&"error"===b?c(e.error):e.on(b,c)):"defined"===b&&c(I[d])}function j(a,b){var c=a.requireModules,d=!1;b?b(a):(z(c,function(b){(b=m(D,b))&&(b.error=a,b.events.error&&(d=!0,b.emit("error",a)))}),d||h.onError(a))}function k(){U.length&&(ja.apply(G,[G.length-1,0].concat(U)),U=[])}function l(a){delete D[a],delete E[a]}function n(a,b,c){var d=a.map.id;a.error?a.emit("error",a.error):(b[d]=!0,z(a.depMaps,function(d,e){var f=d.id,g=m(D,f);g&&!a.depMatched[e]&&!c[f]&&(m(b,f)?(a.defineDep(e,I[f]),a.check()):n(g,b,c))}),c[d]=!0)}function o(){var a,b,e,f,g=(e=1e3*C.waitSeconds)&&w.startTime+e<(new Date).getTime(),h=[],i=[],k=!1,l=!0;if(!s){if(s=!0,H(E,function(e){if(a=e.map,b=a.id,e.enabled&&(a.isDefine||i.push(e),!e.error))if(!e.inited&&g)d(b)?k=f=!0:(h.push(b),c(b));else if(!e.inited&&e.fetched&&a.isDefine&&(k=!0,!a.prefix))return l=!1}),g&&h.length)return e=B("timeout","Load timeout for modules: "+h,null,h),e.contextName=w.contextName,j(e);l&&z(i,function(a){n(a,{},{})}),g&&!f||!k||!A&&!ea||y||(y=setTimeout(function(){y=0,o()},50)),s=!1}}function p(a){t(I,a[0])||g(f(a[0],null,!0)).init(a[1],a[2])}function q(a){var a=a.currentTarget||a.srcElement,b=w.onScriptLoad;return a.detachEvent&&!Z?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1),b=w.onScriptError,(!a.detachEvent||Z)&&a.removeEventListener("error",b,!1),{node:a,id:a&&a.getAttribute("data-requiremodule")}}function r(){var a;for(k();G.length;){if(a=G.shift(),null===a[0])return j(B("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));p(a)}}var s,u,w,x,y,C={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{},config:{}},D={},E={},F={},G=[],I={},L={},M=1,N=1;return x={require:function(a){return a.require?a.require:a.require=w.makeRequire(a.map)},exports:function(a){return a.usingExports=!0,a.map.isDefine?a.exports?a.exports:a.exports=I[a.map.id]={}:void 0},module:function(a){return a.module?a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){var b=m(C.pkgs,a.map.id);return(b?m(C.config,a.map.id+"/"+b.main):m(C.config,a.map.id))||{}},exports:I[a.map.id]}}},u=function(a){this.events=m(F,a.id)||{},this.map=a,this.shim=m(C.shim,a.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0},u.prototype={init:function(a,b,c,d){d=d||{},this.inited||(this.factory=b,c?this.on("error",c):this.events.error&&(c=v(this,function(a){this.emit("error",a)})),this.depMaps=a&&a.slice(0),this.errback=c,this.inited=!0,this.ignore=d.ignore,d.enabled||this.enabled?this.enable():this.check())},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0,w.startTime=(new Date).getTime();var a=this.map;if(!this.shim)return a.prefix?this.callPlugin():this.load();w.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],v(this,function(){return a.prefix?this.callPlugin():this.load()}))}},load:function(){var a=this.map.url;L[a]||(L[a]=!0,w.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var d=this.exports,e=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,1>this.depCount&&!this.defined){if(J(e)){if(this.events.error&&this.map.isDefine||h.onError!==ca)try{d=w.execCb(c,e,b,d)}catch(f){a=f}else d=w.execCb(c,e,b,d);if(this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?d=b.exports:void 0===d&&this.usingExports&&(d=this.exports)),a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",j(this.error=a)}else d=e;this.exports=d,this.map.isDefine&&!this.ignore&&(I[c]=d,h.onResourceLoad)&&h.onResourceLoad(w,this.map,this.depMaps),l(c),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,c=a.id,d=f(a.prefix);this.depMaps.push(d),i(d,"defined",v(this,function(d){var e,k;k=this.map.name;var n=this.map.parentMap?this.map.parentMap.name:null,o=w.makeRequire(a.parentMap,{enableBuildCallback:!0});this.map.unnormalized?(d.normalize&&(k=d.normalize(k,function(a){return b(a,n,!0)})||""),d=f(a.prefix+"!"+k,this.map.parentMap),i(d,"defined",v(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),(k=m(D,d.id))&&(this.depMaps.push(d),this.events.error&&k.on("error",v(this,function(a){this.emit("error",a)})),k.enable())):(e=v(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),e.error=v(this,function(a){this.inited=!0,this.error=a,a.requireModules=[c],H(D,function(a){0===a.map.id.indexOf(c+"_unnormalized")&&l(a.map.id)}),j(a)}),e.fromText=v(this,function(b,d){var i=a.name,k=f(i),l=Q;d&&(b=d),l&&(Q=!1),g(k),t(C.config,c)&&(C.config[i]=C.config[c]);try{h.exec(b)}catch(m){return j(B("fromtexteval","fromText eval for "+c+" failed: "+m,m,[c]))}l&&(Q=!0),this.depMaps.push(k),w.completeLoad(i),o([i],e)}),d.load(a.name,o,e,C))})),w.enable(d,this),this.pluginMaps[d.id]=d},enable:function(){E[this.map.id]=this,this.enabling=this.enabled=!0,z(this.depMaps,v(this,function(a,b){var c,d;if("string"==typeof a){if(a=f(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[b]=a,c=m(x,a.id))return void(this.depExports[b]=c(this));this.depCount+=1,i(a,"defined",v(this,function(a){this.defineDep(b,a),this.check()})),this.errback&&i(a,"error",v(this,this.errback))}c=a.id,d=D[c],!t(x,c)&&d&&!d.enabled&&w.enable(a,this)})),H(this.pluginMaps,v(this,function(a){var b=m(D,a.id);b&&!b.enabled&&w.enable(a,this)})),this.enabling=!1,this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]),c.push(b)},emit:function(a,b){z(this.events[a],function(a){a(b)}),"error"===a&&delete this.events[a]}},w={config:C,contextName:a,registry:D,defined:I,urlFetched:L,defQueue:G,Module:u,makeModuleMap:f,nextTick:h.nextTick,onError:j,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=C.pkgs,c=C.shim,d={paths:!0,config:!0,map:!0};H(a,function(a,b){d[b]?"map"===b?(C.map||(C.map={}),S(C[b],a,!0,!0)):S(C[b],a,!0):C[b]=a}),a.shim&&(H(a.shim,function(a,b){K(a)&&(a={deps:a}),!a.exports&&!a.init||a.exportsFn||(a.exportsFn=w.makeShimExports(a)),c[b]=a}),C.shim=c),a.packages&&(z(a.packages,function(a){a="string"==typeof a?{name:a}:a,b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(fa,"")}}),C.pkgs=b),H(D,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=f(b))}),(a.deps||a.callback)&&w.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;return a.init&&(b=a.init.apply(ba,arguments)),b||a.exports&&da(a.exports)}},makeRequire:function(c,d){function e(b,i,k){var l,m;return d.enableBuildCallback&&i&&J(i)&&(i.__requireJsBuild=!0),"string"==typeof b?J(i)?j(B("requireargs","Invalid require call"),k):c&&t(x,b)?x[b](D[c.id]):h.get?h.get(w,b,c,e):(l=f(b,c,!1,!0),l=l.id,t(I,l)?I[l]:j(B("notloaded",'Module name "'+l+'" has not been loaded yet for context: '+a+(c?"":". Use require([])")))):(r(),w.nextTick(function(){r(),m=g(f(null,c)),m.skipMap=d.skipMap,m.init(b,i,k,{enabled:!0}),o()}),e)}return d=d||{},S(e,{isBrowser:A,toUrl:function(a){var d,e=a.lastIndexOf("."),f=a.split("/")[0];return-1!==e&&("."!==f&&".."!==f||e>1)&&(d=a.substring(e,a.length),a=a.substring(0,e)),w.nameToUrl(b(a,c&&c.id,!0),d,!0)},defined:function(a){return t(I,f(a,c,!1,!0).id)},specified:function(a){return a=f(a,c,!1,!0).id,t(I,a)||t(D,a)}}),c||(e.undef=function(a){k();var b=f(a,c,!0),d=m(D,a);delete I[a],delete L[b.url],delete F[a],d&&(d.events.defined&&(F[a]=d.events),l(a))}),e},enable:function(a){m(D,a.id)&&g(a).enable()},completeLoad:function(a){var b,c,e=m(C.shim,a)||{},f=e.exports;for(k();G.length;){if(c=G.shift(),null===c[0]){if(c[0]=a,b)break;b=!0}else c[0]===a&&(b=!0);p(c)}if(c=m(D,a),!b&&!t(I,a)&&c&&!c.inited){if(C.enforceDefine&&(!f||!da(f)))return d(a)?void 0:j(B("nodefine","No define call for "+a,null,[a]));p([a,e.deps||[],e.exportsFn])}o()},nameToUrl:function(a,b,c){var d,e,f,g,i,j;if(h.jsExtRegExp.test(a))g=a+(b||"");else{for(d=C.paths,e=C.pkgs,g=a.split("/"),i=g.length;i>0;i-=1){if(j=g.slice(0,i).join("/"),f=m(e,j),j=m(d,j)){K(j)&&(j=j[0]),g.splice(0,i,j);break}if(f){a=a===f.name?f.location+"/"+f.main:f.location,g.splice(0,i,a);break}}g=g.join("/"),g+=b||(/\?/.test(g)||c?"":".js"),g=("/"===g.charAt(0)||g.match(/^[\w\+\.\-]+:/)?"":C.baseUrl)+g}return C.urlArgs?g+((-1===g.indexOf("?")?"?":"&")+C.urlArgs):g},load:function(a,b){h.load(w,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){("load"===a.type||la.test((a.currentTarget||a.srcElement).readyState))&&(R=null,a=q(a),w.completeLoad(a.id))},onScriptError:function(a){var b=q(a);return d(b.id)?void 0:j(B("scripterror","Script error for: "+b.id,a,[b.id]))}},w.require=w.makeRequire(),w}var h,x,y,E,L,F,R,M,s,ga,ma=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/gm,na=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,fa=/\.js$/,ka=/^\.\//;x=Object.prototype;var N=x.toString,ha=x.hasOwnProperty,ja=Array.prototype.splice,A=!("undefined"==typeof window||!navigator||!window.document),ea=!A&&"undefined"!=typeof importScripts,la=A&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,Z="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),G={},u={},U=[],Q=!1;if("undefined"==typeof define){if("undefined"!=typeof requirejs){if(J(requirejs))return;u=requirejs,requirejs=void 0}"undefined"!=typeof require&&!J(require)&&(u=require,require=void 0),h=requirejs=function(a,b,c,d){var e,f="_";return!K(a)&&"string"!=typeof a&&(e=a,K(b)?(a=b,b=c,c=d):a=[]),e&&e.context&&(f=e.context),(d=m(G,f))||(d=G[f]=h.s.newContext(f)),e&&d.configure(e),d.require(a,b,c)},h.config=function(a){return h(a)},h.nextTick="undefined"!=typeof setTimeout?function(a){setTimeout(a,4)}:function(a){a()},require||(require=h),h.version="2.1.6",h.jsExtRegExp=/^\/|:|\?|\.js$/,h.isBrowser=A,x=h.s={contexts:G,newContext:ia},h({}),z(["toUrl","undef","defined","specified"],function(a){h[a]=function(){var b=G._;return b.require[a].apply(b,arguments)}}),A&&(y=x.head=document.getElementsByTagName("head")[0],E=document.getElementsByTagName("base")[0])&&(y=x.head=E.parentNode),h.onError=ca,h.load=function(a,b,c){var d,e=a&&a.config||{};if(A)return d=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),d.type=e.scriptType||"text/javascript",d.charset="utf-8",d.async=!0,d.setAttribute("data-requirecontext",a.contextName),d.setAttribute("data-requiremodule",b),!d.attachEvent||d.attachEvent.toString&&0>d.attachEvent.toString().indexOf("[native code")||Z?(d.addEventListener("load",a.onScriptLoad,!1),d.addEventListener("error",a.onScriptError,!1)):(Q=!0,d.attachEvent("onreadystatechange",a.onScriptLoad)),d.src=c,M=d,E?y.insertBefore(d,E):y.appendChild(d),M=null,d;if(ea)try{importScripts(c),a.completeLoad(b)}catch(f){a.onError(B("importscripts","importScripts failed for "+b+" at "+c,f,[b]))}},A&&O(document.getElementsByTagName("script"),function(a){return y||(y=a.parentNode),(L=a.getAttribute("data-main"))?(s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0):void 0}),define=function(a,b,c){var d,e;"string"!=typeof a&&(c=b,b=a,a=null),K(b)||(c=b,b=null),!b&&J(c)&&(b=[],c.length&&(c.toString().replace(ma,"").replace(na,function(a,c){b.push(c)}),b=(1===c.length?["require"]:["require","exports","module"]).concat(b))),Q&&((d=M)||(R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(a){return"interactive"===a.readyState?R=a:void 0}),d=R),d&&(a||(a=d.getAttribute("data-requiremodule")),e=G[d.getAttribute("data-requirecontext")])),(e?e.defQueue:U).push([a,b,c])},define.amd={jQuery:!0},h.exec=function(b){return eval(b)},h(u)}}(this)}WebGLDebugUtils=function(){function a(a){if(null==m){m={};for(var b in a)"number"==typeof a[b]&&(m[a[b]]=b)}}function b(){if(null==m)throw"WebGLDebugUtils.init(ctx) not called"}function c(a){return b(),void 0!==m[a]}function d(a){b();var c=m[a];return void 0!==c?c:"*UNKNOWN WebGL ENUM (0x"+a.toString(16)+")"}function e(a,b,c){var e=l[a];return void 0!==e&&e[b]?d(c):null===c?"null":void 0===c?"undefined":c.toString()}function f(a,b){for(var c="",d=0;dd;++d)a.disableVertexAttribArray(d),a.vertexAttribPointer(d,4,a.FLOAT,!1,0,0),a.vertexAttrib1f(d,0);a.deleteBuffer(c);for(var e=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),d=0;e>d;++d)a.activeTexture(a.TEXTURE0+d),a.bindTexture(a.TEXTURE_CUBE_MAP,null),a.bindTexture(a.TEXTURE_2D,null);for(a.activeTexture(a.TEXTURE0),a.useProgram(null),a.bindBuffer(a.ARRAY_BUFFER,null),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,null),a.bindFramebuffer(a.FRAMEBUFFER,null),a.bindRenderbuffer(a.RENDERBUFFER,null),a.disable(a.BLEND),a.disable(a.CULL_FACE),a.disable(a.DEPTH_TEST),a.disable(a.DITHER),a.disable(a.SCISSOR_TEST),a.blendColor(0,0,0,0),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ONE,a.ZERO),a.clearColor(0,0,0,0),a.clearDepth(1),a.clearStencil(-1),a.colorMask(!0,!0,!0,!0),a.cullFace(a.BACK),a.depthFunc(a.LESS),a.depthMask(!0),a.depthRange(0,1),a.frontFace(a.CCW),a.hint(a.GENERATE_MIPMAP_HINT,a.DONT_CARE),a.lineWidth(1),a.pixelStorei(a.PACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.pixelStorei(a.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),a.UNPACK_COLORSPACE_CONVERSION_WEBGL&&a.pixelStorei(a.UNPACK_COLORSPACE_CONVERSION_WEBGL,a.BROWSER_DEFAULT_WEBGL),a.polygonOffset(0,0),a.sampleCoverage(1,!1),a.scissor(0,0,a.canvas.width,a.canvas.height),a.stencilFunc(a.ALWAYS,0,4294967295),a.stencilMask(4294967295),a.stencilOp(a.KEEP,a.KEEP,a.KEEP),a.viewport(0,0,a.canvas.width,a.canvas.height),a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT|a.STENCIL_BUFFER_BIT);a.getError(););}function j(a){function b(a){return"function"==typeof a?a:function(b){a.handleEvent(b)}}function c(a){var b=a.addEventListener;a.addEventListener=function(c,d,e){switch(c){case"webglcontextlost":x(d);break;case"webglcontextrestored":y(d);break;default:b.apply(a,arguments)}}}function d(){for(var a=Object.keys(w),b=0;b=0&&setTimeout(function(){a.restoreContext()},v)},0)}},a.restoreContext=function(){q&&o.length&&setTimeout(function(){if(!u)throw"can not restore. webglcontestlost listener did not call event.preventDefault";h(),i(l),q=!1,t=0,u=!1;for(var a=o.slice(),b=j("context restored"),c=0;c0)return!1;if(0===b.length)return!0;for(var c in b)if(a.call(b,c))return!1;return!0},this.reset=function(){var a=[];for(var b in this._engines)this._engines.hasOwnProperty(b)&&(a.push(this._engines[b]),delete this._engines[b],this._engineIds.removeItem(b));for(;a.length>0;)a.pop().destroy();SceneJS_events.fireEvent(SceneJS_events.RESET)}};!function(){var a;SceneJS.on("configs",function(b){if(b.pluginPath!=a){a=b.pluginPath;var c=a+"/lib";require.config({paths:{scenejsPluginDeps:c}})}})}();var SceneJS_eventManager=function(){this._handlerIds=new SceneJS_Map,this.typeHandlers={}};SceneJS_eventManager.prototype.createEvent=function(a){this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0})},SceneJS_eventManager.prototype.onEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0}),d=this._handlerIds.addItem(a),e=c.handlers;return e[d]=b,c.numSubs++,d},SceneJS_eventManager.prototype.fireEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0});if(c.numSubs>0){var d=c.handlers;for(var e in d)d.hasOwnProperty(e)&&d[e](b)}},SceneJS_eventManager.prototype.unEvent=function(a){var b=this._handlerIds.items[a];if(b){this._handlerIds.removeItem(a);var c=this.typeHandlers[b];c&&(delete c[a],this.typeHandlers[b].numSubs--)}},SceneJS.Plugins=new function(){function a(a,c,f,g){var h=d[a]||(d[a]={});h[c]=g,b(f,0,function(){for(var b=a+c,d=e[b]||(e[b]=[]);d.length>0;)d.pop()(g);delete e[b]})}function b(a,d,e){if(!a||d>=a.length)return void e();var f=a[d],g=SceneJS_configsModule.configs.pluginPath;if(!g)throw"no pluginPath config";f=g+"/"+f,c(f,function(){b(a,d+1,e)})}function c(a,b){var c=document.createElement("script");c.type="text/javascript",c.readyState?c.onreadystatechange=function(){("loaded"==c.readyState||"complete"==c.readyState)&&(c.onreadystatechange=null,b&&b())}:c.onload=function(){b&&b()},c.src=a,document.getElementsByTagName("head")[0].appendChild(c)}var d={},e={};this.addPlugin=function(){var b,c,d=arguments[0],e=arguments[1];4==arguments.length?(b=arguments[2],c=arguments[3]):c=arguments[2],a(d,e,b,c)},this.hasPlugin=function(a,b){var c=d[a];return c&&!!c[b]},this.getPlugin=function(a,b,f){var g=d[a];if(g){var h=g[b];if(h)return void f(h)}var i=a+b,j=e[i]||(e[i]=[]);if(j.push(f),!(j.length>1)){var k=SceneJS_configsModule.configs.pluginPath;if(!k)throw"no pluginPath config";var l=k+"/"+a+"/"+b+".js";c(l)}}};var SceneJS_events=new function(){this.ERROR=0,this.RESET=1,this.NODE_CREATED=2,this.SCENE_CREATED=3,this.SCENE_COMPILING=4,this.SCENE_DESTROYED=5,this.OBJECT_COMPILING=6,this.WEBGL_CONTEXT_LOST=7,this.WEBGL_CONTEXT_RESTORED=8;var a=[];this.addListener=function(b,c,d){var e=a[b];e||(e=[],a[b]=e);for(var f={command:c,priority:void 0==d?e.length:d},g=-1,h=0,i=e.length;i>h;h++)if(!e[h]){g=h;break}0>g&&(e.push(f),g=e.length-1);var j=b+"."+g;return j},this.removeListener=function(b){var c=b.lastIndexOf("."),d=parseInt(b.substr(0,c)),e=parseInt(b.substr(c+1)),f=a[d];f&&delete f[e]},this.fireEvent=function(b,c){var d=a[b];if(d){c=c||{};for(var e=0;e',e.appendChild(f)}var h=document.getElementById(b);if(!h)throw SceneJS_error.fatalError(SceneJS.errors.CANVAS_NOT_FOUND,"SceneJS.Scene attribute 'canvasId' does not match any elements in the page");this.canvasId=b,this.options=d||{},this.canvas=this.options.simulateWebGLContextLost?WebGLDebugUtils.makeLostContextSimulatingCanvas(h):h,this.ssaaMultiplier=this.options.ssaaMultiplier||1,this.canvas.width=this.canvas.clientWidth*this.ssaaMultiplier,this.canvas.height=this.canvas.clientHeight*this.ssaaMultiplier,this.contextAttr=c,this.gl=null,this.initWebGL()};SceneJS_Canvas.prototype._WEBGL_CONTEXT_NAMES=["webgl","experimental-webgl","webkit-3d","moz-webgl","moz-glweb20"],SceneJS_Canvas.prototype.initWebGL=function(){for(var a=0;!this.gl&&af;f++)d.createNode(a.nodes[f],function(a){c.addNode(a),++e==g&&(b&&b(c),d.scene.publish("nodes/"+c.id,c))});else b&&(b(c),d.scene.publish("nodes/"+c.id,c))})},SceneJS_Engine.prototype._doDestroyNodes=function(){for(var a;this._numNodesToDestroy>0;)a=this._nodesToDestroy[--this._numNodesToDestroy],a._doDestroy(),this._coreFactory.putCore(a._core),this._nodeFactory.putNode(a)},SceneJS_Engine.prototype.findNode=function(a){return this._nodeFactory.nodes.items[a]},SceneJS_Engine.prototype.findNodes=function(a){var b=new RegExp(a),c=[],d=this._nodeFactory.nodes.items;for(var e in d)d.hasOwnProperty(e)&&b.test(e)&&c.push(d[e]);return c},SceneJS_Engine.prototype.hasCore=function(a,b){return this._coreFactory.hasCore(a,b)},SceneJS_Engine.prototype.branchDirty=function(a){if(!this.sceneDirty&&a!=window){a.branchDirty=!0,a.dirty=!0;for(var b=a.parent;b&&!b.dirty&&!b.branchDirty;b=b.parent)b.dirty=!0;this._sceneBranchesDirty=!0}},SceneJS_Engine.prototype.renderFrame=function(a){var b=!1;if(this._needCompile()||a&&a.force)for(var c=(new Date).getTime(),d=a&&a.force,e=0;e0?setTimeout(window[e],1e3/d.fps):requestAnimationFrame(window[e]))},setTimeout(window[e],0)}},SceneJS_Engine.prototype.pick=function(a,b,c){this._needCompile()&&this._doCompile();var d=this.display.pick({canvasX:a,canvasY:b,rayPick:c?c.rayPick:!1});return d},SceneJS_Engine.prototype.readPixels=function(a,b){return this._needCompile()&&this._doCompile(),this.display.readPixels(a,b)},SceneJS_Engine.prototype._needCompile=function(){return this.display.imageDirty||this.display.drawListDirty||this.display.stateSortDirty||this.display.stateOrderDirty||this.display.objectListDirty||this._sceneBranchesDirty||this.sceneDirty},SceneJS_Engine.prototype._doCompile=function(){if(this._sceneBranchesDirty||this.sceneDirty){this._sceneBranchesDirty=!1,SceneJS_events.fireEvent(SceneJS_events.SCENE_COMPILING,{engine:this}),this.pubSubProxy=new SceneJS_PubSubProxy(this.scene,null);var a={pubSubProxy:this.pubSubProxy};this.scene._compileNodes(a),this.sceneDirty=!1}this._doDestroyNodes()},SceneJS_Engine.prototype.pause=function(a){this.paused=a},SceneJS_Engine.prototype.stop=function(){this.running&&(this.running=!1,this.paused=!1,window["__scenejs_sceneLoop"+this.id]=null)},SceneJS_Engine.prototype.destroyNode=function(a){this._nodesToDestroy[this._numNodesToDestroy++]=a;var b=this.sceneStatus.nodes[a.id];b&&(this.sceneStatus.numTasks-=b.numTasks,delete this.sceneStatus.nodes[a.id])},SceneJS_Engine.prototype.destroy=function(){this.destroyed=!0},self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array),function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;ch;h++)i[h](g);SceneJS.publish("configs",this.configs)},this.getConfigs=function(a){if(a){for(var b=this.configs,c=a.split("."),d=0;b&&dc;c++)b.push("----");e=b.join("")},this.error=function(a){this._log("error",a)},this.warn=function(a){this._log("warn",a)},this.info=function(a){this._log("info",a)},this.debug=function(a){this._log("debug",a)},this.setFuncs=function(a){if(a){b=a;for(var d in c)this._flush(d)}},this._flush=function(a){var d=c[a];if(d){var e=b?b[a]:null;if(e){for(var f=0;fy;++y)f=b[y],c=f[0],d=f[1],e=f[2],g[y]=[i*c+m*d+q*e+u,j*c+n*d+r*e+v,k*c+o*d+s*e+w,l*c+p*d+t*e+x];return g},SceneJS_math_transformVector3=function(a,b){var c=b[0],d=b[1],e=b[2];return[a[0]*c+a[4]*d+a[8]*e,a[1]*c+a[5]*d+a[9]*e,a[2]*c+a[6]*d+a[10]*e]},SceneJS_math_transformVector4=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3];return[a[0]*c+a[4]*d+a[8]*e+a[12]*f,a[1]*c+a[5]*d+a[9]*e+a[13]*f,a[2]*c+a[6]*d+a[10]*e+a[14]*f,a[3]*c+a[7]*d+a[11]*e+a[15]*f]},SceneJS_math_projectVec4=function(a){var b=1/a[3];return[a[0]*b,a[1]*b,a[2]*b,1]},SceneJS_math_Plane3=function(a,b,c){if(this.normal=[0,0,1],this.offset=0,a&&b){var d=a[0],e=a[1],f=a[2];if(this.offset=b,c){var g=Math.sqrt(d*d+e*e+f*f);g>0&&(g=1/g,this.normal[0]=d*g,this.normal[1]=e*g,this.normal[2]=f*g,this.offset*=g)}}},SceneJS_math_MAX_DOUBLE=Number.POSITIVE_INFINITY,SceneJS_math_MIN_DOUBLE=Number.NEGATIVE_INFINITY,SceneJS_math_Box3=function(a,b){this.min=a||[SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE],this.max=b||[SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE],this.init=function(a,b){return this.min[0]=a[0],this.min[1]=a[1],this.min[2]=a[2],this.max[0]=b[0],this.max[1]=b[1],this.max[2]=b[2],this},this.fromPoints=function(a){for(var b=a.length,c=0;b>c;++c){var d=a[c][3],e=a[c][0]/d,f=a[c][1]/d,g=a[c][2]/d;ethis.max[0]&&(this.max[0]=e),f>this.max[1]&&(this.max[1]=f),g>this.max[2]&&(this.max[2]=g)}return this},this.isEmpty=function(){return this.min[0]>=this.max[0]&&this.min[1]>=this.max[1]&&this.min[2]>=this.max[2]},this.getCenter=function(){return[(this.max[0]+this.min[0])/2,(this.max[1]+this.min[1])/2,(this.max[2]+this.min[2])/2]},this.getSize=function(){return[this.max[0]-this.min[0],this.max[1]-this.min[1],this.max[2]-this.min[2]]},this.getFacesAreas=function(){var a=this.size;return[a[1]*a[2],a[0]*a[2],a[0]*a[1]]},this.getSurfaceArea=function(){var a=this.getFacesAreas();return 2*(a[0]+a[1]+a[2])},this.getVolume=function(){var a=this.size;return a[0]*a[1]*a[2]},this.getOffset=function(a){return this.min[0]-=a,this.min[1]-=a,this.min[2]-=a,this.max[0]+=a,this.max[1]+=a,this.max[2]+=a,this}},SceneJS_math_AxisBox3=function(a,b){var c=a[0],d=a[1],e=a[2],f=b[0],g=b[1],h=b[2];this.verts=[[c,d,e],[f,d,e],[f,g,e],[c,g,e],[c,d,h],[f,d,h],[f,g,h],[c,g,h]],this.toBox3=function(){for(var a=new SceneJS_math_Box3,b=0;8>b;++b)for(var c=this.verts[b],d=0;3>d;++d)c[d]a.max[d]&&(a.max[d]=c[d])}},SceneJS_math_Sphere3=function(a,b){this.center=[a[0],a[1],a[2]],this.radius=b,this.isEmpty=function(){return 0===this.radius},this.surfaceArea=function(){return 4*Math.PI*this.radius*this.radius},this.getVolume=function(){var a=this.radius;return 4/3*Math.PI*a*a*a}},SceneJS_math_billboardMat=function(a){var b=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],c=[SceneJS_math_lenVec4(b[0]),SceneJS_math_lenVec4(b[1]),SceneJS_math_lenVec4(b[2])],d=SceneJS_math_mat4();SceneJS_math_rcpVec3(c,d);var e=SceneJS_math_scalingMat4v(c);SceneJS_math_mulVec4Scalar(b[0],d[0]),SceneJS_math_mulVec4Scalar(b[1],d[1]),SceneJS_math_mulVec4Scalar(b[2],d[2]);var f=SceneJS_math_identityMat4();return SceneJS_math_setRowMat4(f,0,b[0]),SceneJS_math_setRowMat4(f,1,b[1]),SceneJS_math_setRowMat4(f,2,b[2]),SceneJS_math_mulMat4(f,e)},SceneJS_math_FrustumPlane=function(a,b,c,d){var e=1/Math.sqrt(a*a+b*b+c*c);this.normal=[a*e,b*e,c*e],this.offset=d*e,this.testVertex=[this.normal[0]>=0?1:0,this.normal[1]>=0?1:0,this.normal[2]>=0?1:0]},SceneJS_math_OUTSIDE_FRUSTUM=3,SceneJS_math_INTERSECT_FRUSTUM=4,SceneJS_math_INSIDE_FRUSTUM=5,SceneJS_math_Frustum=function(a,b,c){var d=SceneJS_math_mat4();SceneJS_math_mulMat4(b,a,d);var e=d[0],f=d[1],g=d[2],h=d[3],i=d[4],j=d[5],k=d[6],l=d[7],m=d[8],n=d[9],o=d[10],p=d[11],q=d[12],r=d[13],s=d[14],t=d[15],u=[new SceneJS_math_FrustumPlane(h-e,l-i,p-m,t-q),new SceneJS_math_FrustumPlane(h+e,l+i,p+m,t+q),new SceneJS_math_FrustumPlane(h-f,l-j,p-n,t-r),new SceneJS_math_FrustumPlane(h+f,l+j,p+n,t+r),new SceneJS_math_FrustumPlane(h-g,l-k,p-o,t-s),new SceneJS_math_FrustumPlane(h+g,l+k,p+o,t+s)],v=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],w=[SceneJS_math_lenVec4(v[0]),SceneJS_math_lenVec4(v[1]),SceneJS_math_lenVec4(v[2])],x=SceneJS_math_rcpVec3(w),y=SceneJS_math_scalingMat4v(w),z=SceneJS_math_scalingMat4v(x);SceneJS_math_mulVec4Scalar(v[0],x[0]),SceneJS_math_mulVec4Scalar(v[1],x[1]),SceneJS_math_mulVec4Scalar(v[2],x[2]);var A=SceneJS_math_identityMat4();SceneJS_math_setRowMat4(A,0,v[0]),SceneJS_math_setRowMat4(A,1,v[1]),SceneJS_math_setRowMat4(A,2,v[2]),this.matrix||(this.matrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(b,a,this.matrix),this.billboardMatrix||(this.billboardMatrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(z,SceneJS_math_mulMat4(A,y),this.billboardMatrix),this.viewport=c.slice(0,4),this.textAxisBoxIntersection=function(a){for(var b=SceneJS_math_INSIDE_FRUSTUM,c=[a.min,a.max],d=null,e=0;6>e;++e){if(d=u[e],d.normal[0]*c[d.testVertex[0]][0]+d.normal[1]*c[d.testVertex[1]][1]+d.normal[2]*c[d.testVertex[2]][2]+d.offset<0)return SceneJS_math_OUTSIDE_FRUSTUM;d.normal[0]*c[1-d.testVertex[0]][0]+d.normal[1]*c[1-d.testVertex[1]][1]+d.normal[2]*c[1-d.testVertex[2]][2]+d.offset<0&&(b=SceneJS_math_INTERSECT_FRUSTUM)}return b},this.getProjectedSize=function(a){var b=SceneJS_math_mat4();SceneJS_math_subVec3(a.max,a.min,b);var d=SceneJS_math_lenVec3(b),e=Math.abs(d),f=[.5*(a.min[0]+a.max[0]),.5*(a.min[1]+a.max[1]),.5*(a.min[2]+a.max[2]),0],g=.5*e,h=[-g,0,0,1],i=[g,0,0,1];return h=SceneJS_math_mulMat4v4(this.billboardMatrix,h),h=SceneJS_math_addVec4(h,f),h=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,h)),i=SceneJS_math_mulMat4v4(this.billboardMatrix,i),i=SceneJS_math_addVec4(i,f),i=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,i)),c[2]*Math.abs(i[0]-h[0])},this.getProjectedState=function(a){for(var b,d,e,f=SceneJS_math_transformPoints3(this.matrix,a),g=1e7,h=1e7,i=-1e7,j=-1e7,k=f.length,l=0;k>l;++l)b=SceneJS_math_projectVec4(f[l]),d=b[0],e=b[1],-.5>d&&(d=-.5),-.5>e&&(e=-.5),d>.5&&(d=.5),e>.5&&(e=.5),g>d&&(g=d),h>e&&(h=e),d>i&&(i=d),e>j&&(j=e);g+=.5,h+=.5,i+=.5,j+=.5;var m=c[2],n=c[3];g*=m+15,h*=n+15,i*=m+15,j*=n+15;var o=SceneJS_math_mat4();SceneJS_math_subVec2([i,j],[g,h],o);var p=SceneJS_math_lenVec2(o);return 0>g&&(g=0),i>m&&(i=m),0>h&&(h=0),j>n&&(j=n),{canvasBox:{min:[g,h],max:[i,j]},canvasSize:p}}},SceneJS_math_identityQuaternion=function(){return[0,0,0,1]},SceneJS_math_angleAxisQuaternion=function(a,b,c,d){var e=d/180*Math.PI,f=e/2,g=Math.sin(f);return[g*a,g*b,g*c,Math.cos(f)]},SceneJS_math_mulQuaternions=function(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=b[0],h=b[1],i=b[2],j=b[3];return[f*g+c*j+d*i-e*h,f*h+d*j+e*g-c*i,f*i+e*j+c*h-d*g,f*j-c*g-d*h-e*i]},SceneJS_math_newMat4FromQuaternion=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=2*b,g=2*c,h=2*d,i=f*e,j=g*e,k=h*e,l=f*b,m=g*b,n=h*b,o=g*c,p=h*c,q=h*d,r=SceneJS_math_identityMat4();return SceneJS_math_setCellMat4(r,0,0,1-(o+q)),SceneJS_math_setCellMat4(r,0,1,m-k),SceneJS_math_setCellMat4(r,0,2,n+j),SceneJS_math_setCellMat4(r,1,0,m+k),SceneJS_math_setCellMat4(r,1,1,1-(l+q)),SceneJS_math_setCellMat4(r,1,2,p-i),SceneJS_math_setCellMat4(r,2,0,n-j),SceneJS_math_setCellMat4(r,2,1,p+i),SceneJS_math_setCellMat4(r,2,2,1-(l+o)),r},SceneJS_math_slerp=function(a,b,c){var d=.0174532925*b[3],e=.0174532925*c[3],f=d*e+b[0]*c[0]+b[1]*c[1]+b[2]*c[2];if(Math.abs(f)>=1)return[b[0],b[1],b[2],b[3]];var g=Math.acos(f),h=Math.sqrt(1-f*f);if(Math.abs(h)<.001)return[.5*b[0]+.5*c[0],.5*b[1]+.5*c[1],.5*b[2]+.5*c[2],.5*b[3]+.5*c[3]];var i=Math.sin((1-a)*g)/h,j=Math.sin(a*g)/h;return[b[0]*i+c[0]*j,b[1]*i+c[1]*j,b[2]*i+c[2]*j,57.295779579*(d*i+e*j)]},SceneJS_math_normalizeQuaternion=function(a){var b=SceneJS_math_lenVec4([a[0],a[1],a[2],a[3]]);return[a[0]/b,a[1]/b,a[2]/b,a[3]/b]},SceneJS_math_conjugateQuaternion=function(a){return[-a[0],-a[1],-a[2],a[3]]},SceneJS_math_angleAxisFromQuaternion=function(a){a=SceneJS_math_normalizeQuaternion(a);var b=a[3],c=2*Math.acos(b),d=Math.sqrt(1-b*b);return.001>d?{x:a[0],y:a[1],z:a[2],angle:57.295779579*c}:{x:a[0]/d,y:a[1]/d,z:a[2]/d,angle:57.295779579*c}},SceneJS_sceneStatusModule=new function(){function a(a){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d=c.style;return d.position="absolute",d.width="200px",d.right="10px",d.top="0",d.padding="10px",d["z-index"]="10000",b.appendChild(c),c}function b(a,b){var c=document.createElement("div"),d=c.style;return d["font-family"]="Helvetica",d["font-size"]="14px",d.padding="5px",d.margin="4px",d["padding-left"]="12px",d.border="1px solid #000055",d.color="black",d.background="#AAAAAA",d.opacity="0.8",d["border-radius"]="3px",d["-moz-border-radius"]="3px",d["box-shadow"]="3px 3px 3px #444444",c.innerHTML=b,a.appendChild(c),c}function c(a){a.style.background="#AAFFAA";var b=.8,c=setInterval(function(){0>=b?(a.parentNode.removeChild(a),clearInterval(c)):(a.style.opacity=b,b-=.1)},100)}function d(a){a.style.background="#FFAAAA"}this.sceneStatus={};var e=new SceneJS_Map,f={},g={},h=this;SceneJS_events.addListener(SceneJS_events.SCENE_DESTROYED,function(a){var b=a.engine.id;delete h.sceneStatus[b],delete g[b]}),this.taskStarted=function(c,d){var h=SceneJS_configsModule.configs.statusPopups!==!1,i=c.getScene(),j=i.getId(),k=c.getId(),l=i.getCanvas(),m=e.addItem(),n=this.sceneStatus[j];n||(n=this.sceneStatus[j]={numTasks:0}),n.numTasks++;var o=g[j];o||(o=g[j]={sceneId:j,nodeStates:{},scene:i,popupContainer:h?a(l):null,descCounts:{}});var p=o.descCounts[d];void 0==p&&(p=o.descCounts[d]=0),o.descCounts[d]++;var q=o.nodeStates[k];q||(q=o.nodeStates[k]={nodeId:k,numTasks:0,tasks:{}}),d=d+" "+o.descCounts[d]+"...",q.numTasks++;var r={sceneState:o,nodeState:q,description:d,element:h?b(o.popupContainer,d):null};return q.tasks[m]=r,f[m]=r,m},this.taskFinished=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var d=b.sceneState;this.sceneStatus[d.sceneId].numTasks--,b.element&&c(b.element);var e=b.nodeState;return--e.numTasks<0&&(e.numTasks=0),delete e.tasks[a],0==e.numTasks&&delete d.nodeStates[e.nodeId],null},this.taskFailed=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var c=!!SceneJS_configsModule.configs.statusPopups,e=b.sceneState;this.sceneStatus[e.sceneId].numTasks--,c&&d(b.element);var g=b.nodeState;return g.numTasks--,delete g.tasks[a],0==g.numTasks&&delete b.sceneState.nodeStates[g.nodeId],null}};SceneJS._webgl={},SceneJS._webgl.ArrayBuffer=function(a,b,c,d,e,f){this.allocated=!1,this.gl=a,this.type=b, +this.numItems=d,this.itemSize=e,this.usage=f,this._allocate(c,d)},SceneJS._webgl.ArrayBuffer.prototype._allocate=function(a,b){if(this.allocated=!1,this.handle=this.gl.createBuffer(),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to allocate WebGL ArrayBuffer");this.handle&&(this.gl.bindBuffer(this.type,this.handle),this.gl.bufferData(this.type,a,this.usage),this.gl.bindBuffer(this.type,null),this.numItems=b,this.length=a.length,this.allocated=!0)},SceneJS._webgl.ArrayBuffer.prototype.setData=function(a,b){this.allocated&&(a.length>this.length?(this.destroy(),this._allocate(a,a.length)):b||0===b?this.gl.bufferSubData(this.type,b,a):this.gl.bufferData(this.type,a))},SceneJS._webgl.ArrayBuffer.prototype.unbind=function(){this.allocated&&this.gl.bindBuffer(this.type,null)},SceneJS._webgl.ArrayBuffer.prototype.destroy=function(){this.allocated&&(this.gl.deleteBuffer(this.handle),this.handle=null,this.allocated=!1)},SceneJS._webgl.ArrayBuffer.prototype.bind=function(){this.allocated&&this.gl.bindBuffer(this.type,this.handle)},SceneJS._webgl.Attribute=function(a,b,c,d,e,f){this.gl=a,this.location=f,this.bindFloatArrayBuffer=function(b){b&&(b.bind(),a.enableVertexAttribArray(f),a.vertexAttribPointer(f,b.itemSize,a.FLOAT,!1,0,0))}},SceneJS._webgl.Attribute.prototype.bindInterleavedFloatArrayBuffer=function(a,b,c){this.gl.enableVertexAttribArray(this.location),this.gl.vertexAttribPointer(this.location,a,this.gl.FLOAT,!1,b,c)},SceneJS._webgl.enumMap={funcAdd:"FUNC_ADD",funcSubtract:"FUNC_SUBTRACT",funcReverseSubtract:"FUNC_REVERSE_SUBTRACT",zero:"ZERO",one:"ONE",srcColor:"SRC_COLOR",oneMinusSrcColor:"ONE_MINUS_SRC_COLOR",dstColor:"DST_COLOR",oneMinusDstColor:"ONE_MINUS_DST_COLOR",srcAlpha:"SRC_ALPHA",oneMinusSrcAlpha:"ONE_MINUS_SRC_ALPHA",dstAlpha:"DST_ALPHA",oneMinusDstAlpha:"ONE_MINUS_DST_ALPHA",contantColor:"CONSTANT_COLOR",oneMinusConstantColor:"ONE_MINUS_CONSTANT_COLOR",constantAlpha:"CONSTANT_ALPHA",oneMinusConstantAlpha:"ONE_MINUS_CONSTANT_ALPHA",srcAlphaSaturate:"SRC_ALPHA_SATURATE",front:"FRONT",back:"BACK",frontAndBack:"FRONT_AND_BACK",never:"NEVER",less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL",always:"ALWAYS",cw:"CW",ccw:"CCW",linear:"LINEAR",nearest:"NEAREST",linearMipMapNearest:"LINEAR_MIPMAP_NEAREST",nearestMipMapNearest:"NEAREST_MIPMAP_NEAREST",nearestMipMapLinear:"NEAREST_MIPMAP_LINEAR",linearMipMapLinear:"LINEAR_MIPMAP_LINEAR",repeat:"REPEAT",clampToEdge:"CLAMP_TO_EDGE",mirroredRepeat:"MIRRORED_REPEAT",alpha:"ALPHA",rgb:"RGB",rgba:"RGBA",luminance:"LUMINANCE",luminanceAlpha:"LUMINANCE_ALPHA",textureBinding2D:"TEXTURE_BINDING_2D",textureBindingCubeMap:"TEXTURE_BINDING_CUBE_MAP",compareRToTexture:"COMPARE_R_TO_TEXTURE",unsignedByte:"UNSIGNED_BYTE"},SceneJS._webgl.RenderBuffer=function(a){this.allocated=!1,this.canvas=a.canvas,this.gl=a.canvas.gl,this.buf=null,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.webglRestored=function(a){this.gl=a,this.buf=null,this.allocated=!1,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.bind=function(){this._touch(),this.bound||(this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.bound=!0)},SceneJS._webgl.RenderBuffer.prototype._touch=function(){var a=this.canvas.canvas.width,b=this.canvas.canvas.height;if(this.buf){if(this.buf.width==a&&this.buf.height==b)return;this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf)}this.buf={framebuf:this.gl.createFramebuffer(),renderbuf:this.gl.createRenderbuffer(),texture:this.gl.createTexture(),width:a,height:b},this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.gl.bindTexture(this.gl.TEXTURE_2D,this.buf.texture),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE);try{this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,null)}catch(c){var d=new WebGLUnsignedByteArray(a*b*3);this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,d)}if(this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.DEPTH_COMPONENT16,a,b),this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER,this.gl.COLOR_ATTACHMENT0,this.gl.TEXTURE_2D,this.buf.texture,0),this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER,this.gl.DEPTH_ATTACHMENT,this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.bindTexture(this.gl.TEXTURE_2D,null),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),!this.gl.isFramebuffer(this.buf.framebuf))throw SceneJS_error.fatalError(SceneJS.errors.INVALID_FRAMEBUFFER,"Invalid framebuffer");var e=this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);switch(e){case this.gl.FRAMEBUFFER_COMPLETE:break;case this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");case this.gl.FRAMEBUFFER_UNSUPPORTED:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");default:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: "+e)}this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.clear=function(){if(!this.bound)throw"Render buffer not bound";this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT),this.gl.disable(this.gl.BLEND)},SceneJS._webgl.RenderBuffer.prototype.read=function(a,b){var c=a,d=this.canvas.canvas.height-b,e=new Uint8Array(4);return this.gl.readPixels(c,d,1,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),e},SceneJS._webgl.RenderBuffer.prototype.unbind=function(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.getTexture=function(){var a=this;return{bind:function(b){return a.buf&&a.buf.texture?(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,a.buf.texture),!0):!1},unbind:function(b){a.buf&&a.buf.texture&&(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,null))}}},SceneJS._webgl.RenderBuffer.prototype.destroy=function(){this.buf&&(this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf),this.buf=null,this.bound=!1)},SceneJS._webgl.Program=function(a,b,c){this.allocated=!1,this.gl=a,this._uniforms={},this._samplers={},this._attributes={},this.uniformValues=[],this.materialSettings={specularColor:[0,0,0],specular:0,shine:0,emit:0,alpha:0},this._shaders=[];var d,e,f,g,h,i;for(e=0;ee;++e)f=a.getActiveUniform(this.handle,e),f&&(g=f.name,"\x00"==g[g.length-1]&&(g=g.substr(0,g.length-1)),h=a.getUniformLocation(this.handle,g),f.type==a.SAMPLER_2D||f.type==a.SAMPLER_CUBE||35682==f.type?this._samplers[g]=new SceneJS._webgl.Sampler(a,this.handle,g,f.type,f.size,h):(this._uniforms[g]=new SceneJS._webgl.Uniform(a,this.handle,g,f.type,f.size,h,k),this.uniformValues[k]=null,++k));var l=a.getProgramParameter(this.handle,a.ACTIVE_ATTRIBUTES);for(e=0;l>e;e++)d=a.getActiveAttrib(this.handle,e),d&&(h=a.getAttribLocation(this.handle,d.name),this._attributes[d.name]=new SceneJS._webgl.Attribute(a,this.handle,d.name,d.type,d.size,h));this.allocated=!0}},SceneJS._webgl.Program.prototype.bind=function(){this.allocated&&this.gl.useProgram(this.handle)},SceneJS._webgl.Program.prototype.getUniformLocation=function(a){if(this.allocated){var b=this._uniforms[a];return b?b.getLocation():void 0}},SceneJS._webgl.Program.prototype.getUniform=function(a){if(this.allocated){var b=this._uniforms[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.getAttribute=function(a){if(this.allocated){var b=this._attributes[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.bindFloatArrayBuffer=function(a,b){if(this.allocated){var c=this._attributes[a];c&&c.bindFloatArrayBuffer(b)}},SceneJS._webgl.Program.prototype.bindTexture=function(a,b,c){if(!this.allocated)return!1;var d=this._samplers[a];return d?d.bindTexture(b,c):!1},SceneJS._webgl.Program.prototype.destroy=function(){if(this.allocated){this.gl.deleteProgram(this.handle);for(var a in this._shaders)this.gl.deleteShader(this._shaders[a].handle);this.handle=null,this._attributes=null,this._uniforms=null,this._samplers=null,this.allocated=!1}},SceneJS._webgl.Program.prototype.setUniform=function(a,b){if(this.allocated){var c=this._uniforms[a];c&&(this.uniformValues[c.index]===b&&c.numberValue||(c.setValue(b),this.uniformValues[c.index]=b))}},SceneJS._webgl.Sampler=function(a,b,c,d,e,f){this.bindTexture=function(b,c){return b.bind(c)?(a.uniform1i(f,c),!0):!1}},SceneJS._webgl.Shader=function(a,b,c){if(this.allocated=!1,this.handle=a.createShader(b),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to create WebGL shader");if(a.shaderSource(this.handle,c),a.compileShader(this.handle),this.valid=0!=a.getShaderParameter(this.handle,a.COMPILE_STATUS),!this.valid&&!a.isContextLost()){SceneJS.log.error("Shader program failed to compile: "+a.getShaderInfoLog(this.handle)),SceneJS.log.error("Shader source:");for(var d=c.split("\n"),e=0;eb){var d=b/c,e=a.width*d,f=a.height*d,g=document.createElement("canvas");g.width=SceneJS._webgl.nextHighestPowerOfTwo(e),g.height=SceneJS._webgl.nextHighestPowerOfTwo(f);var h=g.getContext("2d");h.drawImage(a,0,0,a.width,a.height,0,0,g.width,g.height),a=g}return a},SceneJS._webgl.ensureImageSizePowerOfTwo=function(a){if(!SceneJS._webgl.isPowerOfTwo(a.width)||!SceneJS._webgl.isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=SceneJS._webgl.nextHighestPowerOfTwo(a.width),b.height=SceneJS._webgl.nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b}return a},SceneJS._webgl.isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS._webgl.nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS._webgl.Uniform=function(a,b,c,d,e,f,g,h){var i=null,j=null;if(d===a.BOOL)i=function(b){j!==b&&(j=b,a.uniform1i(f,b))};else if(d===a.BOOL_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.BOOL_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.BOOL_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.INT)i=function(b){j!==b&&(j=b,a.uniform1iv(f,b))};else if(d===a.INT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.INT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.INT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.FLOAT)i=function(b){j!==b&&(j=b,a.uniform1f(f,b))};else if(d===a.FLOAT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2fv(f,b))};else if(d===a.FLOAT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3fv(f,b))};else if(d===a.FLOAT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4fv(f,b))};else if(d===a.FLOAT_MAT2)i=function(b){a.uniformMatrix2fv(f,a.FALSE,b)};else if(d===a.FLOAT_MAT3)i=function(b){a.uniformMatrix3fv(f,a.FALSE,b)};else{if(d!==a.FLOAT_MAT4)throw"Unsupported shader uniform type: "+d;i=function(b){a.uniformMatrix4fv(f,a.FALSE,b)}}this.setValue=i,this.getLocation=function(){return f},this.index=g};var SceneJS_nodeEventsModule=new function(){var a,b=[],c=[],d=0,e={type:"listeners",stateId:SceneJS._baseStateId++,empty:!0,listeners:[]};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){d=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(d>0){var g={type:"listeners",stateId:b[d-1],listeners:c.slice(0,d)};f.display.renderListeners=g}else f.display.renderListeners=e;a=!1}}),this.preVisitNode=function(e){var f=e._topicSubs.rendered,g=e._topicSubs.worldPos,h=e._topicSubs.viewPos,i=e._topicSubs.cameraPos,j=e._topicSubs.projPos,k=e._topicSubs.canvasPos;(f||g||h||i||j||k)&&(b[d]=e.id,c[d]=function(a){f&&e.publish("rendered",a,!0),g&&e.publish("worldPos",a.getWorldPos()),h&&e.publish("viewPos",a.getViewPos()),i&&e.publish("cameraPos",a.getCameraPos()),j&&e.publish("projPos",a.getProjPos()),k&&e.publish("canvasPos",a.getCanvasPos())},d++,a=!0)},this.postVisitNode=function(c){c.id==b[d-1]&&(d--,a=!0)}},SceneJS_Core=function(a){this.type=a,this.coreId=null,this.stateId=null,this.useCount=0},SceneJS_CoreFactory=function(){this._stateMap=new SceneJS_Map(null,SceneJS._baseStateId),this._cores={}};SceneJS_CoreFactory.coreTypes={},SceneJS_CoreFactory.createCoreType=function(a,b){},SceneJS_CoreFactory.addCoreBuilder=function(a,b){},SceneJS_CoreFactory.coreAliases={rotate:"xform",translate:"xform",scale:"xform",matrix:"xform",xform:"xform"},SceneJS_CoreFactory.prototype.getCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];d||(d=this._cores[a]={});var e;return b&&(e=d[b])?(e.useCount++,e):(e=new SceneJS_Core(a),e.useCount=1,e.stateId=this._stateMap.addItem(e),e.coreId=void 0!=b&&null!=b?b:e.stateId,d[e.coreId]=e,e)},SceneJS_CoreFactory.prototype.hasCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];return d&&d[b]},SceneJS_CoreFactory.prototype.putCore=function(a){if(0!=a.useCount&&--a.useCount<=0){var b=this._cores[a.type];delete b[a.coreId],this._stateMap.removeItem(a.stateId)}},SceneJS_CoreFactory.prototype.webglRestored=function(){var a,b;for(var c in this._cores)if(this._cores.hasOwnProperty(c)&&(a=this._cores[c]))for(var d in a)a.hasOwnProperty(d)&&(b=a[d],b&&b.webglRestored&&b.webglRestored())},SceneJS.Node=function(){},SceneJS.Node.prototype.constructor=SceneJS.Node,SceneJS.Node.prototype._construct=function(a,b,c,d){this._engine=a,this._core=b,this.coreId=b.coreId,this.id=c.id||c.nodeId||d,this.type=c.type||"node",this.data=c.data,this.parent=null,this.nodes=[],this._handleMap=new SceneJS_Map,this._topicSubs={},this._handleTopics={},this._topicPubs={},this._listeners={},this._numListeners=0,this.dirty=!1,this.branchDirty=!1,this._init&&this._init(c)},SceneJS.Node.prototype.taskStarted=function(a){return SceneJS_sceneStatusModule.taskStarted(this,a||"Task")},SceneJS.Node.prototype.taskFinished=function(a){return SceneJS_sceneStatusModule.taskFinished(a)},SceneJS.Node.prototype.taskFailed=function(a){return SceneJS_sceneStatusModule.taskFailed(a)},SceneJS.Node.prototype.log=function(){var a,b;switch(1==arguments.length?(a="info",b=arguments[0]):2==arguments.length&&(a=arguments[0],b=arguments[1]),a){case"warn":b="WARN; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;case"error":b="ERROR; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;default:b="INFO; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b}console[a]?console[a](b):console.log(b)},SceneJS.Node.prototype.publish=function(a,b,c){if(c||(this._topicPubs[a]=b),this._topicSubs[a]){var d=this._topicSubs[a];for(var e in d)d.hasOwnProperty(e)&&d[e].call(this,b)}},SceneJS.Node.prototype.unpublish=function(a){var b=this._topicSubs[a];if(b)for(var c in b)b.hasOwnProperty(c)&&b[c].call(this,null);delete this._topicPubs[a]},SceneJS.Node.prototype.on=function(a,b){var c=this._topicSubs[a];c||(c={},this._topicSubs[a]=c);var d=this._handleMap.addItem();c[d]=b,this._handleTopics[d]=a;var e=this._topicPubs[a];return e&&b.call(this,e),"rendered"==a&&this._engine.branchDirty(this),d},SceneJS.Node.prototype.off=function(a){var b=this._handleTopics[a];if(b){delete this._handleTopics[a];var c=this._topicSubs[b];c&&delete c[a],this._handleMap.removeItem(a),"rendered"==b&&this._engine.branchDirty(this)}},SceneJS.Node.prototype.once=function(a,b){var c=this,d=this.on(a,function(a){c.off(d),b(a)})},SceneJS.Node.prototype.getScene=function(){return this._engine.scene},SceneJS.Node.prototype.getCoreId=function(){return this._core.coreId},SceneJS.Node.prototype.getID=function(){return this.id},SceneJS.Node.prototype.getId=function(){return this.id},SceneJS.Node.prototype.getNodeId=function(){return this.id},SceneJS.Node.prototype.getType=function(){return this.type},SceneJS.Node.prototype.getData=function(){return this.data},SceneJS.Node.prototype.setData=function(a){return this.data=a,this},SceneJS.Node.prototype.getNumNodes=function(){return this.nodes.length},SceneJS.Node.prototype.getNodes=function(){return this.nodes.slice(0)},SceneJS.Node.prototype.getNodeAt=function(a){return 0>a||a>=this.nodes.length?null:this.nodes[a]},SceneJS.Node.prototype.getFirstNode=function(){return 0==this.nodes.length?null:this.nodes[0]},SceneJS.Node.prototype.getLastNode=function(){return 0==this.nodes.length?null:this.nodes[this.nodes.length-1]},SceneJS.Node.prototype.getNode=function(a){for(var b=0;b0?(b[0].parent=null,this._engine.display.objectListDirty=!0,b[0]):null},SceneJS.Node.prototype.disconnect=function(){if(this.parent){for(var a=0;ab;b++)this.nodes[b].parent=null;var c=this.nodes;return this.nodes=[],this._engine.display.objectListDirty=!0,c},SceneJS.Node.prototype.removeNodes=function(){for(var a=this.disconnectNodes(),b=0;ba;a++)d[a].parent=this.parent;for(a=0,b=c.nodes.length;b>a;a++)if(c.nodes[a]===this)return c.nodes.splice.apply(c.nodes,[a,1].concat(d)),this.nodes=[],this.parent=null,this.destroy(),this._engine.branchDirty(c),c},SceneJS.Node.prototype.addNodes=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNodes - nodes argument is undefined");for(var c,d=[],e=a.length,f=a.length-1;f>=0;f--){var g=a[f];if("node"==g.type||this._engine.hasNodeType(g.type)){if(c=this.addNode(g),d[f]=c,0==--e)return b&&b(a),a}else{var h=this;!function(){var c=f;h.addNode(g,function(f){d[c]=f,0==--e&&b&&b(a)})}()}}return null},SceneJS.Node.prototype.addNode=function(a,b){if(a=a||{},a._compile){if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if("string"==typeof a){var c=this._engine.findNode(a);if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node not found: '"+a+"'");if(a=c,null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if(a.type=a.type||"node","node"==a.type||this._engine.hasNodeType(a.type))return a=this._engine.createNode(a),this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a;var d=this;return this._engine.createNode(a,function(a){d.nodes.push(a),a.parent=d,d._engine.branchDirty(a),b&&b(a)}),null},SceneJS.Node.prototype.insertNode=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is undefined");if(a._compile||(a=this._engine.createNode(a)),!a._compile)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is not a SceneJS.Node");if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is still attached to another parent");if(void 0===b||null===b)a.addNodes(this.disconnectNodes()),this.addNode(a);else{if(0>b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node index out of range: -1");b>=this.nodes.length?this.nodes.push(a):this.nodes.splice(b,0,a)}return a.parent=this,a},SceneJS.Node.prototype.mapNodes=function(a){if(a(this))return this;for(var b,c=0;cg;g++)e=d[g],e.options.scope?e.fn.call(e.options.scope,f):e.fn.call(this,f)}},SceneJS.Node.prototype.removeListener=function(a,b){var c=this._listeners[a];if(!c)return null;for(var d=0;d0},SceneJS.Node.prototype.removeListeners=function(){return this._listeners={},this._numListeners=0,this},SceneJS.Node.prototype.getParent=function(a){return this.parent},SceneJS.Node.prototype.getParentOfType=function(a){for(var b=this.parent;b&&b.type!=a;)b=b.parent;return b},SceneJS.Node.prototype.eachParent=function(a){if(!a)throw"SceneJS.Node.eachParent param 'fn' is null or undefined";for(var b=0,c=this;c.parent;){if(a.call(c.parent,b++)===!0)return c.parent;c=c.parent}return null},SceneJS.Node.prototype.hasNode=function(a){if(null===a||void 0===a)throw"SceneJS.Node.hasNode param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.hasNode param 'node' should be either an index number or an ID string";b=this.getNode(a)}return void 0!=b&&null!=b},SceneJS.Node.prototype.node=function(a){if(null===a||void 0===a)throw"SceneJS.Node.node param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.node param 'node' should be either an index number or an ID string";b=this.getNode(a)}if(!b)throw"SceneJS.Node.node - node not found: '"+a+"'";return b},SceneJS.Node.prototype.eachNode=function(a,b){if(!a)throw"SceneJS.Node.eachNode param 'fn' is null or undefined";if("function"!=typeof a)throw"SceneJS.Node.eachNode param 'fn' should be a function";var c;b=b||{};var d=0;return b.andSelf&&a.call(this,d++)===!0?this:(b.depthFirst||b.breadthFirst?b.depthFirst&&(c=this._iterateEachNodeDepthFirst(a,this,d,!1)):c=this._iterateEachNode(a,this,d),c?c:void 0)},SceneJS.Node.prototype.numNodes=function(){return this.nodes.length},SceneJS.Node.prototype._iterateEachNode=function(a,b,c){for(var d,e=b.nodes.length,f=0;e>f;f++)if(d=b.nodes[f],a.call(d,c++)===!0)return d;return null},SceneJS.Node.prototype._iterateEachNodeDepthFirst=function(a,b,c,d){if(d&&a.call(b,c++)===!0)return b;d=!0;for(var e,f=b.nodes.length,g=0;f>g;g++)if(e=this._iterateEachNodeDepthFirst(a,b.nodes[g],c,d))return e;return null},SceneJS.Node.prototype.findNodesByType=function(a,b){return this._findNodesByType(a,[],b)},SceneJS.Node.prototype._findNodesByType=function(a,b,c){var d;for(d=0;dd;d++)c=this.nodes[d],c.branchDirty=c.branchDirty||this.branchDirty,(c.dirty||c.branchDirty||this._engine.sceneDirty)&&(c._compile(a),c.dirty=!1,c.branchDirty=!1);b&&SceneJS_nodeEventsModule.postVisitNode(this)},SceneJS.Node.prototype.destroy=function(){if(!this.destroyed){if(this.parent)for(var a=0;aa;a++)this.nodes[a]._destroyTree()},SceneJS.Node.prototype._doDestroy=function(){return this._destroy&&this._destroy(),this},SceneJS_PubSubProxy=function(a,b){this.scene=a,this.proxy=b};var SceneJS_NodeFactory=function(){this.nodes=new SceneJS_Map({})};SceneJS_NodeFactory.nodeTypes={},SceneJS_NodeFactory._subs={},SceneJS_NodeFactory.createNodeType=function(a,b,c){if(SceneJS_NodeFactory.nodeTypes[a])throw"Node type already defined: "+a;var d=function(){SceneJS.Node.apply(this,arguments),this.type=a};d.prototype=new SceneJS.Node,d.prototype.constructor=d,SceneJS_NodeFactory.nodeTypes[a]=d;var e=SceneJS_NodeFactory.nodeTypes[a];if(!e)throw"Node type plugin did not install itself correctly";c&&c(d);var f=SceneJS_NodeFactory._subs[a];if(f){for(;f.length>0;)f.pop()(e);delete f[a]}return d},SceneJS_NodeFactory.prototype.getNode=function(a,b,c,d){b.type=b.type||"node";var e;if(e="node"==b.type?SceneJS.Node:SceneJS_NodeFactory.nodeTypes[b.type])return this._createNode(e,a,b,c,d);var f=this;this._getType(a,b.type,function(e){f._createNode(e,a,b,c,d)})},SceneJS_NodeFactory.prototype._createNode=function(a,b,c,d,e){var f=new a,g=c.id||c.nodeId;return g?this.nodes.addItem(g,f):g=this.nodes.addItem(f),f._construct(b,d,c,g),e&&e(f),f},SceneJS_NodeFactory.prototype._getType=function(a,b,c){var d=SceneJS_NodeFactory.nodeTypes[b];if(d)return void c(d);var e=SceneJS_NodeFactory._subs[b]||(SceneJS_NodeFactory._subs[b]=[]);if(e.push(c),!(e.length>1)){var f=SceneJS_sceneStatusModule.taskStarted(a.scene,"Loading plugin");e.push(function(){SceneJS_sceneStatusModule.taskFinished(f)});var g=SceneJS_configsModule.configs.pluginPath; +if(!g)throw"no typePath config";this._loadScript(g+"/node/"+b+".js",function(){SceneJS_sceneStatusModule.taskFailed(f)})}},SceneJS_NodeFactory.prototype._loadScript=function(a,b){var c=document.createElement("script");c.type="text/javascript",c.src=a,c.onerror=b,document.getElementsByTagName("head")[0].appendChild(c)},SceneJS_NodeFactory.prototype.putNode=function(a){this.nodes.removeItem(a.id)},function(){function a(a){var b=a.optics;if("ortho"==b.type?a.matrix=SceneJS_math_orthoMat4c(b.left,b.right,b.bottom,b.top,b.near,b.far):"frustum"==b.type?a.matrix=SceneJS_math_frustumMatrix4(b.left,b.right,b.bottom,b.top,b.near,b.far):"perspective"==b.type&&(a.matrix=SceneJS_math_perspectiveMatrix4(b.fovy*Math.PI/180,b.aspect,b.near,b.far)),a.pan){var c=a.pan,d=SceneJS_math_translationMat4v([c.x||0,c.y||0,c.z||0]);a.matrix=SceneJS_math_mulMat4(d,a.matrix,[])}a.mat?a.mat.set(a.matrix):a.mat=new Float32Array(a.matrix)}var b=SceneJS_math_perspectiveMatrix4(45,1,.1,1e4),c=new Float32Array(b),d={type:"camera",stateId:SceneJS._baseStateId++,matrix:b,mat:c,optics:{type:"perspective",fovy:45,aspect:1,near:.1,far:1e4},checkAspect:function(b,c){b.optics.aspect!=c&&(b.optics.aspect=c,a(this))}},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.projTransform=d,f=0}),SceneJS.Camera=SceneJS_NodeFactory.createNodeType("camera"),SceneJS.Camera.prototype._init=function(b){if(1==this._core.useCount){b.optics=b.optics||{};var c=this.getScene().getCanvas();b.optics.aspect=c.width/c.height,this.setOptics(b.optics),b.pan&&this.setPan(b.pan);var d=this;this._canvasSizeSub=this.getScene().on("canvasSize",function(b){d._core.optics.aspect=b.aspect,a(d._core),d._engine.display.imageDirty=!0})}},SceneJS.Camera.getDefaultMatrix=function(){return c},SceneJS.Camera.prototype.setOptics=function(b){var c=this._core;if(b){var d=b.type||c.optics.type||"perspective";if("ortho"==d)c.optics=SceneJS._applyIf(SceneJS_math_ORTHO_OBJ,{type:d,left:b.left,bottom:b.bottom,near:b.near,right:b.right,top:b.top,far:b.far});else if("frustum"==d)c.optics={type:d,left:b.left||-1,bottom:b.bottom||-1,near:b.near||.1,right:b.right||1,top:b.top||1,far:b.far||1e4};else{if("perspective"!=d)throw b.type?SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not supported - supported types are 'perspective', 'frustum' and 'ortho'"):SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not specified - supported types are 'perspective', 'frustum' and 'ortho'");c.optics={type:d,fovy:b.fovy||60,aspect:void 0==b.aspect?1:b.aspect,near:b.near||.1,far:b.far||1e4}}}else c.optics={type:"perspective",fovy:60,aspect:1,near:.1,far:1e4};this._core.optics.pan=b.pan,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.setPan=function(b){this._core.pan=b,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.getOptics=function(){var a={};for(var b in this._core.optics)this._core.optics.hasOwnProperty(b)&&(a[b]=this._core.optics[b]);return a},SceneJS.Camera.prototype.getMatrix=function(){return this._core.matrix.slice(0)},SceneJS.Camera.prototype._compile=function(a){this._engine.display.projTransform=e[f++]=this._core,this._compileNodes(a),this._engine.display.projTransform=--f>0?e[f-1]:d},SceneJS.Camera.prototype._destroy=function(){this.getScene().off(this._canvasSizeSub)}}(),function(){var a={type:"clips",stateId:SceneJS._baseStateId++,empty:!0,hash:"",clips:[]},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.clips=a,c=0}),SceneJS.Clips=SceneJS_NodeFactory.createNodeType("clips"),SceneJS.Clips.prototype._init=function(a){if(1==this._core.useCount){var b=a.clips;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"clips node attribute missing : 'clips'");this._core.clips=this._core.clips||[];for(var c=0,d=b.length;d>c;c++)this._setClip(c,b[c])}},SceneJS.Clips.prototype.setClips=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.clips.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'clips': index out of range ("+this._core.clips.length+" clips defined)");this._setClip(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Clips.prototype._setClip=function(a,b){var c=this._core.clips[a]||(this._core.clips[a]={});c.normalAndDist=[b.x||0,b.y||0,b.z||0,b.dist||0];var d=b.mode||c.mode||"disabled";if("inside"!=d&&"outside"!=d&&"disabled"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'");c.mode=d,this._core.hash=null},SceneJS.Clips.prototype._compile=function(d){this._core.hash||(this._core.hash=this._core.clips.length),this._engine.display.clips=b[c++]=this._core,this._compileNodes(d),this._engine.display.clips=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"enable",enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.enable=a,c=0}),SceneJS.Enable=SceneJS_NodeFactory.createNodeType("enable"),SceneJS.Enable.prototype._init=function(a){1==this._core.useCount&&(this._core.enabled=!0,void 0!=a.enabled&&this.setEnabled(a.enabled))},SceneJS.Enable.prototype.setEnabled=function(a){return a!==this._core.enabled&&(this._core.enabled=a,this._engine.display.drawListDirty=!0,this.publish("enabled",a)),this},SceneJS.Enable.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Enable.prototype._compile=function(d){this._engine.display.enable=b[c++]=this._core,this._compileNodes(d),this._engine.display.enable=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"flags",picking:!0,clipping:!0,enabled:!0,transparent:!1,backfaces:!0,frontface:"ccw",reflective:!0,solid:!0,hash:"refl;s;"},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.flags=a,c=0}),SceneJS.Flags=SceneJS_NodeFactory.createNodeType("flags"),SceneJS.Flags.prototype._init=function(a){1==this._core.useCount&&(this._core.picking=!0,this._core.clipping=!0,this._core.enabled=!0,this._core.transparent=!1,this._core.backfaces=!0,this._core.frontface="ccw",this._core.reflective=!0,this._core.solid=!0,a.flags&&this.setFlags(a.flags))},SceneJS.Flags.prototype.setFlags=function(a){var b=this._core;return void 0!=a.picking&&(b.picking=!!a.picking,this._engine.display.drawListDirty=!0),void 0!=a.clipping&&(b.clipping=!!a.clipping,this._engine.display.imageDirty=!0),void 0!=a.enabled&&(b.enabled=!!a.enabled,this._engine.display.drawListDirty=!0),void 0!=a.transparent&&(b.transparent=!!a.transparent,this._engine.display.stateSortDirty=!0),void 0!=a.backfaces&&(b.backfaces=!!a.backfaces,this._engine.display.imageDirty=!0),void 0!=a.frontface&&(b.frontface=a.frontface,this._engine.display.imageDirty=!0),void 0!=a.reflective&&(b.reflective=a.reflective,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),void 0!=a.solid&&(b.solid=a.solid,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.addFlags=function(a){return this.setFlags(a)},SceneJS.Flags.prototype.getFlags=function(){var a=this._core;return{picking:a.picking,clipping:a.clipping,enabled:a.enabled,transparent:a.transparent,backfaces:a.backfaces,frontface:a.frontface,reflective:a.reflective,solid:a.solid}},SceneJS.Flags.prototype.setPicking=function(a){return a=!!a,this._core.picking!=a&&(this._core.picking=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getPicking=function(){return this._core.picking},SceneJS.Flags.prototype.setClipping=function(a){return a=!!a,this._core.clipping!=a&&(this._core.clipping=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getClipping=function(){return this._core.clipping},SceneJS.Flags.prototype.setEnabled=function(a){return a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Flags.prototype.setTransparent=function(a){return a=!!a,this._core.transparent!=a&&(this._core.transparent=a,this._engine.display.stateOrderDirty=!0),this},SceneJS.Flags.prototype.getTransparent=function(){return this._core.transparent},SceneJS.Flags.prototype.setBackfaces=function(a){return a=!!a,this._core.backfaces!=a&&(this._core.backfaces=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getBackfaces=function(){return this._core.backfaces},SceneJS.Flags.prototype.setFrontface=function(a){return this._core.frontface!=a&&(this._core.frontface=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getFrontface=function(){return this._core.frontface},SceneJS.Flags.prototype.setReflective=function(a){return a=!!a,this._core.reflective!=a&&(this._core.reflective=a,this._core.hash=(a?"refl":"")+this._core.solid?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getReflective=function(){return this._core.reflective},SceneJS.Flags.prototype.setSolid=function(a){return a=!!a,this._core.solid!=a&&(this._core.solid=a,this._core.hash=(this._core.reflective?"refl":"")+a?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getSolid=function(){return this._core.solid},SceneJS.Flags.prototype._compile=function(d){this._engine.display.flags=b[c++]=this._core,this._compileNodes(d),this._engine.display.flags=--c>0?b[c-1]:a}}(),new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._core.renderBuf.webglRestored()}),SceneJS.ColorTarget=SceneJS_NodeFactory.createNodeType("colorTarget"),SceneJS.ColorTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="color",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.ColorTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.ColorTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._buildNodeCore()}),SceneJS.DepthTarget=SceneJS_NodeFactory.createNodeType("depthTarget"),SceneJS.DepthTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="depth",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.DepthTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.DepthTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a=[],b=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){b=0}),SceneJS.Geometry=SceneJS_NodeFactory.createNodeType("geometry"),SceneJS.Geometry.prototype._init=function(a){if(1==this._core.useCount){this._initNodeCore(a,{origin:a.origin,scale:a.scale,autoNormals:"auto"==a.normals}),this._buildNodeCore(this._engine.canvas.gl,this._core);var b=this;this._core.webglRestored=function(){b._buildNodeCore(b._engine.canvas.gl,b._core)}}},SceneJS.Geometry.prototype._initNodeCore=function(a,b){var c=this;b=b||{};var d=a.primitive||"triangles",e=this._core,f=this._engine.canvas.UINT_INDEX_ENABLED?Uint32Array:Uint16Array;e.primitive=this._getPrimitiveType(d),a.normals&&"triangles"==d&&("auto"===a.normals||a.normals===!0)&&a.positions&&a.indices&&this._buildNormals(a),e.arrays={positions:a.positions?new Float32Array(b.scale||b.origin?this._applyOptions(a.positions,b):a.positions):void 0,normals:a.normals?new Float32Array(a.normals):void 0,uv:a.uv?new Float32Array(a.uv):void 0,uv2:a.uv2?new Float32Array(a.uv2):void 0,colors:a.colors?new Float32Array(a.colors):void 0,indices:a.indices?new f(a.indices):void 0},delete a.positions,delete a.normals,delete a.uv,delete a.uv2,delete a.indices,delete a.colors,e.getTangentBuf=function(){if(e.tangentBuf)return e.tangentBuf;var a=e.arrays;if(a.positions&&a.indices&&a.uv){var b=c._engine.canvas.gl,d=new Float32Array(c._buildTangents(a));e.arrays.tangents=d;var f=b.STATIC_DRAW;return e.tangentBuf=new SceneJS._webgl.ArrayBuffer(b,b.ARRAY_BUFFER,d,d.length,3,f)}}},SceneJS.Geometry.prototype._getPrimitiveType=function(a){var b=this._engine.canvas.gl;switch(a){case"points":return b.POINTS;case"lines":return b.LINES;case"line-loop":return b.LINE_LOOP;case"line-strip":return b.LINE_STRIP;case"triangles":return b.TRIANGLES;case"triangle-strip":return b.TRIANGLE_STRIP;case"triangle-fan":return b.TRIANGLE_FAN;default:throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"geometry primitive unsupported: '"+a+"' - supported types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'")}},SceneJS.Geometry.prototype._applyOptions=function(a,b){var c=a.slice?a.slice(0):new Float32Array(a);if(b.scale)for(var d=void 0!=b.scale.x?b.scale.x:1,e=void 0!=b.scale.y?b.scale.y:1,f=void 0!=b.scale.z?b.scale.z:1,g=0,h=c.length;h>g;g+=3)c[g]*=d,c[g+1]*=e,c[g+2]*=f;if(b.origin)for(var i=void 0!=b.origin.x?b.origin.x:0,j=void 0!=b.origin.y?b.origin.y:0,k=void 0!=b.origin.z?b.origin.z:0,g=0,h=c.length;h>g;g+=3)c[g]-=i,c[g+1]-=j,c[g+2]-=k;return c};var c=function(a){a.vertexBuf&&(a.vertexBuf.destroy(),a.vertexBuf=null),a.normalBuf&&(a.normalBuf.destroy(),a.normalBuf=null),a.uvBuf&&(a.uvBuf.destroy(),a.uvBuf=null),a.uvBuf2&&(a.uvBuf2.destroy(),a.uvBuf2=null),a.colorBuf&&(a.colorBuf.destroy(),a.colorBuf=null),a.tangentBuf&&(a.tangentBuf.destroy(),a.tangentBuf=null),a.indexBuf&&(a.indexBuf.destroy(),a.indexBuf=null),a.interleavedBuf&&(a.interleavedBuf.destroy(),a.interleavedBuf=null)};SceneJS.Geometry.prototype._buildNodeCore=function(a,b){var d=a.STATIC_DRAW;try{var e=b.arrays,f=SceneJS.getConfigs("enableInterleaving")!==!1,g=0,h=0,i=[],j=[],k=function(a,b){return 0==g?g=a.length/b:a.length/b!=g&&(f=!1),i.push(a),j.push(b),h+=b,4*(h-b)};if(e.positions&&(f&&(b.interleavedPositionOffset=k(e.positions,3)),b.vertexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.positions,e.positions.length,3,d)),e.normals&&(f&&(b.interleavedNormalOffset=k(e.normals,3)),b.normalBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.normals,e.normals.length,3,d)),e.uv&&(f&&(b.interleavedUVOffset=k(e.uv,2)),b.uvBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv,e.uv.length,2,d)),e.uv2&&(f&&(b.interleavedUV2Offset=k(e.uv2,2)),b.uvBuf2=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv2,e.uv2.length,2,d)),e.colors&&(f&&(b.interleavedColorOffset=k(e.colors,4)),b.colorBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.colors,e.colors.length,4,d)),e.indices&&(b.indexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ELEMENT_ARRAY_BUFFER,e.indices,e.indices.length,1,d)),h>0&&f){for(var l=[],m=i.length,n=0;g>n;++n)for(var o=0;m>o;++o)for(var p=j[o],q=0;p>q;++q)l.push(i[o][n*p+q]);b.interleavedStride=4*h,b.interleavedBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,new Float32Array(l),l.length,h,d),b.interleavedBuf.dirty=!1}}catch(r){throw c(b),SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate geometry: "+r)}},SceneJS.Geometry.prototype._updateArray=function(a,b,c){var d=a.length,e=b.length;e+c>d&&(e-=e+c-d);for(var f=c,g=0;e>g;f++,g++)a[f]=b[g]},SceneJS.Geometry.prototype._buildNormals=function(a){for(var b,c,d,e,f,g,h=a.positions,i=a.indices,j=new Array(h.length/3),k=0,l=i.length-3;l>k;k+=3){b=i[k+0],c=i[k+1],d=i[k+2],e=[h[3*b+0],h[3*b+1],h[3*b+2]],f=[h[3*c+0],h[3*c+1],h[3*c+2]],g=[h[3*d+0],h[3*d+1],h[3*d+2]],f=SceneJS_math_subVec4(f,e,[0,0,0,0]),g=SceneJS_math_subVec4(g,e,[0,0,0,0]);var m=SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(f,g,[0,0,0,0]),[0,0,0,0]);j[b]||(j[b]=[]),j[c]||(j[c]=[]),j[d]||(j[d]=[]),j[b].push(m),j[c].push(m),j[d].push(m)}for(var n=new Array(h.length),k=0,l=j.length;l>k;k++){for(var o=j[k].length,p=0,q=0,r=0,s=0;o>s;s++)p+=j[k][s][0],q+=j[k][s][1],r+=j[k][s][2];n[3*k+0]=p/o,n[3*k+1]=q/o,n[3*k+2]=r/o}a.normals=n},SceneJS.Geometry.prototype._buildTangents=function(a){for(var b=a.positions,c=a.indices,d=a.uv,e=[],f=0;ft;t++){var u=c[f+t];"undefined"!=typeof e[u]?e[u]=SceneJS_math_addVec3(e[u],s,[]):e[u]=s}}for(var v=[],w=0;wf;f+=3)c=b[f],d=b[f+1],e=b[f+2],cthis._boundary.xmax&&(this._boundary.xmax=c),d>this._boundary.ymax&&(this._boundary.ymax=d),e>this._boundary.zmax&&(this._boundary.zmax=e);return this._boundary},SceneJS.Geometry.prototype._compile=function(c){if(this._core._loading)return void this._compileNodes(c);var d=this._core;d.vertexBuf||(d=this._inheritVBOs(d)),d.indexBuf?(d.hash=[d.normalBuf?"t":"f",d.arrays&&d.arrays.tangents?"t":"f",d.uvBuf?"t":"f",d.uvBuf2?"t":"f",d.colorBuf?"t":"f",d.primitive].join(""),d.stateId=this._core.stateId,d.type="geometry",this._engine.display.geometry=a[b++]=d,SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING,{display:this._engine.display}),this._engine.display.buildObject(this.id)):a[b++]=this._core,this._compileNodes(c),b--},SceneJS.Geometry.prototype._inheritVBOs=function(c){for(var d={primitive:c.primitive,boundary:c.boundary,normalBuf:c.normalBuf,uvBuf:c.uvBuf,uvBuf2:c.uvBuf2,colorBuf:c.colorBuf,interleavedBuf:c.interleavedBuf,indexBuf:c.indexBuf,interleavedStride:c.interleavedStride,interleavedPositionOffset:c.interleavedPositionOffset,interleavedNormalOffset:c.interleavedNormalOffset,interleavedUVOffset:c.interleavedUVOffset,interleavedUV2Offset:c.interleavedUV2Offset,interleavedColorOffset:c.interleavedColorOffset},e=b-1;e>=0;e--)if(a[e].vertexBuf)return d.vertexBuf=a[e].vertexBuf,d.boundary=a[e].boundary,d.normalBuf=a[e].normalBuf,d.uvBuf=a[e].uvBuf,d.uvBuf2=a[e].uvBuf2,d.colorBuf=a[e].colorBuf,d.interleavedBuf=a[e].interleavedBuf,d.interleavedStride=a[e].interleavedStride,d.interleavedPositionOffset=a[e].interleavedPositionOffset,d.interleavedNormalOffset=a[e].interleavedNormalOffset,d.interleavedUVOffset=a[e].interleavedUVOffset,d.interleavedUV2Offset=a[e].interleavedUV2Offset,d.interleavedColorOffset=a[e].interleavedColorOffset,d;return d},SceneJS.Geometry.prototype._destroy=function(){this._engine.display.removeObject(this.id),1==this._core.useCount&&(this._destroyNodeCore(),this._source&&this._source.destroy&&this._source.destroy())},SceneJS.Geometry.prototype._destroyNodeCore=function(){document.getElementById(this._engine.canvas.canvasId)&&c(this._core)}},function(){var a={type:"stage",stateId:SceneJS._baseStateId++,priority:0,pickable:!0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.stage=a,c=0}),SceneJS.Stage=SceneJS_NodeFactory.createNodeType("stage"),SceneJS.Stage.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1,this._core.pickable=!!a.pickable)},SceneJS.Stage.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Stage.prototype.getPriority=function(){return this._core.priority},SceneJS.Stage.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype._compile=function(d){this._engine.display.stage=b[c++]=this._core,this._compileNodes(d),this._engine.display.stage=--c>0?b[c-1]:a}}(),function(){var a={type:"layer",stateId:SceneJS._baseStateId++,priority:0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.layer=a,c=0}),SceneJS.Layer=SceneJS_NodeFactory.createNodeType("layer"),SceneJS.Layer.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1)},SceneJS.Layer.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Layer.prototype.getPriority=function(){return this._core.priority},SceneJS.Layer.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.setClearDepth=function(a){a=a||0,this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Layer.prototype._compile=function(d){this._engine.display.layer=b[c++]=this._core,this._compileNodes(d),this._engine.display.layer=--c>0?b[c-1]:a}}(),SceneJS.Library=SceneJS_NodeFactory.createNodeType("library"),SceneJS.Library.prototype._compile=function(a){},function(){function a(a){if(a.lights&&a.lights.length>0){for(var b,c=a.lights,d=[],e=0,f=c.length;f>e;e++)b=c[e],d.push(b.mode),b.specular&&d.push("s"),b.diffuse&&d.push("d"),d.push("world"==b.space?"w":"v");a.hash=d.join("")}else a.hash=""}var b={type:"lights",stateId:SceneJS._baseStateId++,hash:null,empty:!1,lights:[{mode:"ambient",color:[.7,.7,.8],diffuse:!0,specular:!1},{mode:"dir",color:[1,1,1],diffuse:!0,specular:!0,dir:[-.5,-.5,-1],space:"view"},{mode:"dir",color:[1,1,1],diffuse:!1,specular:!0,dir:[1,-.9,-.7],space:"view"}]};a(b);var c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.lights=b,d=0}),SceneJS.Lights=SceneJS_NodeFactory.createNodeType("lights"),SceneJS.Lights.prototype._init=function(a){if(1==this._core.useCount){var b=a.lights;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"lights node attribute missing : 'lights'");this._core.lights=this._core.lights||[];for(var c=0,d=b.length;d>c;c++)this._initLight(c,b[c])}},SceneJS.Lights.prototype._initLight=function(a,b){var c=[];this._core.lights[a]=c;var d=b.mode||"dir";if("dir"!=d&&"point"!=d&&"ambient"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");var e=b.pos,f=b.dir,g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],c.mode=d,c.diffuse="ambient"==d?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==d?!1:void 0!=b.specular?b.specular:!0,c.pos=b.pos?[e.x||0,e.y||0,e.z||0]:[0,0,0],c.dir=b.dir?[f.x||0,f.y||0,f.z||0]:[0,0,1],c.attenuation=[void 0!=b.constantAttenuation?b.constantAttenuation:0,b.linearAttenuation||0,b.quadraticAttenuation||0];var h=b.space;if(h){if("view"!=h&&"world"!=h)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+h+"' - should be 'view' or 'world'")}else h="world";c.space=h,this._core.hash=null},SceneJS.Lights.prototype.setLights=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.lights.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'lights': index out of range ("+this._core.lights.length+" lights defined)");this._setLight(b,a[c]||{})}this._engine.branchDirty(this)},SceneJS.Lights.prototype._setLight=function(a,b){var c=this._core.lights[a],d=!1,e=!1;if(b.mode&&b.mode!=c.mode){var f=b.mode;if("dir"!=f&&"point"!=f&&"ambient"!=f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");c.mode=f,c.diffuse="ambient"==f?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==f?!1:void 0!=b.specular?b.specular:!0,e=!0}if(b.color){var g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],d=!0}var h=b.pos;h&&(c.pos=[h.x||0,h.y||0,h.z||0],d=!0);var i=b.dir;if(i&&(c.dir=[i.x||0,i.y||0,i.z||0],d=!0),void 0!=b.constantAttenuation&&(c.attenuation[0]=b.constantAttenuation,d=!0),void 0!=b.linearAttenuation&&(c.attenuation[1]=b.linearAttenuation,d=!0),void 0!=b.quadraticAttenuation&&(c.attenuation[2]=b.quadraticAttenuation,d=!0),b.space&&b.space!=c.space){var j=b.space;if("view"!=j&&"world"!=j)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+j+"' - should be 'view' or 'world'");c.space=j,this._core.hash=null,e=!0}void 0!=b.specular&&b.specular!=c.specular&&(c.specular=b.specular,e=!0),void 0!=b.diffuse&&b.diffuse!=c.diffuse&&(c.diffuse=b.diffuse,e=!0),e?this._engine.branchDirty(this):d&&(this._engine.display.imageDirty=!0),this._core.hash=null},SceneJS.Lights.prototype._compile=function(e){this._core.hash||a(this._core),this._engine.display.lights=c[d++]=this._core,this._compileNodes(e),this._engine.display.lights=--d>0?c[d-1]:b}}(),function(){var a=SceneJS_math_lookAtMat4c(0,0,10,0,0,0,0,1,0),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4())),d=new Float32Array(c),e={type:"lookAt",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,lookAt:SceneJS_math_LOOKAT_ARRAYS},f=[],g=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.viewTransform=e,g=0}),SceneJS.Lookat=SceneJS_NodeFactory.createNodeType("lookAt"),SceneJS.Lookat.prototype._init=function(a){if(this._mat=null,this._xf={type:"lookat"},1==this._core.useCount){this._core.eyeX=0,this._core.eyeY=0,this._core.eyeZ=10,this._core.lookX=0,this._core.lookY=0,this._core.lookZ=0,this._core.upX=0,this._core.upY=1,this._core.upZ=0,a.eye||a.look||a.up?(this.setEye(a.eye),this.setLook(a.look),this.setUp(a.up)):(this.setEye({x:0,y:0,z:10}),this.setLook({x:0,y:0,z:0}),this.setUp({x:0,y:1,z:0}));var b=this._core,c=this;this._core.rebuild=function(){b.matrix=SceneJS_math_lookAtMat4c(b.eyeX,b.eyeY,b.eyeZ,b.lookX,b.lookY,b.lookZ,b.upX,b.upY,b.upZ),b.lookAt={eye:[b.eyeX,b.eyeY,b.eyeZ],look:[b.lookX,b.lookY,b.lookZ],up:[b.upX,b.upY,b.upZ]},b.mat?(b.mat.set(b.matrix),b.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))):(b.mat=new Float32Array(b.matrix),b.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))),c.publish("matrix",b.matrix),b.dirty=!1},this._core.dirty=!0,this._tick=this.getScene().on("tick",function(){c._core.dirty&&c._core.rebuild()})}},SceneJS.Lookat.getDefaultMatrix=function(){return b},SceneJS.Lookat.prototype.setEye=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.eyeX=a.x),void 0!=a.y&&null!=a.y&&(this._core.eyeY=a.y),void 0!=a.z&&null!=a.z&&(this._core.eyeZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEye=function(a){return a=a||{},this._core.eyeX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.eyeY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.eyeZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeX=function(a){return this._core.eyeX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeY=function(a){return this._core.eyeY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0, +this},SceneJS.Lookat.prototype.setEyeZ=function(a){return this._core.eyeZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeX=function(a){return this._core.eyeX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeY=function(a){return this._core.eyeY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeZ=function(a){return this._core.eyeZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getEye=function(){return{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ}},SceneJS.Lookat.prototype.setLook=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.lookX=a.x),void 0!=a.y&&null!=a.y&&(this._core.lookY=a.y),void 0!=a.z&&null!=a.z&&(this._core.lookZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLook=function(a){return a=a||{},this._core.lookX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.lookY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.lookZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookX=function(a){return this._core.lookX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookY=function(a){return this._core.lookY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookZ=function(a){return this._core.lookZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookX=function(a){return this._core.lookX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookY=function(a){return this._core.lookY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookZ=function(a){return this._core.lookZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getLook=function(){return{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ}},SceneJS.Lookat.prototype.setUp=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.upX=a.x),void 0!=a.y&&null!=a.y&&(this._core.upY=a.y),void 0!=a.z&&null!=a.z&&(this._core.upZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUp=function(a){return a=a||{},this._core.upX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.upY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.upZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpX=function(a){return this._core.upX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpY=function(a){return this._core.upY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpZ=function(a){return this._core.upZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpX=function(a){return this._core.upX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpY=function(a){return this._core.upY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpZ=function(a){return this._core.upZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getUp=function(){return{x:this._core.upX,y:this._core.upY,z:this._core.upZ}},SceneJS.Lookat.prototype.getMatrix=function(){return this._core.dirty&&this._core.rebuild(),this._core.matrix.slice(0)},SceneJS.Lookat.prototype.getAttributes=function(){return{look:{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ},eye:{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ},up:{x:this._core.upX,y:this._core.upY,z:this._core.upZ}}},SceneJS.Lookat.prototype._compile=function(a){this._engine.display.viewTransform=f[g++]=this._core,this._compileNodes(a),this._engine.display.viewTransform=--g>0?f[g-1]:e},SceneJS.Lookat.prototype._destroy=function(){this.getScene().off(this._tick)}}(),new function(){var a={type:"material",stateId:SceneJS._baseStateId++,baseColor:[1,1,1],specularColor:[1,1,1],specular:1,shine:70,alpha:1,emit:0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.material=a,c=0}),SceneJS.Material=SceneJS_NodeFactory.createNodeType("material"),SceneJS.Material.prototype._init=function(a){1==this._core.useCount&&(this.setBaseColor(a.color||a.baseColor),this.setSpecularColor(a.specularColor),this.setSpecular(a.specular),this.setShine(a.shine),this.setEmit(a.emit),this.setAlpha(a.alpha))},SceneJS.Material.prototype.setBaseColor=function(b){var c=a.baseColor;return this._core.baseColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.baseColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.setColor=SceneJS.Material.prototype.setBaseColor,SceneJS.Material.prototype.getBaseColor=function(){return{r:this._core.baseColor[0],g:this._core.baseColor[1],b:this._core.baseColor[2]}},SceneJS.Material.prototype.getColor=SceneJS.Material.prototype.getBaseColor,SceneJS.Material.prototype.setSpecularColor=function(b){var c=a.specularColor;return this._core.specularColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.specularColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecularColor=function(){return{r:this._core.specularColor[0],g:this._core.specularColor[1],b:this._core.specularColor[2]}},SceneJS.Material.prototype.setSpecular=function(b){return this._core.specular=void 0!=b&&null!=b?b:a.specular,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecular=function(){return this._core.specular},SceneJS.Material.prototype.setShine=function(b){return this._core.shine=void 0!=b&&null!=b?b:a.shine,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getShine=function(){return this._core.shine},SceneJS.Material.prototype.setEmit=function(b){return this._core.emit=void 0!=b&&null!=b?b:a.emit,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getEmit=function(){return this._core.emit},SceneJS.Material.prototype.setAlpha=function(b){return this._core.alpha=void 0!=b&&null!=b?b:a.alpha,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getAlpha=function(){return this._core.alpha},SceneJS.Material.prototype._compile=function(d){this._engine.display.material=b[c++]=this._core,this._compileNodes(d),this._engine.display.material=--c>0?b[c-1]:a}},new function(){var a={type:"morphGeometry",stateId:SceneJS._baseStateId++,hash:"",morph:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.morphGeometry=a,c=0}),SceneJS.MorphGeometry=SceneJS_NodeFactory.createNodeType("morphGeometry"),SceneJS.MorphGeometry.prototype._init=function(a){if(1==this._core.useCount){if(this._sourceConfigs=a.source,this._source=null,a.source){if(!a.source.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry config expected: source.type");var b=this;SceneJS.Plugins.getPlugin("morphGeometry",this._sourceConfigs.type,function(c){if(!c)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: no support for source type '"+b._sourceConfigs.type+"' - need to include plugin for self source type, or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '"+b._sourceConfigs.type+"', ).");if(!c.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)");if(b._source=c.getSource(),!b._source.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'subscribe' method not found on source provided by plugin type '"+a.source.type+"'");var d=!1;b._source.subscribe(function(a){if(d){if(a.targets)for(var c,e,f,g=a.targets,h=b._core.targets,i=0,j=g.length;j>i;i++)c=g[i],e=c.targetIndex,f=h[e],c.positions&&f.vertexBuf&&(f.vertexBuf.bind(),f.vertexBuf.setData(c.positions,0));b._display.imageDirty=!0}else b._buildNodeCore(a),b._core._loading=!1,b._fireEvent("loaded"),b._engine.branchDirty(b),d=!0}),b._core._loading=!0,b._fireEvent("loading"),b._source.configure(b._sourceConfigs)})}else a.create instanceof Function?this._buildNodeCore(a.create()):this._buildNodeCore(a);this._core.webglRestored=function(){},this.setFactor(a.factor)}this._core.factor=a.factor||0,this._core.clamp=!!a.clamp},SceneJS.MorphGeometry.prototype._buildNodeCore=function(a){var b=a.targets||[];if(b.length<2)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node should have at least two targets");var c=a.keys||[];if(c.length!=b.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node mismatch in number of keys and targets");var d=this._core,e=this._engine.canvas.gl,f=e.STATIC_DRAW;d.keys=c,d.targets=[],d.key1=0,d.key2=1;for(var g,h,i,j,k,l=0,m=b.length;m>l;l++)k=b[l],!g&&k.positions&&(g=k.positions),!h&&k.normals&&(h=k.normals),!i&&k.uv&&(i=k.uv),!j&&k.uv2&&(j=k.uv2);try{for(var n,o,l=0,m=b.length;m>l;l++)k=b[l],n={},o=k.positions||g,o&&(n.positions="Float32Array"==typeof o?o:new Float32Array(o),n.vertexBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.positions,o.length,3,f),g=o),o=k.normals||h,o&&(n.normals="Float32Array"==typeof o?o:new Float32Array(o),n.normalBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.normals,o.length,3,f),h=o),o=k.uv||i,o&&(n.uv="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv,o.length,2,f),i=o),o=k.uv2||j,o&&(n.uv2="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf2=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv2,o.length,2,f),j=o),d.targets.push(n)}catch(p){for(var l=0,m=d.targets.length;m>l;l++)n=d.targets[l],n.vertexBuf&&n.vertexBuf.destroy(),n.normalBuf&&n.normalBuf.destroy(),n.uvBuf&&n.uvBuf.destroy(),n.uvBuf2&&n.uvBuf2.destroy();throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate VBO(s) for morphGeometry: "+p)}},SceneJS.MorphGeometry.prototype.setSource=function(a){this._sourceConfigs=a;var b=this._source;b&&b.configure(a)},SceneJS.MorphGeometry.prototype.getSource=function(){return this._sourceConfigs},SceneJS.MorphGeometry.prototype.setFactor=function(a){a=a||0;var b=this._core,c=b.keys,d=b.key1,e=b.key2,f=b.factor;if(ac[c.length-1])d=c.length-2,e=d+1;else{for(;c[d]>a;)d--,e--;for(;c[e]0?b[c-1]:a},SceneJS.MorphGeometry.prototype._makeHash=function(){var a=this._core;if(a.targets.length>0){var b=a.targets[0],c="t",d="f";a.hash=[b.vertexBuf?c:d,b.normalBuf?c:d,b.uvBuf?c:d,b.uvBuf2?c:d].join("")}else a.hash=""},SceneJS.MorphGeometry.prototype._destroy=function(){if(1==this._core.useCount){if(document.getElementById(this._engine.canvas.canvasId))for(var a,b=this._core,c=0,d=b.targets.length;d>c;c++)a=b.targets[c],a.vertexBuf&&a.vertexBuf.destroy(),a.normalBuf&&a.normalBuf.destroy(),a.uvBuf&&a.uvBuf.destroy(),a.uvBuf2&&a.uvBuf2.destroy();this._source&&this._source.destroy&&this._source.destroy()}}},function(){var a={type:"name",stateId:SceneJS._baseStateId++,name:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.name=a,c=0}),SceneJS.Name=SceneJS_NodeFactory.createNodeType("name"),SceneJS.Name.prototype._init=function(a){this.setName(a.name),this._core.nodeId=this.id},SceneJS.Name.prototype.setName=function(a){this._core.name=a||"unnamed",this._engine.branchDirty(this)},SceneJS.Name.prototype.getName=function(){return this._core.name},SceneJS.Name.prototype._compile=function(d){this._engine.display.name=b[c++]=this._core;for(var e,f=[],g=0;c>g;g++)e=b[g].name,e&&f.push(e);this._core.path=f.join("."),this._compileNodes(d),this._engine.display.name=--c>0?b[c-1]:a}}(),new function(){function a(a){var c;if(f>0){c={};for(var d in a)a.hasOwnProperty(d)&&void 0!=a[d]&&(c[d]=g(d))}return b(a.props),{props:a,setProps:function(b){h(b,a)},restoreProps:function(a){c&&i(a,c)}}}function b(a){var b;for(var c in a)a.hasOwnProperty(c)&&(b=a[c],void 0!=b&&null!=b&&(k[c]?a[c]=k[c](null,b):l[c]&&(a[c]=l[c](null,b))))}var c,d={type:"renderer",stateId:SceneJS._baseStateId++,props:null},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){c=a.engine.canvas,f=0,a.engine.display.renderer=e[f++]=d});var g=function(a){for(var b,c,d=f-1;d>=0;d--)if(b=e[d].props,b&&(c=b[a],void 0!=c&&null!=c))return b[a];return null},h=function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=k[c];d&&d(a,b[c])}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor),b.clear&&l.clear(a,b.clear)},i=function(a,b){var c;for(var d in b)if(b.hasOwnProperty(d)&&(c=b[d],void 0!=c&&null!=c)){var e=k[d];e&&e(a,c)}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor)},j=function(a,b){if(!b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Null SceneJS.State node config: "'+b+'"');var c=SceneJS._webgl.enumMap[b];if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Unrecognised SceneJS.State node config value: "'+b+'"');var d=a[c];if(!d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"This browser's WebGL does not support renderer node config value: \""+b+'"');return d},k={enableBlend:function(a,b){return a?void(b?a.enable(a.BLEND):a.disable(a.BLEND)):((null==b||void 0==b)&&(b=!1),b)},blendColor:function(a,b){return a?void a.blendColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},blendEquation:function(a,b){return a?void a.blendEquation(a,j(a,b)):b||"funcAdd"},blendEquationSeparate:function(a,b){return a?void a.blendEquation(j(a,b.rgb),j(a,b.alpha)):(b=b||{},{rgb:b.rgb||"funcAdd",alpha:b.alpha||"funcAdd"})},blendFunc:function(a,b){return a?void a.blendFunc(j(a,b.sfactor||"srcAlpha"),j(a,b.dfactor||"oneMinusSrcAlpha")):(b=b||{},{sfactor:b.sfactor||"srcAlpha",dfactor:b.dfactor||"oneMinusSrcAlpha"})},blendFuncSeparate:function(a,b){return a?void a.blendFuncSeparate(j(a,b.srcRGB||"zero"),j(a,b.dstRGB||"zero"),j(a,b.srcAlpha||"zero"),j(a,b.dstAlpha||"zero")):(b=b||{},{srcRGB:b.srcRGB||"zero",dstRGB:b.dstRGB||"zero",srcAlpha:b.srcAlpha||"zero",dstAlpha:b.dstAlpha||"zero"})},clearColor:function(a,b){return a?void a.clearColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},clearDepth:function(a,b){return a?void a.clearDepth(b):null==b||void 0==b?1:b},clearStencil:function(a,b){return a?void a.clearStencil(b):b||0},colorMask:function(a,b){return a?void a.colorMask(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},enableCullFace:function(a,b){return a?void(b?a.enable(a.CULL_FACE):a.disable(a.CULL_FACE)):b},cullFace:function(a,b){return a?void a.cullFace(j(a,b)):b||"back"},enableDepthTest:function(a,b){return a?void(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST)):((null==b||void 0==b)&&(b=!0),b)},depthFunc:function(a,b){return a?void a.depthFunc(j(a,b)):b||"less"},enableDepthMask:function(a,b){return a?void a.depthMask(b):((null==b||void 0==b)&&(b=!0),b)},depthRange:function(a,b){return a?void a.depthRange(b.zNear,b.zFar):(b=b||{},{zNear:void 0==b.zNear||null==b.zNear?0:b.zNear,zFar:void 0==b.zFar||null==b.zFar?1:b.zFar})},frontFace:function(a,b){return a?void a.frontFace(j(a,b)):b||"ccw"},lineWidth:function(a,b){return a?void a.lineWidth(b):b||1},enableScissorTest:function(a,b){return a?void(b?a.enable(a.SCISSOR_TEST):(b=!1,a.disable(a.SCISSOR_TEST))):b}},l={viewport:function(a,b){return a?void a.viewport(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||1,y:b.y||1,width:b.width||c.canvas.width,height:b.height||c.canvas.height})},scissor:function(a,b){return a?void a.scissor(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||0,y:b.y||0,width:b.width||1,height:b.height||1})},clear:function(a,b){if(!a)return b=b||{};var c;b.color&&(c=a.COLOR_BUFFER_BIT),b.depth&&(c|=a.DEPTH_BUFFER_BIT),b.stencil&&(c|=a.STENCIL_BUFFER_BIT)}};SceneJS.Renderer=SceneJS_NodeFactory.createNodeType("renderer"),SceneJS.Renderer.prototype._init=function(a){if(1==this._core.useCount){for(var b in a)a.hasOwnProperty(b)&&(this._core[b]=a[b]);this._core.dirty=!0}},SceneJS.Renderer.prototype.setViewport=function(a){this._core.viewport=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getViewport=function(){return this._core.viewport?{x:this._core.viewport.x,y:this._core.viewport.y,width:this._core.viewport.width,height:this._core.viewport.height}:void 0},SceneJS.Renderer.prototype.setScissor=function(a){this._core.scissor=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getScissor=function(){return this._core.scissor?{x:this._core.scissor.x,y:this._core.scissor.y,width:this._core.scissor.width,height:this._core.scissor.height}:void 0},SceneJS.Renderer.prototype.setClear=function(a){this._core.clear=a?{r:a.r||0,g:a.g||0,b:a.b||0}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getClear=function(){return this._core.clear?{r:this._core.clear.r,g:this._core.clear.g,b:this._core.clear.b}:null},SceneJS.Renderer.prototype.setEnableBlend=function(a){this._core.enableBlend=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getEnableBlend=function(){return this._core.enableBlend},SceneJS.Renderer.prototype.setBlendColor=function(a){this._core.blendColor=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendColor=function(){return this._core.blendColor?{r:this._core.blendColor.r,g:this._core.blendColor.g,b:this._core.blendColor.b,a:this._core.blendColor.a}:void 0},SceneJS.Renderer.prototype.setBlendEquation=function(a){this._core.blendEquation=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquation=function(){return this._core.blendEquation},SceneJS.Renderer.prototype.setBlendEquationSeparate=function(a){this._core.blendEquationSeparate=a?{rgb:a.rgb||"funcAdd",alpha:a.alpha||"funcAdd"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquationSeparate=function(){return this._core.blendEquationSeparate?{rgb:this._core.rgb,alpha:this._core.alpha}:void 0},SceneJS.Renderer.prototype.setBlendFunc=function(a){this._core.blendFunc=a?{sfactor:a.sfactor||"srcAlpha",dfactor:a.dfactor||"one"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendFunc=function(){return this._core.blendFunc?{sfactor:this._core.sfactor,dfactor:this._core.dfactor}:void 0},SceneJS.Renderer.prototype.setBlendFuncSeparate=function(a){this._core.blendFuncSeparate=a?{srcRGB:a.srcRGB||"zero",dstRGB:a.dstRGB||"zero",srcAlpha:a.srcAlpha||"zero",dstAlpha:a.dstAlpha||"zero"}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getBlendFuncSeparate=function(){return this._core.blendFuncSeparate?{srcRGB:this._core.blendFuncSeparate.srcRGB,dstRGB:this._core.blendFuncSeparate.dstRGB,srcAlpha:this._core.blendFuncSeparate.srcAlpha,dstAlpha:this._core.blendFuncSeparate.dstAlpha}:void 0},SceneJS.Renderer.prototype.setEnableCullFace=function(a){this._core.enableCullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableCullFace=function(){return this._core.enableCullFace},SceneJS.Renderer.prototype.setCullFace=function(a){this._core.cullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getCullFace=function(){return this._core.cullFace},SceneJS.Renderer.prototype.setEnableDepthTest=function(a){this._core.enableDepthTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthTest=function(){return this._core.enableDepthTest},SceneJS.Renderer.prototype.setDepthFunc=function(a){this._core.depthFunc=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthFunc=function(){return this._core.depthFunc},SceneJS.Renderer.prototype.setEnableDepthMask=function(a){this._core.enableDepthMask=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthMask=function(){return this._core.enableDepthMask},SceneJS.Renderer.prototype.setClearDepth=function(a){this._core.clearDepth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Renderer.prototype.setDepthRange=function(a){this._core.depthRange=a?{zNear:void 0==a.zNear||null==a.zNear?0:a.zNear,zFar:void 0==a.zFar||null==a.zFar?1:a.zFar}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthRange=function(){return this._core.depthRange?{zNear:this._core.depthRange.zNear,zFar:this._core.depthRange.zFar}:void 0},SceneJS.Renderer.prototype.setFrontFace=function(a){this._core.frontFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getFrontFace=function(){return this._core.frontFace},SceneJS.Renderer.prototype.setLineWidth=function(a){this._core.lineWidth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Renderer.prototype.setEnableScissorTest=function(a){this._core.enableScissorTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableScissorTest=function(){return this._core.enableScissorTest},SceneJS.Renderer.prototype.setClearStencil=function(a){this._core.clearStencil=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearStencil=function(){return this._core.clearStencil},SceneJS.Renderer.prototype.setColorMask=function(a){this._core.colorMask=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getColorMask=function(){return this._core.colorMask?{r:this._core.colorMask.r,g:this._core.colorMask.g,b:this._core.colorMask.b,a:this._core.colorMask.a}:void 0},SceneJS.Renderer.prototype._compile=function(b){this._core.dirty&&(this._core.props=a(this._core),this._core.dirty=!1),this._engine.display.renderer=e[f++]=this._core,this._compileNodes(b),this._engine.display.renderer=--f>0?e[f-1]:d}},function(){var a={less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL"},b={type:"depthBuffer",stateId:SceneJS._baseStateId++,enabled:!0,clearDepth:1,depthFunc:null,_depthFuncName:"less"},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){null===b.depthFunc&&(b.depthFunc=a.engine.canvas.gl.LESS),a.engine.display.depthBuffer=b,d=0}),SceneJS.DepthBuf=SceneJS_NodeFactory.createNodeType("depthBuffer"),SceneJS.DepthBuf.prototype._init=function(a){void 0!=a.enabled?this.setEnabled(a.enabled):1==this._core.useCount&&this.setEnabled(!0),void 0!=a.clearDepth?this.setClearDepth(a.clearDepth):1==this._core.useCount&&this.setClearDepth(1),void 0!=a.depthFunc?this.setDepthFunc(a.depthFunc):1==this._core.useCount&&this.setDepthFunc("less"),void 0!=a.clear?this.setClear(a.clear):1==this._core.useCount&&this.setClear(!0)},SceneJS.DepthBuf.prototype.setEnabled=function(a){return this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getEnabled=function(){return this._core.enabled},SceneJS.DepthBuf.prototype.setClear=function(a){return this._core.clear!=a&&(this._core.clear=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClear=function(){return this._core.clear},SceneJS.DepthBuf.prototype.setClearDepth=function(a){return this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.DepthBuf.prototype.setDepthFunc=function(b){if(this._core._depthFuncName!=b){var c=a[b];if(void 0==c)throw"unsupported value for 'clearFunc' attribute on depthBuffer node: '"+b+"' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";this._core.depthFunc=this._engine.canvas.gl[c],this._core._depthFuncName=b,this._engine.display.imageDirty=!0}return this},SceneJS.DepthBuf.prototype.getDepthFunc=function(){return this._core._depthFuncName},SceneJS.DepthBuf.prototype._compile=function(a){this._engine.display.depthBuffer=c[d++]=this._core,this._compileNodes(a),this._engine.display.depthBuffer=--d>0?c[d-1]:b}}(),function(){var a={type:"colorBuffer",stateId:SceneJS._baseStateId++,blendEnabled:!1,colorMask:{r:!0,g:!0,b:!0,a:!0}},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.colorBuffer=a,c=0}),SceneJS.ColorBuffer=SceneJS_NodeFactory.createNodeType("colorBuffer"),SceneJS.ColorBuffer.prototype._init=function(a){void 0!=a.blendEnabled?this.setBlendEnabled(a.blendEnabled):1==this._core.useCount&&this.setBlendEnabled(!1),this.setColorMask(a)},SceneJS.ColorBuffer.prototype.setBlendEnabled=function(a){this._core.blendEnabled!=a&&(this._core.blendEnabled=a,this._engine.display.imageDirty=!0),this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getBlendEnabled=function(){return this._core.blendEnabled},SceneJS.ColorBuffer.prototype.setColorMask=function(a){this._core.colorMask={r:void 0!=a.r&&null!=a.r?a.r:!0,g:void 0!=a.g&&null!=a.g?a.g:!0,b:void 0!=a.b&&null!=a.b?a.b:!0,a:void 0!=a.a&&null!=a.a?a.a:!0},this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getColorMask=function(){return this._core.colorMask},SceneJS.ColorBuffer.prototype._compile=function(d){this._engine.display.colorBuffer=b[c++]=this._core,this._compileNodes(d),this._engine.display.colorBuffer=--c>0?b[c-1]:a,this._engine.display.imageDirty=!0}}(),function(){var a={type:"view",stateId:SceneJS._baseStateId++,scissorTestEnabled:!1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.view=a,c=0}),SceneJS.View=SceneJS_NodeFactory.createNodeType("view"),SceneJS.View.prototype._init=function(a){void 0!=a.scissorTestEnabled?this.setScissorTestEnabled(a.scissorTestEnabled):1==this._core.useCount&&this.setScissorTestEnabled(!1)},SceneJS.View.prototype.setScissorTestEnabled=function(a){return this._core.scissorTestEnabled!=a&&(this._core.scissorTestEnabled=a,this._engine.display.imageDirty=!0),this},SceneJS.View.prototype.getScissorTestEnabled=function(){return this._core.scissorTestEnabled},SceneJS.View.prototype._compile=function(d){this._engine.display.view=b[c++]=this._core,this._compileNodes(d),this._engine.display.view=--c>0?b[c-1]:a}}(),SceneJS.Scene=SceneJS_NodeFactory.createNodeType("scene"),SceneJS.Scene.prototype._init=function(a){a.tagMask&&this.setTagMask(a.tagMask),this._tagSelector=null,this.transparent=a.transparent===!0},SceneJS.Scene.prototype.loseWebGLContext=function(){this._engine.loseWebGLContext()},SceneJS.Scene.prototype.getCanvas=function(){return this._engine.canvas.canvas},SceneJS.Scene.prototype.getGL=function(){return this._engine.canvas.gl},SceneJS.Scene.prototype.getZBufferDepth=function(){var a=this._engine.canvas.gl;return a.getParameter(a.DEPTH_BITS)},SceneJS.Scene.prototype.setSSAAMultiplier=function(a){return this._engine.canvas.setSSAAMultiplier(a)},SceneJS.Scene.prototype.setTagMask=function(a){a=a||"XXXXXXXXXXXXXXXXXXXXXXXXXX",this._tagSelector||(this._tagSelector={}),this._tagSelector.mask=a,this._tagSelector.regex=a?new RegExp(a):null,this._engine.display.selectTags(this._tagSelector)},SceneJS.Scene.prototype.getTagMask=function(){return this._tagSelector?this._tagSelector.mask:null},SceneJS.Scene.prototype.setNumPasses=function(a){this._engine.setNumPasses(a)},SceneJS.Scene.prototype.renderFrame=function(a){return this._engine.renderFrame(a)},SceneJS.Scene.prototype.needFrame=function(){this._engine.display.imageDirty=!0},SceneJS.Scene.prototype.start=function(a){this._engine.start(a)},SceneJS.Scene.prototype.setFPS=function(a){this._engine.fps=a},SceneJS.Scene.prototype.pause=function(a){this._engine.pause(a)},SceneJS.Scene.prototype.isRunning=function(){return this._engine.running},SceneJS.Scene.prototype.pick=function(a,b,c){var d=this._engine.pick(a,b,c);return this.renderFrame({force:!0}),d?(this.publish("pick",d),d):void this.publish("nopick")},SceneJS.Scene.prototype.readPixels=function(a,b){return this._engine.readPixels(a,b)},SceneJS.Scene.prototype._destroy=function(){this.destroyed||(delete SceneJS._engines[this.id],SceneJS._engineIds.removeItem(this.id),this.destroyed=!0)},SceneJS.Scene.prototype.isActive=function(){return!this._engine.destroyed},SceneJS.Scene.prototype.stop=function(){this._engine.stop()},SceneJS.Scene.prototype.containsNode=function(a){return!!this._engine.findNode(a)},SceneJS.Scene.prototype.findNodes=function(a){return this._engine.findNodes(a)},SceneJS.Scene.prototype.findNode=function(a,b){return this.getNode(a,b)},SceneJS.Scene.prototype.getNode=function(a,b){var c=this._engine.findNode(a);return c?(b&&b(c),c):b?void this.once("nodes/"+a,b):null},SceneJS.Scene.prototype.hasCore=function(a,b){return this._engine.hasCore(a,b)},SceneJS.Scene.prototype.getStatus=function(){var a=SceneJS_sceneStatusModule.sceneStatus[this.id];return a?SceneJS._shallowClone(a):{destroyed:!0}},new function(){function a(a){for(var b,c,d={},e=0;i>e;e++){b=a[e];for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c])}return d}var b={type:"shader",stateId:SceneJS._baseStateId++,hash:"",empty:!0,shader:{}},c=[],d=[],e=[],f=[],g=[],h=[],i=0,j=!0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.shader=b,i=0,j=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(k){if(j){if(i>0){var l={type:"shader",stateId:c[i-1],hash:c.slice(0,i).join("."),shaders:{fragment:{code:f.slice(0,i).join(""),hooks:a(g)},vertex:{code:d.slice(0,i).join(""),hooks:a(e)}},paramsStack:h.slice(0,i)};k.display.shader=l}else k.display.shader=b;j=!1}}),SceneJS.Shader=SceneJS_NodeFactory.createNodeType("shader"),SceneJS.Shader.prototype._init=function(a){1==this._core.useCount&&(this._setShaders(a.shaders),this.setParams(a.params))},SceneJS.Shader.prototype._setShaders=function(a){a=a||[],this._core.shaders={};for(var b,c=0,d=a.length;d>c;c++){if(b=a[c],!b.stage)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"shader 'stage' attribute expected");var e;b.code&&(e=SceneJS._isArray(b.code)?b.code.join(""):b.code),this._core.shaders[b.stage]={code:e,hooks:b.hooks}}},SceneJS.Shader.prototype.setParams=function(a){a=a||{};var b=this._core.params;b||(b=this._core.params={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.Shader.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.Shader.prototype._compile=function(a){c[i]=this._core.coreId;var b=this._core.shaders,k=b.fragment||{},l=b.vertex||{};f[i]=k.code||"",g[i]=k.hooks||{},d[i]=l.code||"", +e[i]=l.hooks||{},h[i]=this._core.params||{},i++,j=!0,this._compileNodes(a),i--,j=!0}},new function(){var a,b={type:"shaderParams",stateId:SceneJS._baseStateId++,empty:!0},c=[],d=[],e=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(c){c.engine.display.shaderParams=b,e=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(e>0){var g={type:"shaderParams",stateId:c[e-1],paramsStack:d.slice(0,e)};f.display.shaderParams=g}else f.display.shaderParams=b;a=!1}}),SceneJS.ShaderParams=SceneJS_NodeFactory.createNodeType("shaderParams"),SceneJS.ShaderParams.prototype._init=function(a){1==this._core.useCount&&this.setParams(a.params)},SceneJS.ShaderParams.prototype.setParams=function(a){a=a||{};var b=this._core;b.params||(b.params={});for(var c in a)a.hasOwnProperty(c)&&(b.params[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.ShaderParams.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.ShaderParams.prototype._compile=function(b){c[e]=this._core.coreId,d[e]=this._core.params,e++,a=!0,this._compileNodes(b),e--,a=!0}},function(){var a={type:"style",stateId:SceneJS._baseStateId++,lineWidth:1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.style=a,c=0}),SceneJS.Style=SceneJS_NodeFactory.createNodeType("style"),SceneJS.Style.prototype._init=function(a){void 0!=a.lineWidth&&this.setLineWidth(a.lineWidth)},SceneJS.Style.prototype.setLineWidth=function(a){return this._core.lineWidth!=a&&(this._core.lineWidth=a,this._engine.display.imageDirty=!0),this},SceneJS.Style.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Style.prototype._compile=function(d){this._engine.display.style=b[c++]=this._core,this._compileNodes(d),this._engine.display.style=--c>0?b[c-1]:a}}(),function(){var a={type:"tag",stateId:SceneJS._baseStateId++,tag:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.tag=a,c=0}),SceneJS.Tag=SceneJS_NodeFactory.createNodeType("tag"),SceneJS.Tag.prototype._init=function(a){if(1==this._core.useCount){if(!a.tag)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"tag node attribute missing : 'tag'");this.setTag(a.tag)}},SceneJS.Tag.prototype.setTag=function(a){var b=this._core;b.tag=a,b.pattern=null,b.matched=!1,this._engine.display.drawListDirty=!0},SceneJS.Tag.prototype.getTag=function(){return this._core.tag},SceneJS.Tag.prototype._compile=function(d){this._engine.display.tag=b[c++]=this._core,this._compileNodes(d),this._engine.display.tag=--c>0?b[c-1]:a}}(),new function(){var a={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.texture=a,c=0}),SceneJS.Texture=SceneJS_NodeFactory.createNodeType("_texture"),SceneJS.Texture.prototype._init=function(a){if(1==this._core.useCount){this._core.layers=[],this._core.params={};var b=void 0==a.waitForLoad?!0:a.waitForLoad;if(!a.layers)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers missing");if(!SceneJS._isArray(a.layers))throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers should be an array");for(var c,d=this._engine.canvas.gl,e=0;ec;c++)h._loadLayerTexture(b,a[c])}}},SceneJS.Texture.prototype._loadLayerTexture=function(a,b){var c=this,d=b.source;if(d){if(!d.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"texture layer config expected: source.type");SceneJS.Plugins.getPlugin("texture",d.type,function(e){if(!e.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'getSource' method missing on plugin for texture source type '"+d.type+"'.");var f=e.getSource({gl:a});if(!f.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'subscribe' method missing on plugin for texture source type '"+d.type+"'");var g=SceneJS_sceneStatusModule.taskStarted(c,"Loading texture");f.subscribe(function(){var d=!1;return function(e){d?c._engine.display.imageDirty=!0:(d=!0,c._setLayerTexture(a,b,e),SceneJS_sceneStatusModule.taskFinished(g))}}()),f.configure&&f.configure(d),b._source=f})}else{var e=b.uri||b.src,f=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),g=new Image;g.onload=function(){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);var e=SceneJS_configsModule.configs.maxTextureSize;e&&(g=SceneJS._webgl.clampImageSize(g,e)),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c._ensureImageSizePowerOfTwo(g)),c._setLayerTexture(a,b,d),SceneJS_sceneStatusModule.taskFinished(f),c._engine.display.imageDirty=!0},g.onerror=function(){SceneJS_sceneStatusModule.taskFailed(f)},0==e.indexOf("data")?g.src=e:(g.crossOrigin="Anonymous",g.src=e)}},SceneJS.Texture.prototype._ensureImageSizePowerOfTwo=function(a){if(!this._isPowerOfTwo(a.width)||!this._isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=this._nextHighestPowerOfTwo(a.width),b.height=this._nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b,a.crossOrigin=""}return a},SceneJS.Texture.prototype._isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS.Texture.prototype._nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS.Texture.prototype._setLayerTexture=function(a,b,c){b.texture=new SceneJS._webgl.Texture2D(a,{texture:c,minFilter:this._getGLOption("minFilter",a,b,a.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",a,b,a.LINEAR),wrapS:this._getGLOption("wrapS",a,b,a.REPEAT),wrapT:this._getGLOption("wrapT",a,b,a.REPEAT),isDepth:this._getOption(b.isDepth,!1),depthMode:this._getGLOption("depthMode",a,b,a.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",a,b,a.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",a,b,a.LEQUAL),flipY:this._getOption(b.flipY,!0),width:this._getOption(b.width,1),height:this._getOption(b.height,1),internalFormat:this._getGLOption("internalFormat",a,b,a.LEQUAL),sourceFormat:this._getGLOption("sourceType",a,b,a.ALPHA),sourceType:this._getGLOption("sourceType",a,b,a.UNSIGNED_BYTE),update:null}),this.destroyed&&b.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._getGLOption=function(a,b,c,d){var e=c[a];if(void 0==e)return d;var f=SceneJS._webgl.enumMap[e];if(void 0==f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+e+"'");var g=b[f];return g},SceneJS.Texture.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.Texture.prototype.setLayer=function(a){if(void 0==a.index||null==a.index)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index null or undefined");if(a.index<0||a.index>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(parseInt(a.index),a),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype.setLayers=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._setLayer=function(a,b){b=b||{};var c=this._core.layers[a];if(void 0!=b.blendFactor&&null!=b.blendFactor&&(c.blendFactor=b.blendFactor),b.source){var d=c._source;d&&d.configure&&d.configure(b.source)}(b.translate||b.rotate||b.scale)&&this._setLayerTransform(b,c)},SceneJS.Texture.prototype._setLayerTransform=function(a,b){var c,d;if(a.translate){var e=a.translate;void 0!=e.x&&(b.translate.x=e.x),void 0!=e.y&&(b.translate.y=e.y),c=SceneJS_math_translationMat4v([e.x||0,e.y||0,0])}if(a.scale){var f=a.scale;void 0!=f.x&&(b.scale.x=f.x),void 0!=f.y&&(b.scale.y=f.y),d=SceneJS_math_scalingMat4v([f.x||1,f.y||1,1]),c=c?SceneJS_math_mulMat4(c,d):d}if(a.rotate){var g=a.rotate;void 0!=g.z&&(b.rotate.z=g.z||0),d=SceneJS_math_rotationMat4v(.0174532925*g.z,[0,0,1]),c=c?SceneJS_math_mulMat4(c,d):d}c&&(b.matrix=c,b.matrixAsArray?b.matrixAsArray.set(b.matrix):b.matrixAsArray=new Float32Array(b.matrix),b.matrixAsArray=new Float32Array(b.matrix))},SceneJS.Texture.prototype._compile=function(d){this._core.hash||this._makeHash(),this._engine.display.texture=b[c++]=this._core,this._compileNodes(d),this._engine.display.texture=--c>0?b[c-1]:a},SceneJS.Texture.prototype._makeHash=function(){var a,b=this._core;if(b.layers&&b.layers.length>0){for(var c,d=b.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");a=e.join("")}else a="";b.hash!=a&&(b.hash=a)},SceneJS.Texture.prototype._destroy=function(){if(1==this._core.useCount)for(var a,b,c=this._core.layers,d=0,e=c.length;e>d;d++)a=c[d],a.texture&&a.texture.destroy(),b=a._source,b&&b.destroy&&b.destroy()}},new function(){function a(){var a,b;(0!=this.translate.x||0!=this.translate.y)&&(a=SceneJS_math_translationMat4v([this.translate.x||0,this.translate.y||0,0])),(1!=this.scale.x||1!=this.scale.y)&&(b=SceneJS_math_scalingMat4v([this.scale.x||1,this.scale.y||1,1]),a=a?SceneJS_math_mulMat4(a,b):b),0!=this.rotate&&(b=SceneJS_math_rotationMat4v(.0174532925*this.rotate,[0,0,1]),a=a?SceneJS_math_mulMat4(a,b):b),a&&(this.matrix=a,this.matrixAsArray?this.matrixAsArray.set(this.matrix):this.matrixAsArray=new Float32Array(this.matrix)),this._matrixDirty=!1}var b={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.texture=b,d=0});var c=[],d=0;SceneJS.TextureMap=SceneJS_NodeFactory.createNodeType("texture"),SceneJS.TextureMap.prototype._init=function(b){var c=this;if(1==this._core.useCount){if(b.applyFrom&&"uv"!=b.applyFrom&&"uv2"!=b.applyFrom&&"normal"!=b.applyFrom&&"geometry"!=b.applyFrom)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyFrom value is unsupported - should be either 'uv', 'uv2', 'normal' or 'geometry'");if(b.applyTo&&"baseColor"!=b.applyTo&&"color"!=b.applyTo&&"specular"!=b.applyTo&&"emit"!=b.applyTo&&"alpha"!=b.applyTo&&"normals"!=b.applyTo&&"shine"!=b.applyTo)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyTo value is unsupported - should be either 'color', 'baseColor', 'specular' or 'normals'");if(b.blendMode&&"add"!=b.blendMode&&"multiply"!=b.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layer blendMode value is unsupported - should be either 'add' or 'multiply'");"color"==b.applyTo&&(b.applyTo="baseColor"),SceneJS._apply({waitForLoad:void 0==b.waitForLoad?!0:b.waitForLoad,texture:null,applyFrom:b.applyFrom?b.applyFrom:"uv",applyTo:b.applyTo?b.applyTo:"baseColor",blendMode:b.blendMode?b.blendMode:"multiply",blendFactor:void 0!=b.blendFactor&&null!=b.blendFactor?b.blendFactor:1,translate:b.translate?SceneJS._apply(b.translate,{x:0,y:0}):{x:0,y:0},scale:b.scale?SceneJS._apply(b.scale,{x:1,y:1}):{x:1,y:1},rotate:b.rotate||0,matrix:null,_matrixDirty:!0,buildMatrix:a},this._core),a.call(this._core),b.src?(this._core.src=b.src,this._loadTexture(b.src)):b.image?(this._core.image=b.image,this._initTexture(b.image)):b.target&&this.getScene().getNode(b.target,function(a){c.setTarget(a)}),this._core.webglRestored=function(){c._core.image?c._initTexture(c._core.image):c._core.src?c._loadTexture(c._core.src):c._core.target}}},SceneJS.TextureMap.prototype._loadTexture=function(a){var b=this,c=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),d=new Image;d.onload=function(){b._initTexture(d),SceneJS_sceneStatusModule.taskFinished(c),b._engine.display.imageDirty=!0},d.onerror=function(){SceneJS_sceneStatusModule.taskFailed(c)},0==a.indexOf("data")?d.src=a:(d.crossOrigin="Anonymous",d.src=a)},SceneJS.TextureMap.prototype._initTexture=function(a){var b=this._engine.canvas.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);var d=SceneJS_configsModule.configs.maxTextureSize;d&&(a=SceneJS._webgl.clampImageSize(a,d)),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(a)),this._core.image=a,this._core.texture=new SceneJS._webgl.Texture2D(b,{texture:c,minFilter:this._getGLOption("minFilter",b.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",b.LINEAR),wrapS:this._getGLOption("wrapS",b.REPEAT),wrapT:this._getGLOption("wrapT",b.REPEAT),isDepth:this._getOption(this._core.isDepth,!1),depthMode:this._getGLOption("depthMode",b.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",b.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",b.LEQUAL),flipY:this._getOption(this._core.flipY,!0),width:this._getOption(this._core.width,1),height:this._getOption(this._core.height,1),internalFormat:this._getGLOption("internalFormat",b.ALPHA),sourceFormat:this._getGLOption("sourceFormat",b.ALPHA),sourceType:this._getGLOption("sourceType",b.UNSIGNED_BYTE),update:null}),this.destroyed&&this._core.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype._getGLOption=function(a,b){var c=this._engine.canvas.gl,d=this._core[a];if(void 0==d)return b;var e=SceneJS._webgl.enumMap[d];if(void 0==e)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+d+"'");return c[e]},SceneJS.TextureMap.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.TextureMap.prototype.setSrc=function(a){this._core.image=null,this._core.src=a,this._core.target=null,this._loadTexture(a)},SceneJS.TextureMap.prototype.setImage=function(a){this._core.image=a,this._core.src=null,this._core.target=null,this._initTexture(a)},SceneJS.TextureMap.prototype.setTarget=function(a){return"colorTarget"!=a.type&&"depthTarget"!=a.type?void console.log("Target node type not compatible: "+a.type):(delete this._core.src,this._core.target=a,this._core.src=null,this._core.image=null,this._core.texture=a._core.renderBuf.getTexture(),this._core.texture.bufType=a._core.bufType,void(this._engine.display.imageDirty=!0))},SceneJS.TextureMap.prototype.setBlendFactor=function(a){this._core.blendFactor=a,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getBlendFactor=function(){return this._core.blendFactor},SceneJS.TextureMap.prototype.setTranslate=function(a){this._core.translate||(this._core.translate={x:0,y:0}),this._core.translate.x=a.x,this._core.translate.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getTranslate=function(){return this._core.translate},SceneJS.TextureMap.prototype.setScale=function(a){this._core.scale||(this._core.scale={x:0,y:0}),this._core.scale.x=a.x,this._core.scale.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getScale=function(){return this._core.scale},SceneJS.TextureMap.prototype.setRotate=function(a){this._core.rotate=a,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getRotate=function(){return this._core.rotate},SceneJS.TextureMap.prototype.getMatrix=function(){return this._core._matrixDirty&&this._core.buildMatrix.call(this.core)(),this.core.matrix},SceneJS.TextureMap.prototype._compile=function(a){this.__core||(this.__core=this._engine._coreFactory.getCore("texture"));var e=this._engine.display.texture;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),c[d++]=this.__core,this._engine.display.texture=this.__core,this._compileNodes(a),this._engine.display.texture=--d>0?c[d-1]:b},SceneJS.TextureMap.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.TextureMap.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&!this._core.target&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}},function(){var a={type:"cubemap",stateId:SceneJS._baseStateId++,empty:!0,texture:null,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.cubemap=a,c=0}),SceneJS.Reflect=SceneJS_NodeFactory.createNodeType("reflect"),SceneJS.Reflect.prototype._init=function(a){if(1==this._core.useCount){if(this._core.hash="y",a.blendMode&&"add"!=a.blendMode&&"multiply"!=a.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"reflection blendMode value is unsupported - should be either 'add' or 'multiply'");this._core.blendMode=a.blendMode||"multiply",this._core.intensity=void 0!=a.intensity&&null!=a.intensity?a.intensity:1,this._core.applyTo="reflect";for(var b=this,c=this._engine.canvas.gl,d=c.createTexture(),e=[c.TEXTURE_CUBE_MAP_POSITIVE_X,c.TEXTURE_CUBE_MAP_NEGATIVE_X,c.TEXTURE_CUBE_MAP_POSITIVE_Y,c.TEXTURE_CUBE_MAP_NEGATIVE_Y,c.TEXTURE_CUBE_MAP_POSITIVE_Z,c.TEXTURE_CUBE_MAP_NEGATIVE_Z],f=[],g=SceneJS_sceneStatusModule.taskStarted(this,"Loading reflection texture"),h=!1,i=0;ii;i++)c.texImage2D(e[i],0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(f[i]));b._core.texture=new SceneJS._webgl.Texture2D(c,{texture:d,target:c.TEXTURE_CUBE_MAP,minFilter:c.LINEAR,magFilter:c.LINEAR,wrapS:c.CLAMP_TO_EDGE,wrapT:c.CLAMP_TO_EDGE}),SceneJS_sceneStatusModule.taskFinished(g),b._engine.display.imageDirty=!0}}}(),j.onerror=function(){h=!0,SceneJS_sceneStatusModule.taskFailed(g)},j.src=a.src[i]}}},SceneJS.Reflect.prototype._compile=function(d){this.__core||(this.__core=this._engine._coreFactory.getCore("cubemap"));var e=this._engine.display.cubemap;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),b[c++]=this.__core,this._engine.display.cubemap=this.__core,this._compileNodes(d),this._engine.display.cubemap=--c>0?b[c-1]:a},SceneJS.Reflect.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode);b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.Reflect.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}}(),SceneJS.XForm=SceneJS_NodeFactory.createNodeType("xform"),SceneJS.XForm.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.XForm.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.XForm.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.XForm.prototype.setElements=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.XForm elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.XForm.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Matrix=SceneJS_NodeFactory.createNodeType("matrix"),SceneJS.Matrix.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.Matrix.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Matrix.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Matrix.prototype.setMatrix=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Matrix elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Matrix.prototype.setElements=SceneJS.Matrix.prototype.setMatrix,SceneJS.Matrix.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Rotate=SceneJS_NodeFactory.createNodeType("rotate"),SceneJS.Rotate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setAngle(a.angle),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_rotationMat4v(b.angle*Math.PI/180,[b.x,b.y,b.z])}}},SceneJS.Rotate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Rotate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Rotate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for rotate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.setAngle=function(a){this._core.angle=a||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getAngle=function(){return this._core.angle},SceneJS.Rotate.prototype.setXYZ=function(a){a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Rotate.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getX=function(){return this._core.x},SceneJS.Rotate.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getY=function(){return this._core.y},SceneJS.Rotate.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getZ=function(){return this._core.z},SceneJS.Rotate.prototype.incAngle=function(a){this._core.angle+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Translate=SceneJS_NodeFactory.createNodeType("translate"),SceneJS.Translate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_translationMat4v([b.x,b.y,b.z],b.matrix)}}},SceneJS.Translate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Translate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Translate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for translate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Translate.prototype.setXYZ=function(a){return a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Translate.prototype.setX=function(a){return this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setY=function(a){return this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setZ=function(a){return this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incX=function(a){return this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incY=function(a){return this._core.y+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incZ=function(a){return this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getX=function(){return this._core.x},SceneJS.Translate.prototype.getY=function(){return this._core.y},SceneJS.Translate.prototype.getZ=function(){return this._core.z},SceneJS.Translate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Scale=SceneJS_NodeFactory.createNodeType("scale"),SceneJS.Scale.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_scalingMat4v([b.x,b.y,b.z])}}},SceneJS.Scale.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Scale.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Scale.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for scale node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setXYZ=function(a){a=a||{},this._core.x=void 0==a.x?1:a.x,this._core.y=void 0==a.y?1:a.y,this._core.z=void 0==a.z?1:a.z,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Scale.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getX=function(){return this._core.x},SceneJS.Scale.prototype.getY=function(){return this._core.y},SceneJS.Scale.prototype.getZ=function(){return this._core.z},SceneJS.Scale.prototype.incX=function(a){this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.incY=function(a){this._core.y+=a,this._core.matrixDirty=!0},SceneJS.Scale.prototype.incZ=function(a){this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()};var SceneJS_modelXFormStack=new function(){var a=SceneJS_math_identityMat4(),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(SceneJS_math_identityMat4(),SceneJS_math_mat4())),d=new Float32Array(c),e={type:"xform",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,parent:null,cores:[],numCores:0,dirty:!1,matrixDirty:!1},f=[],g=0;this.top=e;var h,i=this;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){g=0,i.top=e,h=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(a){h&&(g>0?a.display.modelTransform=f[g-1]:a.display.modelTransform=e,h=!1)}),this.buildCore=function(a){function b(a){a.dirty=!0,a.matrixDirty=!0;for(var c=0,d=a.numCores;d>c;c++)b(a.cores[c])}a.parent=null,a.cores=[],a.numCores=0,a.matrixDirty=!1,a.matrix=SceneJS_math_identityMat4(),a.mat=new Float32Array(a.matrix),a.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(a.matrix,SceneJS_math_mat4()))),a.dirty=!1,a.setDirty=function(){a.matrixDirty=!0,a.dirty,b(a)},a.build=function(){a.matrixDirty&&(a.buildMatrix&&a.buildMatrix(),a.matrixDirty=!1);var b,c=a.parent;if(c)for(b=a.matrix.slice(0);c;)c.matrixDirty&&(c.buildMatrix&&c.buildMatrix(),c.mat.set(c.matrix),c.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(c.matrix,SceneJS_math_mat4()))),c.matrixDirty=!1),SceneJS_math_mulMat4(c.matrix,b,b),!c.dirty,c=c.parent;else b=a.matrix;a.mat.set(b),a.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4()))),a.dirty=!1}},this.push=function(a){f[g++]=a,a.parent=this.top,a.dirty=!0,this.top&&(this.top.cores[this.top.numCores++]=a),a.numCores=0,this.top=a,h=!0},this.pop=function(){this.top=--g>0?f[g-1]:e,h=!0}};SceneJS.Types=new function(){this.addType=function(a,b){SceneJS_NodeFactory.createNodeType(a,b,function(a){var c;for(var d in b)if(b.hasOwnProperty(d))switch(c=b[d],d){case"init":case"construct":!function(){var c=b[d];a.prototype._init=function(a){c.call(this,a)},a.prototype._fromPlugin=!0}();break;case"destroy":case"destruct":a.prototype._destroy=c;break;default:a.prototype[d]=c}})},this.hasType=function(a){return!!SceneJS_NodeFactory.nodeTypes[a]}};var SceneJS_Display=function(a){this._canvas=a.canvas,this._programFactory=new SceneJS_ProgramFactory({canvas:a.canvas}),this._chunkFactory=new SceneJS_ChunkFactory,this.transparent=a.transparent===!0, +this.enable=null,this.flags=null,this.layer=null,this.stage=null,this.renderer=null,this.depthBuffer=null,this.colorBuffer=null,this.view=null,this.lights=null,this.material=null,this.texture=null,this.cubemap=null,this.modelTransform=null,this.viewTransform=null,this.projTransform=null,this.renderTarget=null,this.clips=null,this.morphGeometry=null,this.name=null,this.tag=null,this.renderListeners=null,this.shader=null,this.shaderParams=null,this.style=null,this.geometry=null,this._objectFactory=new SceneJS_ObjectFactory,this._objects={},this._ambientColor=[0,0,0,1],this._objectList=[],this._objectListLen=0,this._drawList=[],this._drawListLen=0,this._pickDrawList=[],this._pickDrawListLen=0,this._targetList=[],this._targetListLen=0,this._frameCtx={pickNames:[],canvas:this._canvas,VAO:null},this._frameCtx.renderListenerCtx=new SceneJS.RenderContext(this._frameCtx),this.objectListDirty=!0,this.stateOrderDirty=!0,this.stateSortDirty=!0,this.drawListDirty=!0,this.imageDirty=!0,this.pickBufDirty=!0,this.rayPickBufDirty=!0};SceneJS_Display.prototype.webglRestored=function(){this._programFactory.webglRestored(),this._chunkFactory.webglRestored();var a=this._canvas.gl;this.pickBuf&&this.pickBuf.webglRestored(a),this.rayPickBuf&&this.rayPickBuf.webglRestored(a),this.imageDirty=!0},SceneJS_Display.prototype.buildObject=function(a){var b=this._objects[a];b||(b=this._objects[a]=this._objectFactory.getObject(a),this.objectListDirty=!0),b.stage=this.stage,b.layer=this.layer,b.renderTarget=this.renderTarget,b.texture=this.texture,b.cubemap=this.cubemap,b.geometry=this.geometry,b.enable=this.enable,b.flags=this.flags,b.tag=this.tag;var c=[this.geometry.hash,this.shader.hash,this.clips.hash,this.morphGeometry.hash,this.texture.hash,this.cubemap.hash,this.lights.hash,this.flags.hash].join(";");b.program&&c==b.hash||(b.program&&this._programFactory.putProgram(b.program),b.program=this._programFactory.getProgram(c,this),b.hash=c),this._setChunk(b,0,"program"),this._setChunk(b,1,"xform",this.modelTransform),this._setChunk(b,2,"lookAt",this.viewTransform),this._setChunk(b,3,"camera",this.projTransform),this._setChunk(b,4,"flags",this.flags),this._setChunk(b,5,"shader",this.shader),this._setChunk(b,6,"shaderParams",this.shaderParams),this._setChunk(b,7,"style",this.style),this._setChunk(b,8,"depthBuffer",this.depthBuffer),this._setChunk(b,9,"colorBuffer",this.colorBuffer),this._setChunk(b,10,"view",this.view),this._setChunk(b,11,"name",this.name),this._setChunk(b,12,"lights",this.lights),this._setChunk(b,13,"material",this.material),this._setChunk(b,14,"texture",this.texture),this._setChunk(b,15,"cubemap",this.cubemap),this._setChunk(b,16,"clips",this.clips),this._setChunk(b,17,"renderer",this.renderer),this._setChunk(b,18,"geometry",this.morphGeometry,this.geometry),this._setChunk(b,19,"listeners",this.renderListeners),this._setChunk(b,20,"draw",this.geometry)},SceneJS_Display.prototype._setChunk=function(a,b,c,d,e){var f,g=this._chunkFactory.chunkTypes[c];if(d){if(d.empty){var h=a.chunks[b];return h&&this._chunkFactory.putChunk(h),void(a.chunks[b]=null)}f=g.prototype.programGlobal?"_"+d.stateId:"p"+a.program.id+"_"+d.stateId,e&&(f+="__"+e.stateId)}else f="p"+a.program.id;f=b+"__"+f;var h=a.chunks[b];if(h){if(h.id==f)return;this._chunkFactory.putChunk(h)}a.chunks[b]=this._chunkFactory.getChunk(f,c,a.program,d,e),"lights"==c&&this._setAmbient(d)},SceneJS_Display.prototype._setAmbient=function(a){for(var b,c=a.lights,d=0,e=c.length;e>d;d++)b=c[d],"ambient"==b.mode&&(this._ambientColor[0]=b.color[0],this._ambientColor[1]=b.color[1],this._ambientColor[2]=b.color[2])},SceneJS_Display.prototype.removeObject=function(a){var b=this._objects[a];b&&(this._programFactory.putProgram(b.program),b.program=null,b.hash=null,this._objectFactory.putObject(b),delete this._objects[a],this.objectListDirty=!0)},SceneJS_Display.prototype.selectTags=function(a){this._tagSelector=a,this.drawListDirty=!0},SceneJS_Display.prototype.render=function(a){a=a||{},this.objectListDirty&&(this._buildObjectList(),this.objectListDirty=!1,this.stateOrderDirty=!0),this.stateOrderDirty&&(this._makeStateSortKeys(),this.stateOrderDirty=!1,this.stateSortDirty=!0),this.stateSortDirty&&(this._stateSort(),this.stateSortDirty=!1,this.drawListDirty=!0),this.drawListDirty&&(this._buildDrawList(),this.imageDirty=!0),(this.imageDirty||a.force)&&(this._doDrawList({clear:a.clear!==!1}),this.imageDirty=!1,this.pickBufDirty=!0)},SceneJS_Display.prototype._buildObjectList=function(){this._objectListLen=0;for(var a in this._objects)this._objects.hasOwnProperty(a)&&(this._objectList[this._objectListLen++]=this._objects[a])},SceneJS_Display.prototype._makeStateSortKeys=function(){for(var a,b=0,c=this._objectListLen;c>b;b++)a=this._objectList[b],a.program?a.sortKey=1e12*(a.stage.priority+1)+1e9*(a.flags.transparent?2:1)+1e6*(a.layer.priority+1)+1e3*(a.program.id+1)+a.texture.stateId:a.sortKey=-1},SceneJS_Display.prototype._stateSort=function(){this._objectList.length=this._objectListLen,this._objectList.sort(this._stateSortObjects)},SceneJS_Display.prototype._stateSortObjects=function(a,b){return a.sortKey-b.sortKey},SceneJS_Display.prototype._logObjectList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._objectListLen+" objects");for(var a=0,b=this._objectListLen;b>a;a++){var c=this._objectList[a];console.log("SceneJS_Display : object["+a+"] sortKey = "+c.sortKey)}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._buildDrawList=function(){this._lastStateId=this._lastStateId||[],this._lastPickStateId=this._lastPickStateId||[];for(var a=0;23>a;a++)this._lastStateId[a]=null,this._lastPickStateId[a]=null;this._drawListLen=0,this._pickDrawListLen=0;var b,c,d,e,f,g={},h=[],i=[];this._tagSelector&&(c=this._tagSelector.mask,d=this._tagSelector.regex),this._objectDrawList=this._objectDrawList||[],this._objectDrawListLen=0;for(var a=0,j=this._objectListLen;j>a;a++)if(b=this._objectList[a],b.enable.enabled!==!1&&(f=b.flags,f.enabled!==!1&&b.layer.enabled&&(!c||(e=b.tag,!e.tag||(e.mask!=c&&(e.mask=c,e.matches=d.test(e.tag)),e.matches)))))if(b.renderTarget.targets)for(var k,l,m,n=b.renderTarget.targets,o=0,p=n.length;p>o;o++)k=n[o],l=k.coreId,m=g[l],m||(m=[],g[l]=m,h.push(m),i.push(this._chunkFactory.getChunk(k.stateId,"renderTarget",b.program,k))),m.push(b);else this._objectDrawList[this._objectDrawListLen++]=b;for(var m,k,b,q,a=0,j=h.length;j>a;a++){m=h[a],k=i[a],this._appendRenderTargetChunk(k);for(var o=0,p=m.length;p>o;o++)b=m[o],q=b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q)}b&&this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1,"renderTarget",b.program,{}));for(var a=0,j=this._objectDrawListLen;j>a;a++)b=this._objectDrawList[a],q=!b.stage||b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q);this.drawListDirty=!1},SceneJS_Display.prototype._appendRenderTargetChunk=function(a){this._drawList[this._drawListLen++]=a},SceneJS_Display.prototype._appendObjectToDrawLists=function(a,b){for(var c,d=a.chunks,e=a.flags.picking,f=0,g=d.length;g>f;f++)c=d[f],c&&(c.draw&&(c.unique||this._lastStateId[f]!=c.id)&&(this._drawList[this._drawListLen++]=c,this._lastStateId[f]=c.id),c.pick&&b!==!1&&e&&(c.unique||this._lastPickStateId[f]!=c.id)&&(this._pickDrawList[this._pickDrawListLen++]=c,this._lastPickStateId[f]=c.id))},SceneJS_Display.prototype._logDrawList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._drawListLen+" draw list chunks");for(var a=0,b=this._drawListLen;b>a;a++){var c=this._drawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._logPickList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._pickDrawListLen+" pick list chunks");for(var a=0,b=this._pickDrawListLen;b>a;a++){var c=this._pickDrawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype.pick=function(a){var b=this._canvas.canvas,c=this._canvas.ssaaMultiplier,d=null,e=a.canvasX*c,f=a.canvasY*c,g=this.pickBuf;g||(g=this.pickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.pickBufDirty=!0),this.render(),g.bind(),this.pickBufDirty&&(g.clear(),this._doDrawList({pick:!0,clear:!0}),this._canvas.gl.finish(),this.pickBufDirty=!1,this.rayPickBufDirty=!0);var h=g.read(e,f),i=h[0]+256*h[1]+65536*h[2],j=i>=1?i-1:-1;g.unbind();var k=this._frameCtx.pickNames[j];if(k&&(d={name:k.name,path:k.path,nodeId:k.nodeId,canvasPos:[e,f]},a.rayPick)){var l=this.rayPickBuf;l||(l=this.rayPickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.rayPickBufDirty=!0),l.bind(),this.rayPickBufDirty&&(l.clear(),this._doDrawList({pick:!0,rayPick:!0,clear:!0}),this.rayPickBufDirty=!1),h=l.read(e,f),l.unbind();var m=this._unpackDepth(h),n=b.width,o=b.height,p=(e-n/2)/(n/2),q=-(f-o/2)/(o/2),r=this._frameCtx.cameraMat,s=this._frameCtx.viewMat,t=SceneJS_math_mulMat4(r,s,[]),u=SceneJS_math_inverseMat4(t,[]),v=SceneJS_math_transformVector4(u,[p,q,-1,1]);v=SceneJS_math_mulVec4Scalar(v,1/v[3]);var w=SceneJS_math_transformVector4(u,[p,q,1,1]);w=SceneJS_math_mulVec4Scalar(w,1/w[3]);var x=SceneJS_math_subVec3(w,v,[]),y=SceneJS_math_addVec3(v,SceneJS_math_mulVec4Scalar(x,m,[]),[]);d.worldPos=y}return d},SceneJS_Display.prototype.readPixels=function(a,b){this._readPixelBuf||(this._readPixelBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas})),this._readPixelBuf.bind(),this._readPixelBuf.clear(),this.render({force:!0});for(var c,d,e=0;b>e;e++)c=a[e]||(a[e]={}),d=this._readPixelBuf.read(c.x,c.y),c.r=d[0],c.g=d[1],c.b=d[2],c.a=d[3];this._readPixelBuf.unbind()},SceneJS_Display.prototype._unpackDepth=function(a){var b=[a[0]/256,a[1]/256,a[2]/256,a[3]/256],c=[1/16777216,1/65536,1/256,1];return SceneJS_math_dotVector4(b,c)},SceneJS_Display.prototype._doDrawList=function(a){var b=this._canvas.gl,c=this._frameCtx;c.renderTarget=null,c.targetIndex=0,c.renderBuf=null,c.viewMat=null,c.modelMat=null,c.cameraMat=null,c.renderer=null,c.depthbufEnabled=null,c.clearDepth=null,c.depthFunc=b.LESS,c.scissorTestEnabled=!1,c.blendEnabled=!1,c.backfaces=!0,c.frontface="ccw",c.pick=!!a.pick,c.rayPick=!!a.rayPick,c.pickIndex=0,c.textureUnit=0,c.lineWidth=1,c.transparent=!1,c.ambientColor=this._ambientColor,c.aspect=this._canvas.canvas.width/this._canvas.canvas.height,this._canvas.UINT_INDEX_ENABLED&&b.getExtension("OES_element_index_uint");var d=b.getExtension("OES_vertex_array_object");if(c.VAO=d?d:null,b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),this.transparent?b.clearColor(0,0,0,0):b.clearColor(this._ambientColor[0],this._ambientColor[1],this._ambientColor[2],1),a.clear&&b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),b.frontFace(b.CCW),b.disable(b.CULL_FACE),b.disable(b.BLEND),a.pick)for(var e=0,f=this._pickDrawListLen;f>e;e++)this._pickDrawList[e].pick(c);else for(var e=0,f=this._drawListLen;f>e;e++)this._drawList[e].draw(c);if(b.flush(),c.renderBuf&&c.renderBuf.unbind(),c.VAO){c.VAO.bindVertexArrayOES(null);for(var e=0;10>e;e++)b.disableVertexAttribArray(e)}},SceneJS_Display.prototype.destroy=function(){this._programFactory.destroy()};var SceneJS_ProgramSourceFactory=new function(){function a(a){if(a.renderTarget&&a.renderTarget.targets)for(var b=a.renderTarget.targets,c=0,d=b.length;d>c;c++)if("depth"===b[c].bufType)return!0;return!1}this._sourceCache={},this.getSource=function(a,b){var c=this._sourceCache[a];return c?(c.useCount++,c):this._sourceCache[a]=new SceneJS_ProgramSource(a,this._composePickingVertexShader(b),this._composePickingFragmentShader(b),this._composeRenderingVertexShader(b),this._composeRenderingFragmentShader(b))},this.putSource=function(a){var b=this._sourceCache[a];b&&0==--b.useCount&&(this._sourceCache[b.hash]=null)},this._composePickingVertexShader=function(a){var b=!!a.morphGeometry.targets,c=["precision mediump float;","attribute vec3 SCENEJS_aVertex;","uniform mat4 SCENEJS_uMMatrix;","uniform mat4 SCENEJS_uVMatrix;","uniform mat4 SCENEJS_uVNMatrix;","uniform mat4 SCENEJS_uPMatrix;"];return c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),b&&(c.push("uniform float SCENEJS_uMorphFactor;"),a.morphGeometry.targets[0].vertexBuf&&c.push("attribute vec3 SCENEJS_aMorphVertex;")),c.push("void main(void) {"),c.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "),b&&a.morphGeometry.targets[0].vertexBuf&&c.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "),c.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "),c.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"),c.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"),c.push("}"),c},this._composePickingFragmentShader=function(a){var b=a.clips.clips.length>0,c=["precision mediump float;"];if(c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),c.push("uniform bool SCENEJS_uRayPickMode;"),c.push("uniform vec3 SCENEJS_uPickColor;"),c.push("uniform float SCENEJS_uZNear;"),c.push("uniform float SCENEJS_uZFar;"),c.push("uniform bool SCENEJS_uClipping;"),b)for(var d=0;d 0.0) { discard; }"),c.push("}")}return c.push(" if (SCENEJS_uRayPickMode) {"),c.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"),c.push(" gl_FragColor = packDepth(zNormalizedDepth); "),c.push(" } else {"),c.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "),c.push(" }"),c.push("}"),c},this._isTexturing=function(a){if(a.texture.layers&&a.texture.layers.length>0){if(a.geometry.uvBuf||a.geometry.uvBuf2)return!0;if(a.morphGeometry.targets&&(a.morphGeometry.targets[0].uvBuf||a.morphGeometry.targets[0].uvBuf2))return!0}return!1},this._isCubeMapping=function(a){return a.flags.reflective&&a.cubemap.layers&&a.cubemap.layers.length>0&&a.geometry.normalBuf},this._hasNormals=function(a){return a.geometry.normalBuf?!0:a.morphGeometry.targets&&a.morphGeometry.targets[0].normalBuf?!0:!1},this._hasTangents=function(a){if(a.texture){var b=a.texture.layers;if(!b)return!1;for(var c=0,d=b.length;d>c;c++)if("normals"==b[c].applyTo)return!0}return!1},this._composeRenderingVertexShader=function(a){var b=a.shader.shaders||{};if(b.vertex&&b.vertex.code&&""!=b.vertex.code&&SceneJS._isEmpty(b.vertex.hooks))return[b.vertex.code];var c=b.vertex||{},d=c.hooks||{},e=b.fragment||{},f=e.hooks||{},g=this._isTexturing(a),h=this._hasNormals(a),i=this._hasTangents(a),j=a.clips.clips.length>0,k=!!a.morphGeometry.targets,l=["precision mediump float;"];if(l.push("uniform mat4 SCENEJS_uMMatrix;"),l.push("uniform mat4 SCENEJS_uVMatrix;"),l.push("uniform mat4 SCENEJS_uPMatrix;"),l.push("attribute vec3 SCENEJS_aVertex;"),l.push("uniform vec3 SCENEJS_uWorldEye;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("attribute vec3 SCENEJS_aNormal;"),l.push("uniform mat4 SCENEJS_uMNMatrix;"),l.push("uniform mat4 SCENEJS_uVNMatrix;"),l.push("varying vec3 SCENEJS_vViewNormal;"),i&&l.push("attribute vec4 SCENEJS_aTangent;");for(var m=0;m0,l=["\n"];if(l.push("precision mediump float;"),k&&l.push("varying vec4 SCENEJS_vWorldVertex;"),l.push("varying vec4 SCENEJS_vViewVertex;"),l.push("uniform float SCENEJS_uZNear;"),l.push("uniform float SCENEJS_uZFar;"),k)for(var m=0;mm;m++)n=b.texture.layers[m],l.push("uniform sampler2D SCENEJS_uSampler"+m+";"),n.matrix&&l.push("uniform mat4 SCENEJS_uLayer"+m+"Matrix;"),l.push("uniform float SCENEJS_uLayer"+m+"BlendFactor;")}if(h&&g)for(var n,m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("uniform samplerCube SCENEJS_uCubeMapSampler"+m+";"),l.push("uniform float SCENEJS_uCubeMapIntensity"+m+";");if(l.push("uniform bool SCENEJS_uClipping;"),l.push("uniform bool SCENEJS_uSolid;"),l.push("uniform bool SCENEJS_uDepthMode;"),l.push("uniform bool SCENEJS_uTransparent;"),b.geometry.colorBuf&&l.push("varying vec4 SCENEJS_vColor;"),l.push("uniform vec3 SCENEJS_uAmbientColor;"),l.push("uniform vec3 SCENEJS_uMaterialColor;"),l.push("uniform float SCENEJS_uMaterialAlpha;"),l.push("uniform float SCENEJS_uMaterialEmit;"),l.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"),l.push("uniform float SCENEJS_uMaterialSpecular;"),l.push("uniform float SCENEJS_uMaterialShine;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("varying vec3 SCENEJS_vViewNormal;");for(var p,m=0;m 0.0) { discard; }"),l.push("}")}h&&i&&(l.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"),l.push(" if (a < 0.0) {"),l.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"),l.push(" return;"),l.push(" }")),l.push(" vec3 ambient= SCENEJS_uAmbientColor;"),f&&b.geometry.uvBuf&&e.texturePos&&l.push(e.texturePos+"(SCENEJS_vUVCoord);"),e.viewPos&&l.push(e.viewPos+"(SCENEJS_vViewVertex);"),h&&e.viewNormal&&l.push(e.viewNormal+"(SCENEJS_vViewNormal);"),b.geometry.colorBuf?l.push(" vec3 color = SCENEJS_vColor.rgb;"):l.push(" vec3 color = SCENEJS_uMaterialColor;"),l.push(" float alpha = SCENEJS_uMaterialAlpha;"),l.push(" float emit = SCENEJS_uMaterialEmit;"),l.push(" float specular = SCENEJS_uMaterialSpecular;"),l.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"),l.push(" float shine = SCENEJS_uMaterialShine;"),e.materialBaseColor&&l.push("color="+e.materialBaseColor+"(color);"),e.materialAlpha&&l.push("alpha="+e.materialAlpha+"(alpha);"),e.materialEmit&&l.push("emit="+e.materialEmit+"(emit);"),e.materialSpecular&&l.push("specular="+e.materialSpecular+"(specular);"),e.materialSpecularColor&&l.push("specularColor="+e.materialSpecularColor+"(specularColor);"),e.materialShine&&l.push("shine="+e.materialShine+"(shine);"),h&&(l.push(" float attenuation = 1.0;"),j?l.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"):l.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"));var n;if(f){l.push(" vec4 texturePos;"),l.push(" vec2 textureCoord=vec2(0.0,0.0);");for(var m=0,o=b.texture.layers.length;o>m;m++){if(n=b.texture.layers[m],"normal"==n.applyFrom&&h){if(!b.geometry.normalBuf){SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors");continue}l.push("texturePos=vec4(viewNormalVec.xyz, 1.0);")}if("uv"==n.applyFrom){if(!b.geometry.uvBuf){SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);")}if("uv2"==n.applyFrom){if(!b.geometry.uvBuf2){SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);")}n.matrix?l.push("textureCoord=(SCENEJS_uLayer"+m+"Matrix * texturePos).xy;"):l.push("textureCoord=texturePos.xy;"),"alpha"==n.applyTo&&("multiply"==n.blendMode?l.push("alpha = alpha * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"):"add"==n.blendMode&&l.push("alpha = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * alpha) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);")),"baseColor"==n.applyTo&&("multiply"==n.blendMode?l.push("color = color * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"):l.push("color = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * color) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);")),"emit"==n.applyTo&&("multiply"==n.blendMode?l.push("emit = emit * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("emit = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * emit) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"specular"==n.applyTo&&h&&("multiply"==n.blendMode?l.push("specular = specular * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("specular = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * specular) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"shine"==n.applyTo&&("multiply"==n.blendMode?l.push("shine = shine * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("shine = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * shine) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"normals"==n.applyTo&&h&&l.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);")}}if(h&&g){l.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"),l.push("envLookup.y = envLookup.y * -1.0;"),l.push("vec4 envColor;");for(var m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("envColor = textureCube(SCENEJS_uCubeMapSampler"+m+", envLookup);"),l.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity"+m+");")}if(l.push(" vec4 fragColor;"),h){l.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 viewLightVec;"),l.push(" float dotN;"),l.push(" float lightDist;");for(var p,m=0,o=b.lights.lights.length;o>m;m++)p=b.lights.lights[m],"ambient"!=p.mode&&(l.push("viewLightVec = SCENEJS_vViewLightVecAndDist"+m+".xyz;"),"point"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),l.push("lightDist = SCENEJS_vViewLightVecAndDist"+m+".w;"),l.push("attenuation = 1.0 - ( SCENEJS_uLightAttenuation"+m+"[0] + SCENEJS_uLightAttenuation"+m+"[1] * lightDist + SCENEJS_uLightAttenuation"+m+"[2] * lightDist * lightDist);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+" * attenuation;"),p.specular&&l.push(" specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;")),"dir"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+";"),p.specular&&l.push("specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);")));l.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);")}else l.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);");return e.pixelColor&&l.push("fragColor="+e.pixelColor+"(fragColor);"),a(b)?(l.push(" if (SCENEJS_uDepthMode) {"),l.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"),l.push(" const vec4 bias = vec4(1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 0.0);"),l.push(" float r = depth;"),l.push(" float g = fract(r * 255.0);"),l.push(" float b = fract(g * 255.0);"),l.push(" float a = fract(b * 255.0);"),l.push(" vec4 colour = vec4(r, g, b, a);"),l.push(" gl_FragColor = colour - (colour.yzww * bias);"),l.push(" } else {"),l.push(" gl_FragColor = fragColor;"),l.push(" };")):l.push(" gl_FragColor = fragColor;"),l.push("}"),l}},SceneJS_ProgramSource=function(a,b,c,d,e){this.hash=a,this.pickVertexSrc=b,this.pickFragmentSrc=c,this.drawVertexSrc=d,this.drawFragmentSrc=e,this.useCount=0},SceneJS_ProgramFactory=function(a){this._canvas=a.canvas,this._programs={},this._nextProgramId=0};SceneJS_ProgramFactory.prototype.getProgram=function(a,b){var c=this._programs[a];if(!c){var d=SceneJS_ProgramSourceFactory.getSource(a,b);c=new SceneJS_Program(this._nextProgramId++,a,d,this._canvas.gl),this._programs[a]=c}return c.useCount++,c},SceneJS_ProgramFactory.prototype.putProgram=function(a){--a.useCount<=0&&(a.draw.destroy(),a.pick.destroy(),SceneJS_ProgramSourceFactory.putSource(a.hash),delete this._programs[a.hash])},SceneJS_ProgramFactory.prototype.webglRestored=function(){var a,b=this._canvas.gl;for(var c in this._programs)this._programs.hasOwnProperty(c)&&(a=this._programs[c],a&&a.build&&a.build(b))},SceneJS_ProgramFactory.prototype.destroy=function(){};var SceneJS_Program=function(a,b,c,d){this.id=a,this.hash=c.hash,this.source=c,this.gl=d,this.UINT_INDEX_ENABLED=!!d.getExtension("OES_element_index_uint"),this.draw=null,this.pick=null,this.useCount=0,this.build(d)};SceneJS_Program.prototype.build=function(a){this.gl=a,this.draw=new SceneJS._webgl.Program(a,[this.source.drawVertexSrc.join("\n")],[this.source.drawFragmentSrc.join("\n")]),this.pick=new SceneJS._webgl.Program(a,[this.source.pickVertexSrc.join("\n")],[this.source.pickFragmentSrc.join("\n")])};var SceneJS_ObjectFactory=function(){};SceneJS_ObjectFactory.prototype._freeObjects=[],SceneJS_ObjectFactory.prototype._numFreeObjects=0,SceneJS_ObjectFactory.prototype.getObject=function(a){ +var b;return this._numFreeObjects>0?(b=this._freeObjects[--this._numFreeObjects],b.id=a,b):new SceneJS_Object(a)},SceneJS_ObjectFactory.prototype.putObject=function(a){this._freeObjects[this._numFreeObjects++]=a};var SceneJS_Object=function(a){this.id=a,this.hash=null,this.sortKey=null,this.chunks=[],this.chunksLen=0,this.program=null,this.layer=null,this.texture=null,this.flags=null,this.tag=null};SceneJS.RenderContext=function(a){this._frameCtx=a},SceneJS.RenderContext.prototype.getCameraMatrix=function(){return this._frameCtx.cameraMat},SceneJS.RenderContext.prototype.getViewMatrix=function(){return this._frameCtx.viewMat},SceneJS.RenderContext.prototype.getModelMatrix=function(){return this._frameCtx.modelMat},SceneJS.RenderContext.prototype.getCanvasPos=function(a){this.getProjPos(a);var b=this._frameCtx.canvas.canvas,c=this._frameCtx.canvas.ssaaMultiplier,d=b.width/c,e=b.height/c,f=this._pc,g=f[0]/f[3]*d*.5,h=f[1]/f[3]*e*.5;return{x:g+.5*d,y:e-h-.5*e}},SceneJS.RenderContext.prototype.getCameraPos=function(a){return this.getProjPos(a),this._camPos=SceneJS_math_normalizeVec3(this._pc,[0,0,0]),{x:this._camPos[0],y:this._camPos[1],z:this._camPos[2]}},SceneJS.RenderContext.prototype.getProjPos=function(a){return this.getViewPos(a),this._pc=SceneJS_math_transformPoint3(this._frameCtx.cameraMat,this._vc),{x:this._pc[0],y:this._pc[1],z:this._pc[2],w:this._pc[3]}},SceneJS.RenderContext.prototype.getViewPos=function(a){return this.getWorldPos(a),this._vc=SceneJS_math_transformPoint3(this._frameCtx.viewMat,this._wc),{x:this._vc[0],y:this._vc[1],z:this._vc[2],w:this._vc[3]}},SceneJS.RenderContext.prototype.getWorldPos=function(a){return this._wc=SceneJS_math_transformPoint3(this._frameCtx.modelMat,a||[0,0,0]),{x:this._wc[0],y:this._wc[1],z:this._wc[2],w:this._wc[3]}};var SceneJS_Chunk=function(){};SceneJS_Chunk.prototype.init=function(a,b,c,d){this.id=a,this.program=b,this.core=c,this.core2=d,this.build&&this.build()};var SceneJS_ChunkFactory=function(){this._chunks={},this.chunkTypes=SceneJS_ChunkFactory.chunkTypes};SceneJS_ChunkFactory.chunkTypes={},SceneJS_ChunkFactory._freeChunks={},SceneJS_ChunkFactory.createChunkType=function(a){if(!a.type)throw"'type' expected in params";var b=SceneJS_Chunk,c=function(){this.useCount=0,this.init.apply(this,arguments)};return c.prototype=new b,c.prototype.constructor=c,a.drawAndPick&&(a.draw=a.pick=a.drawAndPick),SceneJS_ChunkFactory.chunkTypes[a.type]=c,SceneJS._apply(a,c.prototype),SceneJS_ChunkFactory._freeChunks[a.type]={chunks:[],chunksLen:0},c},SceneJS_ChunkFactory.prototype.getChunk=function(a,b,c,d,e){var f=SceneJS_ChunkFactory.chunkTypes[b];if(!f)throw"chunk type not supported: '"+b+"'";var g=this._chunks[a];if(g)return g.useCount++,g;var h=SceneJS_ChunkFactory._freeChunks[b];return h.chunksLen>0&&(g=h.chunks[--h.chunksLen]),g?g.init(a,c,d,e):g=new f(a,c,d,e),g.type=b,g.useCount=1,this._chunks[a]=g,g},SceneJS_ChunkFactory.prototype.putChunk=function(a){if(0!=a.useCount&&--a.useCount<=0){a.recycle&&a.recycle(),delete this._chunks[a.id];var b=SceneJS_ChunkFactory._freeChunks[a.type];b.chunks[b.chunksLen++]=a}},SceneJS_ChunkFactory.prototype.webglRestored=function(){var a;for(var b in this._chunks)this._chunks.hasOwnProperty(b)&&(a=this._chunks[b],a&&a.build&&a.build())},SceneJS_ChunkFactory.createChunkType({type:"camera",build:function(){this._uPMatrixDraw=this.program.draw.getUniform("SCENEJS_uPMatrix"),this._uZNearDraw=this.program.draw.getUniform("SCENEJS_uZNear"),this._uZFarDraw=this.program.draw.getUniform("SCENEJS_uZFar"),this._uPMatrixPick=this.program.pick.getUniform("SCENEJS_uPMatrix"),this._uZNearPick=this.program.pick.getUniform("SCENEJS_uZNear"),this._uZFarPick=this.program.pick.getUniform("SCENEJS_uZFar")},draw:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixDraw&&this._uPMatrixDraw.setValue(this.core.mat),this._uZNearDraw&&this._uZNearDraw.setValue(this.core.optics.near),this._uZFarDraw&&this._uZFarDraw.setValue(this.core.optics.far),a.cameraMat=this.core.mat},pick:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixPick&&this._uPMatrixPick.setValue(this.core.mat),a.rayPick&&(this._uZNearPick&&this._uZNearPick.setValue(this.core.optics.near),this._uZFarPick&&this._uZFarPick.setValue(this.core.optics.far)),a.cameraMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"clips",build:function(){this._draw=this._draw||[];for(var a=this.program.draw,b=0,c=this.core.clips.length;c>b;b++)this._draw[b]={uClipMode:a.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:a.getUniform("SCENEJS_uClipNormalAndDist"+b)};this._pick=this._pick||[];for(var d=this.program.pick,b=0,c=this.core.clips.length;c>b;b++)this._pick[b]={uClipMode:d.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:d.getUniform("SCENEJS_uClipNormalAndDist"+b)}},drawAndPick:function(a){for(var b,c,d,e=a.pick?this._pick:this._draw,f=this.core.clips,g=(this.program.gl,0),h=f.length;h>g;g++)a.pick?(b=e[g].uClipMode,c=e[g].uClipNormalAndDist):(b=e[g].uClipMode,c=e[g].uClipNormalAndDist),b&&c&&(d=f[g],"inside"==d.mode?(b.setValue(2),c.setValue(d.normalAndDist)):"outside"==d.mode?(b.setValue(1),c.setValue(d.normalAndDist)):b.setValue(0))}}),SceneJS_ChunkFactory.createChunkType({type:"draw",unique:!0,build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode")},drawAndPick:function(a){var b=this.program.gl,c=this.program.UINT_INDEX_ENABLED?b.UNSIGNED_INT:b.UNSIGNED_SHORT;a.pick?this._depthModePick&&this._depthModePick.setValue(a.depthMode):this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),b.drawElements(this.core.primitive,this.core.indexBuf.numItems,c,0)}}),SceneJS_ChunkFactory.createChunkType({type:"flags",build:function(){var a=this.program.draw;this._uClippingDraw=a.getUniform("SCENEJS_uClipping"),this._uSolidDraw=a.getUniform("SCENEJS_uSolid");var b=this.program.pick;this._uClippingPick=b.getUniform("SCENEJS_uClipping")},drawAndPick:function(a){var b=this.program.gl,c=this.core.backfaces;a.backfaces!=c&&(c?b.disable(b.CULL_FACE):b.enable(b.CULL_FACE),a.backfaces=c);var d=this.core.frontface;a.frontface!=d&&("ccw"==d?b.frontFace(b.CCW):b.frontFace(b.CW),a.frontface=d);var e=this.core.transparent;a.transparent!=e&&(a.pick||(e?(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA),a.blendEnabled=!0):(b.disable(b.BLEND),a.blendEnabled=!1)),a.transparent=e),a.pick?this._uClippingPick&&this._uClippingPick.setValue(this.core.clipping):(this._uClippingDraw&&this._uClippingDraw.setValue(this.core.clipping),this._uSolidDraw&&this._uSolidDraw.setValue(this.core.solid))}}),SceneJS_ChunkFactory.createChunkType({type:"renderTarget",programGlobal:!0,draw:function(a){var b=this.program.gl;a.renderBuf&&(b.flush(),a.renderBuf.unbind(),a.renderBuf=null);var c=this.core.renderBuf;return c?(c.bind(),a.depthMode="depth"===this.core.bufType,a.depthMode||a.blendEnabled&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA)),b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),b.clearColor(a.ambientColor[0],a.ambientColor[1],a.ambientColor[2],1),b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),void(a.renderBuf=c)):void(a.depthMode=!1)}}),SceneJS_ChunkFactory.createChunkType({type:"geometry",build:function(){var a=this.program.draw;this._aVertexDraw=a.getAttribute("SCENEJS_aVertex"),this._aNormalDraw=a.getAttribute("SCENEJS_aNormal"),this._aUVDraw=a.getAttribute("SCENEJS_aUVCoord"),this._aUV2Draw=a.getAttribute("SCENEJS_aUVCoord2"),this._aTangentDraw=a.getAttribute("SCENEJS_aTangent"),this._aColorDraw=a.getAttribute("SCENEJS_aVertexColor"),this._aMorphVertexDraw=a.getAttribute("SCENEJS_aMorphVertex"),this._aMorphNormalDraw=a.getAttribute("SCENEJS_aMorphNormal"),this._uMorphFactorDraw=a.getUniform("SCENEJS_uMorphFactor");var b=this.program.pick;this._aVertexPick=b.getAttribute("SCENEJS_aVertex"),this._aMorphVertexPick=b.getAttribute("SCENEJS_aMorphVertex"),this._uMorphFactorPick=b.getUniform("SCENEJS_uMorphFactor"),this.VAO=null,this.VAOMorphKey1=0,this.VAOMorphKey2=0,this.VAOHasInterleavedBuf=!1},recycle:function(){if(this.VAO){var a=this.program.gl.getExtension("OES_vertex_array_object");a.deleteVertexArrayOES(this.VAO),this.VAO=null}},morphDraw:function(){this.VAOMorphKey1=this.core.key1,this.VAOMorphKey2=this.core.key2;var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexDraw?(this._aVertexDraw.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexDraw.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aMorphNormalDraw?(this._aNormalDraw.bindFloatArrayBuffer(a.normalBuf),this._aMorphNormalDraw.bindFloatArrayBuffer(b.normalBuf)):this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this.setDrawMorphFactor()},setDrawMorphFactor:function(){this._uMorphFactorDraw&&this._uMorphFactorDraw.setValue*this.core.factor},draw:function(a){var b=this.core.targets&&this.core.targets.length,c=this.core2.interleavedBuf&&!this.core2.interleavedBuf.dirty;if(this.VAO){if(a.VAO.bindVertexArrayOES(this.VAO),b){if(this.VAOMorphKey1==this.core.key1&&this.VAOMorphKey2==this.core.key2)return void this.setDrawMorphFactor()}else if(c||!this.VAOHasInterleavedBuf)return}else if(a.VAO){a.VAO.bindVertexArrayOES(null),this.VAO=a.VAO.createVertexArrayOES(),a.VAO.bindVertexArrayOES(this.VAO);this.program.gl}b?this.morphDraw():c?(this.VAOHasInterleavedBuf=!0,this.core2.interleavedBuf.bind(),this._aVertexDraw&&this._aVertexDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedPositionOffset),this._aNormalDraw&&this._aNormalDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedNormalOffset),this._aUVDraw&&this._aUVDraw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUVOffset),this._aUV2Draw&&this._aUV2Draw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUV2Offset),this._aColorDraw&&this._aColorDraw.bindInterleavedFloatArrayBuffer(4,this.core2.interleavedStride,this.core2.interleavedColorOffset),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())):(this.VAOHasInterleavedBuf=!1,this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())),this.core2.indexBuf.bind()},morphPick:function(){var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexPick?(this._aVertexPick.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexPick.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this._uMorphFactorPick&&this._uMorphFactorPick.setValue(this.core.factor)},pick:function(a){this.core.targets&&this.core.targets.length?this.morphPick():this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this.core2.indexBuf.bind()}}),SceneJS_ChunkFactory.createChunkType({type:"lights",build:function(){this._uAmbientColor=this._uAmbientColor||[],this._uLightColor=this._uLightColor||[],this._uLightDir=this._uLightDir||[],this._uLightPos=this._uLightPos||[],this._uLightCutOff=this._uLightCutOff||[],this._uLightSpotExp=this._uLightSpotExp||[],this._uLightAttenuation=this._uLightAttenuation||[];for(var a=this.core.lights,b=this.program,c=0,d=a.length;d>c;c++)switch(a[c].mode){case"ambient":this._uAmbientColor[c]=b.draw.getUniform("SCENEJS_uAmbientColor");break;case"dir":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=null,this._uLightDir[c]=b.draw.getUniform("SCENEJS_uLightDir"+c);break;case"point":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=b.draw.getUniform("SCENEJS_uLightPos"+c),this._uLightDir[c]=null,this._uLightAttenuation[c]=b.draw.getUniform("SCENEJS_uLightAttenuation"+c)}},draw:function(a){a.dirty&&this.build();for(var b,c=this.core.lights,d=(this.program.gl,0),e=c.length;e>d;d++)b=c[d],this._uAmbientColor[d]?this._uAmbientColor[d].setValue(b.color):(this._uLightColor[d]&&this._uLightColor[d].setValue(b.color),this._uLightPos[d]&&(this._uLightPos[d].setValue(b.pos),this._uLightAttenuation[d]&&this._uLightAttenuation[d].setValue(b.attenuation)),this._uLightDir[d]&&this._uLightDir[d].setValue(b.dir))}}),SceneJS_ChunkFactory.createChunkType({type:"listeners",programGlobal:!0,build:function(){},draw:function(a){for(var b=this.core.listeners,c=a.renderListenerCtx,d=b.length-1;d>=0;d--)if(b[d](c)===!0)return!0}}),SceneJS_ChunkFactory.createChunkType({type:"lookAt",build:function(){this._uvMatrixDraw=this.program.draw.getUniform("SCENEJS_uVMatrix"),this._uVNMatrixDraw=this.program.draw.getUniform("SCENEJS_uVNMatrix"),this._uWorldEyeDraw=this.program.draw.getUniform("SCENEJS_uWorldEye"),this._uvMatrixPick=this.program.pick.getUniform("SCENEJS_uVMatrix")},draw:function(a){this.core.dirty&&this.core.rebuild();this.program.gl;this._uvMatrixDraw&&this._uvMatrixDraw.setValue(this.core.mat),this._uVNMatrixDraw&&this._uVNMatrixDraw.setValue(this.core.normalMat),this._uWorldEyeDraw&&this._uWorldEyeDraw.setValue(this.core.lookAt.eye),a.viewMat=this.core.mat},pick:function(a){this.program.gl;this._uvMatrixPick&&this._uvMatrixPick.setValue(this.core.mat),a.viewMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"material",build:function(){var a=this.program.draw;this._uMaterialBaseColor=a.getUniform("SCENEJS_uMaterialColor"),this._uMaterialSpecularColor=a.getUniform("SCENEJS_uMaterialSpecularColor"),this._uMaterialSpecular=a.getUniform("SCENEJS_uMaterialSpecular"),this._uMaterialShine=a.getUniform("SCENEJS_uMaterialShine"),this._uMaterialEmit=a.getUniform("SCENEJS_uMaterialEmit"),this._uMaterialAlpha=a.getUniform("SCENEJS_uMaterialAlpha")},draw:function(){this.program.gl;this._uMaterialBaseColor&&this._uMaterialBaseColor.setValue(this.core.baseColor),this._uMaterialSpecularColor&&this._uMaterialSpecularColor.setValue(this.core.specularColor),this._uMaterialSpecular&&this._uMaterialSpecular.setValue(this.core.specular),this._uMaterialShine&&this._uMaterialShine.setValue(this.core.shine),this._uMaterialEmit&&this._uMaterialEmit.setValue(this.core.emit),this._uMaterialAlpha&&this._uMaterialAlpha.setValue(this.core.alpha)}}),SceneJS_ChunkFactory.createChunkType({type:"name",build:function(){this._uPickColor=this.program.pick.getUniform("SCENEJS_uPickColor")},pick:function(a){if(this._uPickColor&&this.core.name){a.pickNames[a.pickIndex++]=this.core;var b=a.pickIndex>>16&255,c=a.pickIndex>>8&255,d=255&a.pickIndex;this._uPickColor.setValue([d/255,c/255,b/255])}}}),SceneJS_ChunkFactory.createChunkType({type:"program",build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode"),this._rayPickMode=this.program.pick.getUniform("SCENEJS_uRayPickMode")},draw:function(a){var b=this.program.draw;b.bind(),a.textureUnit=0;var c=this.program.gl;if(this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),!a.VAO)for(var d=0;10>d;d++)c.disableVertexAttribArray(d);a.drawProgram=this.program.draw},pick:function(a){var b=this.program.pick;b.bind();var c=this.program.gl;this._rayPickMode&&this._rayPickMode.setValue(a.rayPick),this._depthModePick&&this._depthModePick.setValue(a.depthMode),a.textureUnit=0;for(var d=0;10>d;d++)c.disableVertexAttribArray(d)}}),SceneJS_ChunkFactory.createChunkType({type:"renderer",build:function(){},drawAndPick:function(a){if(this.core.props){var b=this.program.gl;a.renderer&&(a.renderer.props.restoreProps(b),a.renderer=this.core),this.core.props.setProps(b)}}}),SceneJS_ChunkFactory.createChunkType({type:"depthBuffer",programGlobal:!0,drawAndPick:function(a){var b=this.program.gl,c=this.core.enabled;a.depthbufEnabled!=c&&(c?b.enable(b.DEPTH_TEST):b.disable(b.DEPTH_TEST),a.depthbufEnabled=c);var d=this.core.clearDepth;a.clearDepth!=d&&(b.clearDepth(d),a.clearDepth=d);var e=this.core.depthFunc;a.depthFunc!=e&&(b.depthFunc(e),a.depthFunc=e),this.core.clear&&b.clear(b.DEPTH_BUFFER_BIT)}}),SceneJS_ChunkFactory.createChunkType({type:"colorBuffer",programGlobal:!0,build:function(){},drawAndPick:function(a){if(!a.transparent){var b=this.core.blendEnabled,c=this.program.gl;a.blendEnabled!=b&&(b?c.enable(c.BLEND):c.disable(c.BLEND),a.blendEnabled=b);var d=this.core.colorMask;c.colorMask(d.r,d.g,d.b,d.a)}}}),SceneJS_ChunkFactory.createChunkType({type:"view",programGlobal:!0,build:function(){},drawAndPick:function(a){var b=this.core.scissorTestEnabled;if(a.scissorTestEnabled!=b){var c=this.program.gl;b?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST),a.scissorTestEnabled=b}}}),SceneJS_ChunkFactory.createChunkType({type:"shader",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"shaderParams",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"style",programGlobal:!0,drawAndPick:function(a){var b=this.core.lineWidth;if(a.lineWidth!=b){var c=this.program.gl;c.lineWidth(b),a.lineWidth=b}}}),SceneJS_ChunkFactory.createChunkType({type:"texture",build:function(){this._uTexSampler=this._uTexSampler||[],this._uTexMatrix=this._uTexMatrix||[],this._uTexBlendFactor=this._uTexBlendFactor||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uTexSampler[d]="SCENEJS_uSampler"+d,this._uTexMatrix[d]=c.getUniform("SCENEJS_uLayer"+d+"Matrix"),this._uTexBlendFactor[d]=c.getUniform("SCENEJS_uLayer"+d+"BlendFactor")},draw:function(a){a.textureUnit=0;var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uTexSampler[e]&&c.texture&&(d.bindTexture(this._uTexSampler[e],c.texture,a.textureUnit++),c._matrixDirty&&c.buildMatrix&&c.buildMatrix.call(c),this._uTexMatrix[e]&&this._uTexMatrix[e].setValue(c.matrixAsArray),this._uTexBlendFactor[e]&&this._uTexBlendFactor[e].setValue(c.blendFactor));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"cubemap",build:function(){this._uCubeMapSampler=this._uCubeMapSampler||[],this._uCubeMapIntensity=this._uCubeMapIntensity||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uCubeMapSampler[d]="SCENEJS_uCubeMapSampler"+d,this._uCubeMapIntensity[d]=c.getUniform("SCENEJS_uCubeMapIntensity"+d)},draw:function(a){var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uCubeMapSampler[e]&&c.texture&&(d.bindTexture(this._uCubeMapSampler[e],c.texture,a.textureUnit++),this._uCubeMapIntensity[e]&&this._uCubeMapIntensity[e].setValue(c.intensity));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"xform",build:function(){var a=this.program.draw;this._uMatLocationDraw=a.getUniform("SCENEJS_uMMatrix"),this._uNormalMatLocationDraw=a.getUniform("SCENEJS_uMNMatrix");var b=this.program.pick;this._uMatLocationPick=b.getUniform("SCENEJS_uMMatrix")},draw:function(a){(SceneJS_configsModule.configs.forceXFormCoreRebuild===!0||this.core.dirty&&this.core.build)&&this.core.build();this.program.gl;this._uMatLocationDraw&&this._uMatLocationDraw.setValue(this.core.mat),this._uNormalMatLocationDraw&&this._uNormalMatLocationDraw.setValue(this.core.normalMat),a.modelMat=this.core.mat},pick:function(a){this.core.dirty&&this.core.build();this.program.gl;this._uMatLocationPick&&this._uMatLocationPick.setValue(this.core.mat),a.modelMat=this.core.mat}}); \ No newline at end of file diff --git a/build/4.2.0/scenejs-4.2.0.js b/build/4.2.0/scenejs-4.2.0.js new file mode 100644 index 00000000..6f3ef137 --- /dev/null +++ b/build/4.2.0/scenejs-4.2.0.js @@ -0,0 +1,18308 @@ +/* + * SceneJS V4.2.0 + * + * A WebGL-based 3D scene graph from xeoLabs + * http://scenejs.org/ + * + * Built on 2015-06-10 + * + * MIT License + * Copyright 2015, Lindsay Kay + * http://xeolabs.com/ + * + */ + +/* + * SceneJS Latest + * + * A WebGL-based 3D scene graph from xeoLabs + * http://scenejs.org/ + * + * MIT License + * Copyright 2015, Lindsay Kay + * http://xeolabs.com/ + * + */ + +;// Only define RequireJS if not already present +if (undefined === require) {;/* + RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + Available via the MIT or new BSD license. + see: http://github.com/jrburke/requirejs for details + */ +var requirejs,require,define; +(function(ba){function J(b){return"[object Function]"===N.call(b)}function K(b){return"[object Array]"===N.call(b)}function z(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(J(n)){if(this.events.error&&this.map.isDefine||h.onError!==ca)try{e=k.execCb(c,n,b,e)}catch(d){a=d}else e=k.execCb(c,n,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!== + this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else e=n;this.exports=e;if(this.map.isDefine&&!this.ignore&&(r[c]=e,h.onResourceLoad))h.onResourceLoad(k,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete= + !0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=l(a.prefix);this.depMaps.push(d);u(d,"defined",v(this,function(e){var n,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,C=k.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=l(a.prefix+"!"+d,this.map.parentMap),u(e,"defined",v(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})), + d=m(q,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",v(this,function(a){this.emit("error",a)}));d.enable()}}else n=v(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),n.error=v(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];H(q,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),n.fromText=v(this,function(e,c){var d=a.name,g=l(d),i=Q;c&&(e=c);i&&(Q=!1);s(g);t(j.config,b)&&(j.config[d]=j.config[b]);try{h.exec(e)}catch(D){return w(B("fromtexteval", + "fromText eval for "+b+" failed: "+D,D,[b]))}i&&(Q=!0);this.depMaps.push(g);k.completeLoad(d);C([d],n)}),e.load(a.name,C,n,j)}));k.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){W[this.map.id]=this;this.enabling=this.enabled=!0;z(this.depMaps,v(this,function(a,b){var c,e;if("string"===typeof a){a=l(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(P,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;u(a,"defined",v(this,function(a){this.defineDep(b, + a);this.check()}));this.errback&&u(a,"error",v(this,this.errback))}c=a.id;e=q[c];!t(P,c)&&(e&&!e.enabled)&&k.enable(a,this)}));H(this.pluginMaps,v(this,function(a){var b=m(q,a.id);b&&!b.enabled&&k.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){z(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};k={config:j,contextName:b,registry:q,defined:r,urlFetched:V,defQueue:I,Module:$,makeModuleMap:l, + nextTick:h.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.pkgs,c=j.shim,e={paths:!0,config:!0,map:!0};H(a,function(a,b){e[b]?"map"===b?(j.map||(j.map={}),S(j[b],a,!0,!0)):S(j[b],a,!0):j[b]=a});a.shim&&(H(a.shim,function(a,b){K(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=k.makeShimExports(a);c[b]=a}),j.shim=c);a.packages&&(z(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name, + location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(fa,"")}}),j.pkgs=b);H(q,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=l(b))});if(a.deps||a.callback)k.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,f){function d(e,c,g){var i,j;f.enableBuildCallback&&(c&&J(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(J(c))return w(B("requireargs", + "Invalid require call"),g);if(a&&t(P,e))return P[e](q[a.id]);if(h.get)return h.get(k,e,a,d);i=l(e,a,!1,!0);i=i.id;return!t(r,i)?w(B("notloaded",'Module name "'+i+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[i]}M();k.nextTick(function(){M();j=s(l(null,a));j.skipMap=f.skipMap;j.init(e,c,g,{enabled:!0});E()});return d}f=f||{};S(d,{isBrowser:A,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1g.attachEvent.toString().indexOf("[native code"))&&!Z?(Q=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=d,M=g,E?y.insertBefore(g,E):y.appendChild(g), + M=null,g;if(ea)try{importScripts(d),b.completeLoad(c)}catch(l){b.onError(B("importscripts","importScripts failed for "+c+" at "+d,l,[c]))}};A&&O(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(L=b.getAttribute("data-main"))return s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0});define=function(b,c,d){var h,g;"string"!==typeof b&&(d=c,c=b,b=null); + K(c)||(d=c,c=null);!c&&J(d)&&(c=[],d.length&&(d.toString().replace(ma,"").replace(na,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(Q){if(!(h=M))R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return R=b}),h=R;h&&(b||(b=h.getAttribute("data-requiremodule")),g=G[h.getAttribute("data-requirecontext")])}(g?g.defQueue:U).push([b,c,d])};define.amd={jQuery:!0};h.exec=function(b){return eval(b)}; + h(u)}})(this);;}; +WebGLDebugUtils = function() { + +/** + * Wrapped logging function. + * @param {string} msg Message to log. + */ +var log = function(msg) { + if (window.console && window.console.log) { + window.console.log(msg); + } +}; + +/** + * Which arguements are enums. + * @type {!Object.} + */ +var glValidEnumContexts = { + + // Generic setters and getters + + 'enable': { 0:true }, + 'disable': { 0:true }, + 'getParameter': { 0:true }, + + // Rendering + + 'drawArrays': { 0:true }, + 'drawElements': { 0:true, 2:true }, + + // Shaders + + 'createShader': { 0:true }, + 'getShaderParameter': { 1:true }, + 'getProgramParameter': { 1:true }, + + // Vertex attributes + + 'getVertexAttrib': { 1:true }, + 'vertexAttribPointer': { 2:true }, + + // Textures + + 'bindTexture': { 0:true }, + 'activeTexture': { 0:true }, + 'getTexParameter': { 0:true, 1:true }, + 'texParameterf': { 0:true, 1:true }, + 'texParameteri': { 0:true, 1:true, 2:true }, + 'texImage2D': { 0:true, 2:true, 6:true, 7:true }, + 'texSubImage2D': { 0:true, 6:true, 7:true }, + 'copyTexImage2D': { 0:true, 2:true }, + 'copyTexSubImage2D': { 0:true }, + 'generateMipmap': { 0:true }, + + // Buffer objects + + 'bindBuffer': { 0:true }, + 'bufferData': { 0:true, 2:true }, + 'bufferSubData': { 0:true }, + 'getBufferParameter': { 0:true, 1:true }, + + // Renderbuffers and framebuffers + + 'pixelStorei': { 0:true, 1:true }, + 'readPixels': { 4:true, 5:true }, + 'bindRenderbuffer': { 0:true }, + 'bindFramebuffer': { 0:true }, + 'checkFramebufferStatus': { 0:true }, + 'framebufferRenderbuffer': { 0:true, 1:true, 2:true }, + 'framebufferTexture2D': { 0:true, 1:true, 2:true }, + 'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true }, + 'getRenderbufferParameter': { 0:true, 1:true }, + 'renderbufferStorage': { 0:true, 1:true }, + + // Frame buffer operations (clear, blend, depth test, stencil) + + 'clear': { 0:true }, + 'depthFunc': { 0:true }, + 'blendFunc': { 0:true, 1:true }, + 'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true }, + 'blendEquation': { 0:true }, + 'blendEquationSeparate': { 0:true, 1:true }, + 'stencilFunc': { 0:true }, + 'stencilFuncSeparate': { 0:true, 1:true }, + 'stencilMaskSeparate': { 0:true }, + 'stencilOp': { 0:true, 1:true, 2:true }, + 'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true }, + + // Culling + + 'cullFace': { 0:true }, + 'frontFace': { 0:true }, +}; + +/** + * Map of numbers to names. + * @type {Object} + */ +var glEnums = null; + +/** + * Initializes this module. Safe to call more than once. + * @param {!WebGLRenderingContext} ctx A WebGL context. If + * you have more than one context it doesn't matter which one + * you pass in, it is only used to pull out constants. + */ +function init(ctx) { + if (glEnums == null) { + glEnums = { }; + for (var propertyName in ctx) { + if (typeof ctx[propertyName] == 'number') { + glEnums[ctx[propertyName]] = propertyName; + } + } + } +} + +/** + * Checks the utils have been initialized. + */ +function checkInit() { + if (glEnums == null) { + throw 'WebGLDebugUtils.init(ctx) not called'; + } +} + +/** + * Returns true or false if value matches any WebGL enum + * @param {*} value Value to check if it might be an enum. + * @return {boolean} True if value matches one of the WebGL defined enums + */ +function mightBeEnum(value) { + checkInit(); + return (glEnums[value] !== undefined); +} + +/** + * Gets an string version of an WebGL enum. + * + * Example: + * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); + * + * @param {number} value Value to return an enum for + * @return {string} The string version of the enum. + */ +function glEnumToString(value) { + checkInit(); + var name = glEnums[value]; + return (name !== undefined) ? name : + ("*UNKNOWN WebGL ENUM (0x" + value.toString(16) + ")"); +} + +/** + * Returns the string version of a WebGL argument. + * Attempts to convert enum arguments to strings. + * @param {string} functionName the name of the WebGL function. + * @param {number} argumentIndx the index of the argument. + * @param {*} value The value of the argument. + * @return {string} The value as a string. + */ +function glFunctionArgToString(functionName, argumentIndex, value) { + var funcInfo = glValidEnumContexts[functionName]; + if (funcInfo !== undefined) { + if (funcInfo[argumentIndex]) { + return glEnumToString(value); + } + } + if (value === null) { + return "null"; + } else if (value === undefined) { + return "undefined"; + } else { + return value.toString(); + } +} + +/** + * Converts the arguments of a WebGL function to a string. + * Attempts to convert enum arguments to strings. + * + * @param {string} functionName the name of the WebGL function. + * @param {number} args The arguments. + * @return {string} The arguments as a string. + */ +function glFunctionArgsToString(functionName, args) { + // apparently we can't do args.join(","); + var argStr = ""; + for (var ii = 0; ii < args.length; ++ii) { + argStr += ((ii == 0) ? '' : ', ') + + glFunctionArgToString(functionName, ii, args[ii]); + } + return argStr; +}; + + +function makePropertyWrapper(wrapper, original, propertyName) { + //log("wrap prop: " + propertyName); + wrapper.__defineGetter__(propertyName, function() { + return original[propertyName]; + }); + // TODO(gmane): this needs to handle properties that take more than + // one value? + wrapper.__defineSetter__(propertyName, function(value) { + //log("set: " + propertyName); + original[propertyName] = value; + }); +} + +// Makes a function that calls a function on another object. +function makeFunctionWrapper(original, functionName) { + //log("wrap fn: " + functionName); + var f = original[functionName]; + return function() { + //log("call: " + functionName); + var result = f.apply(original, arguments); + return result; + }; +} + +/** + * Given a WebGL context returns a wrapped context that calls + * gl.getError after every command and calls a function if the + * result is not gl.NO_ERROR. + * + * @param {!WebGLRenderingContext} ctx The webgl context to + * wrap. + * @param {!function(err, funcName, args): void} opt_onErrorFunc + * The function to call when gl.getError returns an + * error. If not specified the default function calls + * console.log with a message. + * @param {!function(funcName, args): void} opt_onFunc The + * function to call when each webgl function is called. + * You can use this to log all calls for example. + */ +function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc) { + init(ctx); + opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { + // apparently we can't do args.join(","); + var argStr = ""; + for (var ii = 0; ii < args.length; ++ii) { + argStr += ((ii == 0) ? '' : ', ') + + glFunctionArgToString(functionName, ii, args[ii]); + } + log("WebGL error "+ glEnumToString(err) + " in "+ functionName + + "(" + argStr + ")"); + }; + + // Holds booleans for each GL error so after we get the error ourselves + // we can still return it to the client app. + var glErrorShadow = { }; + + // Makes a function that calls a WebGL function and then calls getError. + function makeErrorWrapper(ctx, functionName) { + return function() { + if (opt_onFunc) { + opt_onFunc(functionName, arguments); + } + var result = ctx[functionName].apply(ctx, arguments); + var err = ctx.getError(); + if (err != 0) { + glErrorShadow[err] = true; + opt_onErrorFunc(err, functionName, arguments); + } + return result; + }; + } + + // Make a an object that has a copy of every property of the WebGL context + // but wraps all functions. + var wrapper = {}; + for (var propertyName in ctx) { + if (typeof ctx[propertyName] == 'function') { + wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); + } else { + makePropertyWrapper(wrapper, ctx, propertyName); + } + } + + // Override the getError function with one that returns our saved results. + wrapper.getError = function() { + for (var err in glErrorShadow) { + if (glErrorShadow.hasOwnProperty(err)) { + if (glErrorShadow[err]) { + glErrorShadow[err] = false; + return err; + } + } + } + return ctx.NO_ERROR; + }; + + return wrapper; +} + +function resetToInitialState(ctx) { + var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); + var tmp = ctx.createBuffer(); + ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp); + for (var ii = 0; ii < numAttribs; ++ii) { + ctx.disableVertexAttribArray(ii); + ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0); + ctx.vertexAttrib1f(ii, 0); + } + ctx.deleteBuffer(tmp); + + var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS); + for (var ii = 0; ii < numTextureUnits; ++ii) { + ctx.activeTexture(ctx.TEXTURE0 + ii); + ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null); + ctx.bindTexture(ctx.TEXTURE_2D, null); + } + + ctx.activeTexture(ctx.TEXTURE0); + ctx.useProgram(null); + ctx.bindBuffer(ctx.ARRAY_BUFFER, null); + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null); + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); + ctx.disable(ctx.BLEND); + ctx.disable(ctx.CULL_FACE); + ctx.disable(ctx.DEPTH_TEST); + ctx.disable(ctx.DITHER); + ctx.disable(ctx.SCISSOR_TEST); + ctx.blendColor(0, 0, 0, 0); + ctx.blendEquation(ctx.FUNC_ADD); + ctx.blendFunc(ctx.ONE, ctx.ZERO); + ctx.clearColor(0, 0, 0, 0); + ctx.clearDepth(1); + ctx.clearStencil(-1); + ctx.colorMask(true, true, true, true); + ctx.cullFace(ctx.BACK); + ctx.depthFunc(ctx.LESS); + ctx.depthMask(true); + ctx.depthRange(0, 1); + ctx.frontFace(ctx.CCW); + ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE); + ctx.lineWidth(1); + ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4); + ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4); + ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false); + ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); + // TODO: Delete this IF. + if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) { + ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL); + } + ctx.polygonOffset(0, 0); + ctx.sampleCoverage(1, false); + ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height); + ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF); + ctx.stencilMask(0xFFFFFFFF); + ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP); + ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); + ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT); + + // TODO: This should NOT be needed but Firefox fails with 'hint' + while(ctx.getError()); +} + +function makeLostContextSimulatingCanvas(canvas) { + var unwrappedContext_; + var wrappedContext_; + var onLost_ = []; + var onRestored_ = []; + var wrappedContext_ = {}; + var contextId_ = 1; + var contextLost_ = false; + var resourceId_ = 0; + var resourceDb_ = []; + var numCallsToLoseContext_ = 0; + var numCalls_ = 0; + var canRestore_ = false; + var restoreTimeout_ = 0; + + // Holds booleans for each GL error so can simulate errors. + var glErrorShadow_ = { }; + + canvas.getContext = function(f) { + return function() { + var ctx = f.apply(canvas, arguments); + // Did we get a context and is it a WebGL context? + if (ctx instanceof WebGLRenderingContext) { + if (ctx != unwrappedContext_) { + if (unwrappedContext_) { + throw "got different context" + } + unwrappedContext_ = ctx; + wrappedContext_ = makeLostContextSimulatingContext(unwrappedContext_); + } + return wrappedContext_; + } + return ctx; + } + }(canvas.getContext); + + function wrapEvent(listener) { + if (typeof(listener) == "function") { + return listener; + } else { + return function(info) { + listener.handleEvent(info); + } + } + } + + var addOnContextLostListener = function(listener) { + onLost_.push(wrapEvent(listener)); + }; + + var addOnContextRestoredListener = function(listener) { + onRestored_.push(wrapEvent(listener)); + }; + + + function wrapAddEventListener(canvas) { + var f = canvas.addEventListener; + canvas.addEventListener = function(type, listener, bubble) { + switch (type) { + case 'webglcontextlost': + addOnContextLostListener(listener); + break; + case 'webglcontextrestored': + addOnContextRestoredListener(listener); + break; + default: + f.apply(canvas, arguments); + } + }; + } + + wrapAddEventListener(canvas); + + canvas.loseContext = function() { + if (!contextLost_) { + contextLost_ = true; + numCallsToLoseContext_ = 0; + ++contextId_; + while (unwrappedContext_.getError()); + clearErrors(); + glErrorShadow_[unwrappedContext_.CONTEXT_LOST_WEBGL] = true; + var event = makeWebGLContextEvent("context lost"); + var callbacks = onLost_.slice(); + setTimeout(function() { + //log("numCallbacks:" + callbacks.length); + for (var ii = 0; ii < callbacks.length; ++ii) { + //log("calling callback:" + ii); + callbacks[ii](event); + } + if (restoreTimeout_ >= 0) { + setTimeout(function() { + canvas.restoreContext(); + }, restoreTimeout_); + } + }, 0); + } + }; + + canvas.restoreContext = function() { + if (contextLost_) { + if (onRestored_.length) { + setTimeout(function() { + if (!canRestore_) { + throw "can not restore. webglcontestlost listener did not call event.preventDefault"; + } + freeResources(); + resetToInitialState(unwrappedContext_); + contextLost_ = false; + numCalls_ = 0; + canRestore_ = false; + var callbacks = onRestored_.slice(); + var event = makeWebGLContextEvent("context restored"); + for (var ii = 0; ii < callbacks.length; ++ii) { + callbacks[ii](event); + } + }, 0); + } + } + }; + + canvas.loseContextInNCalls = function(numCalls) { + if (contextLost_) { + throw "You can not ask a lost contet to be lost"; + } + numCallsToLoseContext_ = numCalls_ + numCalls; + }; + + canvas.getNumCalls = function() { + return numCalls_; + }; + + canvas.setRestoreTimeout = function(timeout) { + restoreTimeout_ = timeout; + }; + + function isWebGLObject(obj) { + //return false; + return (obj instanceof WebGLBuffer || + obj instanceof WebGLFramebuffer || + obj instanceof WebGLProgram || + obj instanceof WebGLRenderbuffer || + obj instanceof WebGLShader || + obj instanceof WebGLTexture); + } + + function checkResources(args) { + for (var ii = 0; ii < args.length; ++ii) { + var arg = args[ii]; + if (isWebGLObject(arg)) { + return arg.__webglDebugContextLostId__ == contextId_; + } + } + return true; + } + + function clearErrors() { + var k = Object.keys(glErrorShadow_); + for (var ii = 0; ii < k.length; ++ii) { + delete glErrorShadow_[k]; + } + } + + function loseContextIfTime() { + ++numCalls_; + if (!contextLost_) { + if (numCallsToLoseContext_ == numCalls_) { + canvas.loseContext(); + } + } + } + + // Makes a function that simulates WebGL when out of context. + function makeLostContextFunctionWrapper(ctx, functionName) { + var f = ctx[functionName]; + return function() { + // log("calling:" + functionName); + // Only call the functions if the context is not lost. + loseContextIfTime(); + if (!contextLost_) { + //if (!checkResources(arguments)) { + // glErrorShadow_[wrappedContext_.INVALID_OPERATION] = true; + // return; + //} + + var result = f.apply(ctx, arguments); + return result; + } + }; + } + + function freeResources() { + for (var ii = 0; ii < resourceDb_.length; ++ii) { + var resource = resourceDb_[ii]; + if (resource instanceof WebGLBuffer) { + unwrappedContext_.deleteBuffer(resource); + } else if (resource instanceof WebGLFramebuffer) { + unwrappedContext_.deleteFramebuffer(resource); + } else if (resource instanceof WebGLProgram) { + unwrappedContext_.deleteProgram(resource); + } else if (resource instanceof WebGLRenderbuffer) { + unwrappedContext_.deleteRenderbuffer(resource); + } else if (resource instanceof WebGLShader) { + unwrappedContext_.deleteShader(resource); + } else if (resource instanceof WebGLTexture) { + unwrappedContext_.deleteTexture(resource); + } + } + } + + function makeWebGLContextEvent(statusMessage) { + return { + statusMessage: statusMessage, + preventDefault: function() { + canRestore_ = true; + } + }; + } + + return canvas; + + function makeLostContextSimulatingContext(ctx) { + // copy all functions and properties to wrapper + for (var propertyName in ctx) { + if (typeof ctx[propertyName] == 'function') { + wrappedContext_[propertyName] = makeLostContextFunctionWrapper( + ctx, propertyName); + } else { + makePropertyWrapper(wrappedContext_, ctx, propertyName); + } + } + + // Wrap a few functions specially. + wrappedContext_.getError = function() { + loseContextIfTime(); + if (!contextLost_) { + var err; + while (err = unwrappedContext_.getError()) { + glErrorShadow_[err] = true; + } + } + for (var err in glErrorShadow_) { + if (glErrorShadow_[err]) { + delete glErrorShadow_[err]; + return err; + } + } + return wrappedContext_.NO_ERROR; + }; + + var creationFunctions = [ + "createBuffer", + "createFramebuffer", + "createProgram", + "createRenderbuffer", + "createShader", + "createTexture" + ]; + for (var ii = 0; ii < creationFunctions.length; ++ii) { + var functionName = creationFunctions[ii]; + wrappedContext_[functionName] = function(f) { + return function() { + loseContextIfTime(); + if (contextLost_) { + return null; + } + var obj = f.apply(ctx, arguments); + obj.__webglDebugContextLostId__ = contextId_; + resourceDb_.push(obj); + return obj; + }; + }(ctx[functionName]); + } + + var functionsThatShouldReturnNull = [ + "getActiveAttrib", + "getActiveUniform", + "getBufferParameter", + "getContextAttributes", + "getAttachedShaders", + "getFramebufferAttachmentParameter", + "getParameter", + "getProgramParameter", + "getProgramInfoLog", + "getRenderbufferParameter", + "getShaderParameter", + "getShaderInfoLog", + "getShaderSource", + "getTexParameter", + "getUniform", + "getUniformLocation", + "getVertexAttrib" + ]; + for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) { + var functionName = functionsThatShouldReturnNull[ii]; + wrappedContext_[functionName] = function(f) { + return function() { + loseContextIfTime(); + if (contextLost_) { + return null; + } + return f.apply(ctx, arguments); + } + }(wrappedContext_[functionName]); + } + + var isFunctions = [ + "isBuffer", + "isEnabled", + "isFramebuffer", + "isProgram", + "isRenderbuffer", + "isShader", + "isTexture" + ]; + for (var ii = 0; ii < isFunctions.length; ++ii) { + var functionName = isFunctions[ii]; + wrappedContext_[functionName] = function(f) { + return function() { + loseContextIfTime(); + if (contextLost_) { + return false; + } + return f.apply(ctx, arguments); + } + }(wrappedContext_[functionName]); + } + + wrappedContext_.checkFramebufferStatus = function(f) { + return function() { + loseContextIfTime(); + if (contextLost_) { + return wrappedContext_.FRAMEBUFFER_UNSUPPORTED; + } + return f.apply(ctx, arguments); + }; + }(wrappedContext_.checkFramebufferStatus); + + wrappedContext_.getAttribLocation = function(f) { + return function() { + loseContextIfTime(); + if (contextLost_) { + return -1; + } + return f.apply(ctx, arguments); + }; + }(wrappedContext_.getAttribLocation); + + wrappedContext_.getVertexAttribOffset = function(f) { + return function() { + loseContextIfTime(); + if (contextLost_) { + return 0; + } + return f.apply(ctx, arguments); + }; + }(wrappedContext_.getVertexAttribOffset); + + wrappedContext_.isContextLost = function() { + return contextLost_; + }; + + return wrappedContext_; + } +} + +return { + /** + * Initializes this module. Safe to call more than once. + * @param {!WebGLRenderingContext} ctx A WebGL context. If + } + * you have more than one context it doesn't matter which one + * you pass in, it is only used to pull out constants. + */ + 'init': init, + + /** + * Returns true or false if value matches any WebGL enum + * @param {*} value Value to check if it might be an enum. + * @return {boolean} True if value matches one of the WebGL defined enums + */ + 'mightBeEnum': mightBeEnum, + + /** + * Gets an string version of an WebGL enum. + * + * Example: + * WebGLDebugUtil.init(ctx); + * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); + * + * @param {number} value Value to return an enum for + * @return {string} The string version of the enum. + */ + 'glEnumToString': glEnumToString, + + /** + * Converts the argument of a WebGL function to a string. + * Attempts to convert enum arguments to strings. + * + * Example: + * WebGLDebugUtil.init(ctx); + * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTURE_2D); + * + * would return 'TEXTURE_2D' + * + * @param {string} functionName the name of the WebGL function. + * @param {number} argumentIndx the index of the argument. + * @param {*} value The value of the argument. + * @return {string} The value as a string. + */ + 'glFunctionArgToString': glFunctionArgToString, + + /** + * Converts the arguments of a WebGL function to a string. + * Attempts to convert enum arguments to strings. + * + * @param {string} functionName the name of the WebGL function. + * @param {number} args The arguments. + * @return {string} The arguments as a string. + */ + 'glFunctionArgsToString': glFunctionArgsToString, + + /** + * Given a WebGL context returns a wrapped context that calls + * gl.getError after every command and calls a function if the + * result is not NO_ERROR. + * + * You can supply your own function if you want. For example, if you'd like + * an exception thrown on any GL error you could do this + * + * function throwOnGLError(err, funcName, args) { + * throw WebGLDebugUtils.glEnumToString(err) + + * " was caused by call to " + funcName; + * }; + * + * ctx = WebGLDebugUtils.makeDebugContext( + * canvas.getContext("webgl"), throwOnGLError); + * + * @param {!WebGLRenderingContext} ctx The webgl context to wrap. + * @param {!function(err, funcName, args): void} opt_onErrorFunc The function + * to call when gl.getError returns an error. If not specified the default + * function calls console.log with a message. + * @param {!function(funcName, args): void} opt_onFunc The + * function to call when each webgl function is called. You + * can use this to log all calls for example. + */ + 'makeDebugContext': makeDebugContext, + + /** + * Given a canvas element returns a wrapped canvas element that will + * simulate lost context. The canvas returned adds the following functions. + * + * loseContext: + * simulates a lost context event. + * + * restoreContext: + * simulates the context being restored. + * + * lostContextInNCalls: + * loses the context after N gl calls. + * + * getNumCalls: + * tells you how many gl calls there have been so far. + * + * setRestoreTimeout: + * sets the number of milliseconds until the context is restored + * after it has been lost. Defaults to 0. Pass -1 to prevent + * automatic restoring. + * + * @param {!Canvas} canvas The canvas element to wrap. + */ + 'makeLostContextSimulatingCanvas': makeLostContextSimulatingCanvas, + + /** + * Resets a context to the initial state. + * @param {!WebGLRenderingContext} ctx The webgl context to + * reset. + */ + 'resetToInitialState': resetToInitialState +}; + +}(); +;/** + * @class Generic map of IDs to items - can generate own IDs or accept given IDs. IDs should be strings in order to not + * clash with internally generated IDs, which are numbers. + * @private + */ +var SceneJS_Map = function(items, _baseId) { + + /** + * @property Items in this map + */ + this.items = items || []; + + + var baseId = _baseId || 0; + var lastUniqueId = baseId + 1; + + /** + * Adds an item to the map and returns the ID of the item in the map. If an ID is given, the item is + * mapped to that ID. Otherwise, the map automatically generates the ID and maps to that. + * + * id = myMap.addItem("foo") // ID internally generated + * + * id = myMap.addItem("foo", "bar") // ID is "foo" + * + */ + this.addItem = function() { + + var item; + + if (arguments.length == 2) { + + var id = arguments[0]; + + item = arguments[1]; + + if (this.items[id]) { // Won't happen if given ID is string + throw SceneJS_error.fatalError(SceneJS.errors.ID_CLASH, "ID clash: '" + id + "'"); + } + + this.items[id] = item; + + return id; + + } else { + + while (true) { + + item = arguments[0]; + var findId = lastUniqueId++; + + if (!this.items[findId]) { + this.items[findId] = item; + return findId; + } + } + } + }; + + /** + * Removes the item of the given ID from the map + */ + this.removeItem = function(id) { + delete this.items[id]; + }; +};;/** + * The SceneJS object. + */ +var SceneJS = new (function () { + + /** + * This SceneJS version + */ + this.VERSION = '3.2'; + + this._baseStateId = 0; + + // Pub/sub support + this._handleMap = new SceneJS_Map(); // Subscription handle pool + this._topicSubs = {}; // A [handle -> callback] map for each topic name + this._handleTopics = {}; // Maps handles to topic names + this._topicPubs = {}; // Maps topics to publications + + /** + * @property {SceneJS_Engine} Engines currently in existance + */ + this._engines = {}; + + this._engineIds = new SceneJS_Map(); + + + /** + * Publishes to a topic. + * + * Immediately notifies existing subscriptions to that topic, retains the publication to give to + * any subsequent notifications on that topic as they are made. + * + * @param {String} topic Publication topic + * @param {Object} pub The publication + * @param {Boolean} [forget] When true, the publication will be sent to subscribers then forgotten, so that any + * subsequent subscribers will not receive it + * @private + */ + this.publish = function (topic, pub, forget) { + if (!forget) { + this._topicPubs[topic] = pub; // Save notification + } + var subsForTopic = this._topicSubs[topic]; + if (subsForTopic) { // Notify subscriptions + for (var handle in subsForTopic) { + if (subsForTopic.hasOwnProperty(handle)) { + subsForTopic[handle].call(this, pub); + } + } + } + }; + + /** + * Removes a topic publication + * + * Immediately notifies existing subscriptions to that topic, sending them each a null publication. + * + * @param topic Publication topic + * @private + */ + this.unpublish = function (topic) { + var subsForTopic = this._topicSubs[topic]; + if (subsForTopic) { // Notify subscriptions + for (var handle in subsForTopic) { + if (subsForTopic.hasOwnProperty(handle)) { + subsForTopic[handle].call(this, null); + } + } + } + delete this._topicPubs[topic]; + }; + + + /** + * Listen for data changes at a particular location + * + *

Your callback will be triggered for + * the initial data and again whenever the data changes. Use {@link #off} to stop receiving updates.

+ * + *

The callback is be called with SceneJS as scope.

+ * + * @param {String} location Publication location + * @param {Function(data)} callback Called when fresh data is available at the location + * @return {String} Handle to the subscription, which may be used to unsubscribe with {@link #off}. + */ + this.on = function (topic, callback) { + var subsForTopic = this._topicSubs[topic]; + if (!subsForTopic) { + subsForTopic = {}; + this._topicSubs[topic] = subsForTopic; + } + var handle = this._handleMap.addItem(); // Create unique handle + subsForTopic[handle] = callback; + this._handleTopics[handle] = topic; + var pub = this._topicPubs[topic]; + if (pub) { // A publication exists, notify callback immediately + callback.call(this, pub); + } + return handle; + }; + + /** + * Unsubscribes from a publication that was previously made with {@link #on}. + * @param handle Publication handle + */ + this.off = function (handle) { + var topic = this._handleTopics[handle]; + if (topic) { + delete this._handleTopics[handle]; + var topicSubs = this._topicSubs[topic]; + if (topicSubs) { + delete topicSubs[handle]; + } + this._handleMap.removeItem(handle); // Release handle + if (topic == "rendered") { + this._engine.branchDirty(this); + } + } + }; + + /** + * Listens for exactly one data update at the specified location, and then stops listening. + *

This is equivalent to calling {@link #on}, and then calling {@link #off} inside the callback function.

+ * @param {String} location Data location to listen to + * @param {Function(data)} callback Called when fresh data is available at the location + */ + this.once = function (topic, callback) { + var self = this; + var sub = this.on(topic, + function (pub) { + self.off(sub); + callback(pub); + }); + }; + + /** + * Creates a new scene from the given JSON description and begins rendering it + * + * @param {String} json JSON scene description + * @param {*} options Optional options + * @param {Boolean} options.simulateWebGLContextLost Set true to enable simulation of lost WebGL context (has performance impact) + * @returns {SceneJS.Scene} New scene + */ + this.createScene = function (json, options) { + + json = json || {}; + + if (json.id) { + if (this._engines[json.id]) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Scene already exists with this ID: '" + json.id + "'"); + } + this._engineIds.addItem(json.id, {}); + } else { + json.id = this._engineIds.addItem({}); + } + + var engine = new SceneJS_Engine(json, options); + + this._engines[json.id] = engine; + + SceneJS_events.fireEvent(SceneJS_events.SCENE_CREATED, { // Notify modules that need to know about new scene + engine:engine + }); + + engine.scene.start(options); + + return engine.scene; + }; + + /** + * Gets an existing scene + * + * @param {String} sceneId ID of target scene + * @deprecated + * @returns {SceneJS.Scene} The selected scene + */ + this.scene = function (sceneId) { + + var engine = this._engines[sceneId]; + + return engine ? engine.scene : null; + }; + + /** + * Gets an existing scene. + * + * When no scene ID is given, the first scene found is returned. This is a shorthand convenience for + * easy scripting when only one scene is defined. + * + * @param {String} [sceneId] ID of target scene + * @returns {SceneJS.Scene} The selected scene + */ + this.getScene = function (sceneId) { + + if (!sceneId) { + for (var sceneId in this._engines) { + if (this._engines.hasOwnProperty(sceneId)) { + return this._engines[sceneId].scene; + } + } + } + + var engine = this._engines[sceneId]; + + return engine ? engine.scene : null; + }; + + /** + * Gets existing scenes + * + * @returns Existing scenes, mapped to their IDs + */ + this.getScenes = function () { + + var scenes = {}; + + for (var sceneId in this._engines) { + if (this._engines.hasOwnProperty(sceneId)) { + scenes[sceneId] = this._engines[sceneId].scene; + } + } + + return scenes; + }; + + /** + * Tests if the given object is an array + * @private + */ + this._isArray = function (testObject) { + return testObject && !(testObject.propertyIsEnumerable('length')) + && typeof testObject === 'object' && typeof testObject.length === 'number'; + }; + + /** + * + */ + this._shallowClone = function (o) { + var o2 = {}; + for (var name in o) { + if (o.hasOwnProperty(name)) { + o2[name] = o[name]; + } + } + return o2; + }; + + /** + * Add properties of o to o2 where undefined or null on o2 + * @private + */ + this._applyIf = function (o, o2) { + for (var name in o) { + if (o.hasOwnProperty(name)) { + if (o2[name] == undefined || o2[name] == null) { + o2[name] = o[name]; + } + } + } + return o2; + }; + + /** + * Add properties of o to o2, overwriting them on o2 if already there. + * The optional clear flag causes properties on o2 to be cleared first + * @private + */ + this._apply = function (o, o2, clear) { + var name; + if (clear) { + for (name in o2) { + if (o2.hasOwnProperty(name)) { + delete o2[name]; + } + } + } + for (name in o) { + if (o.hasOwnProperty(name) && o[name] != undefined) { + o2[name] = o[name]; + } + } + return o2; + }; + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + /** + * Tests is an object is empty + * @param obj + * @returns {boolean} + * @private + */ + this._isEmpty =function(obj) { + // null and undefined are "empty" + if (obj == null) return true; + // Assume if it has a length property with a non-zero value + // that that property is correct. + if (obj.length > 0) return false; + if (obj.length === 0) return true; + // Otherwise, does it have any properties of its own? + // Note that this doesn't handle + // toString and valueOf enumeration bugs in IE < 9 + for (var key in obj) { + if (hasOwnProperty.call(obj, key)) return false; + } + return true; + }; + + /** + * Resets SceneJS, destroying all existing scenes + */ + this.reset = function () { + + var temp = []; + + for (var id in this._engines) { // Collect engines to destroy + if (this._engines.hasOwnProperty(id)) { + + temp.push(this._engines[id]); + + delete this._engines[id]; + + this._engineIds.removeItem(id); + } + } + + while (temp.length > 0) { // Destroy the engines + temp.pop().destroy(); + } + + SceneJS_events.fireEvent(SceneJS_events.RESET); + }; + +})(); +;// Configure RequireJS to find plugins relative to plugins location +(function () { + + var pluginPath; + + SceneJS.on("configs", + function (configs) { + if (configs.pluginPath != pluginPath) { + pluginPath = configs.pluginPath; + var libPath = pluginPath + "/lib"; + require.config({ + paths:{ + "scenejsPluginDeps":libPath + } + }); + } + }); +})();;/** + * @private + */ +var SceneJS_eventManager = function () { + + this._handlerIds = new SceneJS_Map(); + + this.typeHandlers = {}; +}; + +/** + * + */ +SceneJS_eventManager.prototype.createEvent = function (type) { + + if (this.typeHandlers[type]) { + return; + } + + this.typeHandlers[type] = { + handlers:{}, + numSubs:0 + }; +}; + +/** + * Subscribes to an event defined on this event manager + * + * @param {String} type Event type one of the values in SceneJS_events + * @param {Function} callback Handler function that will accept whatever parameter object accompanies the event + * @return {String} handle Handle to the event binding + */ +SceneJS_eventManager.prototype.onEvent = function (type, callback) { + + var handlersForType = this.typeHandlers[type] || (this.typeHandlers[type] = { + handlers:{}, + numSubs:0 + }); + + var handlerId = this._handlerIds.addItem(type); + + var handlers = handlersForType.handlers; + handlers[handlerId] = callback; + handlersForType.numSubs++; + + return handlerId; +}; + +/** + * + */ +SceneJS_eventManager.prototype.fireEvent = function (type, params) { + + var handlersForType = this.typeHandlers[type] || (this.typeHandlers[type] = { + handlers:{}, + numSubs:0 + }); + + if (handlersForType.numSubs > 0) { + + var handlers = handlersForType.handlers; + + for (var handlerId in handlers) { + if (handlers.hasOwnProperty(handlerId)) { + handlers[handlerId](params); + } + } + } +}; + +/** + * Unsubscribes to an event previously subscribed to on this manager + * + * @param {String} handlerId Subscription handle + */ +SceneJS_eventManager.prototype.unEvent = function (handlerId) { + + var type = this._handlerIds.items[handlerId]; + if (!type) { + return; + } + + this._handlerIds.removeItem(handlerId); + + var handlers = this.typeHandlers[type]; + + if (!handlers) { + return; + } + + delete handlers[handlerId]; + this.typeHandlers[type].numSubs--; +}; +;/** + * SceneJS plugin registry + */ +SceneJS.Plugins = new (function () { + + // Plugin map for each node type + var nodePlugins = {}; + + // Subscribers to plugins + var pluginSubs = {}; + + /** + * Installs a plugin into SceneJS + * @param {String} nodeType Node type name + * @param {String} pluginType Plugin type name + * @param [{String}] deps List of URLs of JavaScript files that the plugin depends on + * @param {Function} plugin Plugin constructor + */ + this.addPlugin = function () { + var nodeType = arguments[0]; + var pluginType = arguments[1]; + var deps; + var plugin; + if (arguments.length == 4) { + deps = arguments[2]; + plugin = arguments[3]; + } else { + plugin = arguments[2]; + } + addPlugin(nodeType, pluginType, deps, plugin); + }; + + function addPlugin(nodeType, pluginType, deps, plugin) { + var plugins = nodePlugins[nodeType] || (nodePlugins[nodeType] = {}); + plugins[pluginType] = plugin; + // Load dependencies, if any + loadDeps(deps, + 0, + function () { + // Notify and unsubscribe subscribers + var subId = nodeType + pluginType; + var subs = pluginSubs[subId] || (pluginSubs[subId] = []); + while (subs.length > 0) { + subs.pop()(plugin); + } + delete pluginSubs[subId]; + }); + } + + // Loads list of dependencies, synchronously and in order + function loadDeps(deps, i, ok) { + if (!deps || i >= deps.length) { + ok(); + return; + } + var src = deps[i]; + var pluginPath = SceneJS_configsModule.configs.pluginPath; + if (!pluginPath) { + throw "no pluginPath config"; // Build script error - should create this config + } + src = pluginPath + "/" + src; + loadScript(src, + function () { + loadDeps(deps, i + 1, ok); + }); + } + + /** + * Tests if given plugin is installed + */ + this.hasPlugin = function (nodeType, pluginType) { + var plugins = nodePlugins[nodeType]; + return (plugins && !!plugins[pluginType]); + }; + + /** + * Returns installed plugin of given type and ID + */ + this.getPlugin = function (nodeType, pluginType, ok) { + var plugins = nodePlugins[nodeType]; + if (plugins) { + var plugin = plugins[pluginType]; + if (plugin) { + ok(plugin); + return; + } + } + var subId = nodeType + pluginType; + var subs = pluginSubs[subId] || (pluginSubs[subId] = []); + subs.push(ok); + if (subs.length > 1) { // Not first sub + return; + } + var self = this; + var pluginPath = SceneJS_configsModule.configs.pluginPath; + if (!pluginPath) { + throw "no pluginPath config"; // Build script error - should create this config + } + var pluginFilePath = pluginPath + "/" + nodeType + "/" + pluginType + ".js"; + loadScript(pluginFilePath); + }; + + function loadScript(src, ok) { + var script = document.createElement("script"); + script.type = "text/javascript"; + if (script.readyState) { //IE + script.onreadystatechange = function () { + if (script.readyState == "loaded" || + script.readyState == "complete") { + script.onreadystatechange = null; + if (ok) { + ok(); + } + } + }; + } else { //Others + script.onload = function () { + if (ok) { + ok(); + } + }; + } + script.src = src; + document.getElementsByTagName("head")[0].appendChild(script); + } + +})();;/** + * @private + */ +var SceneJS_events = new (function () { + + this.ERROR = 0; + this.RESET = 1; // SceneJS framework reset + this.NODE_CREATED = 2; // Scene has just been created + this.SCENE_CREATED = 3; // Scene has just been created + this.SCENE_COMPILING = 4; // Scene about to be compiled and drawn + this.SCENE_DESTROYED = 5; // Scene just been destroyed + this.OBJECT_COMPILING = 6; + this.WEBGL_CONTEXT_LOST = 7; + this.WEBGL_CONTEXT_RESTORED = 8; + + /* Priority queue for each type of event + */ + var events = []; + + /** + * Registers a handler for the given event and returns a subscription handle + * + * The handler can be registered with an optional priority number which specifies the order it is + * called among the other handler already registered for the event. + * + * So, with n being the number of commands registered for the given event: + * + * (priority <= 0) - command will be the first called + * (priority >= n) - command will be the last called + * (0 < priority < n) - command will be called at the order given by the priority + * @private + * @param type Event type - one of the values in SceneJS_events + * @param command - Handler function that will accept whatever parameter object accompanies the event + * @param priority - Optional priority number (see above) + * @return {String} - Subscription handle + */ + this.addListener = function (type, command, priority) { + + var list = events[type]; + + if (!list) { + list = []; + events[type] = list; + } + + var handler = { + command:command, + priority:(priority == undefined) ? list.length : priority + }; + + var index = -1; + + for (var i = 0, len = list.length; i < len; i++) { + if (!list[i]) { + index = i; + break; + } + } + + if (index < 0) { + list.push(handler); + index = list.length - 1; + } + +// +// for (var i = 0; i < list.length; i++) { +// if (list[i].priority > handler.priority) { +// list.splice(i, 0, handler); +// return i; +// } +// } + + + var handle = type + "." + index; + + return handle; + }; + + /** + * Removes a listener + * @param handle Subscription handle + */ + this.removeListener = function (handle) { + + var lastIdx = handle.lastIndexOf("."); + + var type = parseInt(handle.substr(0, lastIdx)); + var index = parseInt(handle.substr(lastIdx + 1)); + + var list = events[type]; + + if (!list) { + return; + } + + delete list[index]; + }; + + /** + * @private + */ + this.fireEvent = function (type, params) { + + var list = events[type]; + + if (list) { + params = params || {}; + for (var i = 0; i < list.length; i++) { + if (list[i]) { + list[i].command(params); + } + } + } + }; + +})(); + + +/** + * Subscribe to SceneJS events + * @deprecated + */ +SceneJS.bind = function (name, func) { + switch (name) { + + case "error" : + + return SceneJS_events.addListener(SceneJS_events.ERROR, func); + break; + + case "reset" : + + return SceneJS_events.addListener( + SceneJS_events.RESET, + function () { + func(); + }); + break; + + case "webglcontextlost" : + + return SceneJS_events.addListener( + SceneJS_events.WEBGL_CONTEXT_LOST, + function (params) { + func(params); + }); + break; + + case "webglcontextrestored" : + + return SceneJS_events.addListener( + SceneJS_events.WEBGL_CONTEXT_RESTORED, + function (params) { + func(params); + }); + break; + + default: + throw SceneJS_error.fatalError("SceneJS.bind - this event type not supported: '" + name + "'"); + } +}; + +/* Subscribe to SceneJS events + * @deprecated + */ +SceneJS.onEvent = SceneJS.bind; + +/* Unsubscribe from event + */ +SceneJS.unEvent = function (handle) { + return SceneJS_events.removeListener(handle); +}; + +SceneJS.subscribe = SceneJS.addListener = SceneJS.onEvent = SceneJS.bind; + +SceneJS.unsubscribe = SceneJS.unEvent; + + +SceneJS.on = SceneJS.onEvent; +SceneJS.off = SceneJS.unEvent; + + + +;/** + * + */ +var SceneJS_Canvas = function (id, canvasId, contextAttr, options) { + + /** + * ID of this canvas + */ + this.canvasId; + + if (!canvasId) { + // Automatic default canvas + canvasId = "canvas-" + id; + var body = document.getElementsByTagName("body")[0]; + var div = document.createElement('div'); + var style = div.style; + style.height = "100%"; + style.width = "100%"; + style.padding = "0"; + style.margin = "0"; + style.left = "0"; + style.top = "0"; + style.position = "absolute"; + // style["z-index"] = "10000"; + div.innerHTML += ''; + body.appendChild(div); + } + + // Bind to canvas + var canvas = document.getElementById(canvasId); + if (!canvas) { + throw SceneJS_error.fatalError(SceneJS.errors.CANVAS_NOT_FOUND, + "SceneJS.Scene attribute 'canvasId' does not match any elements in the page"); + } + this.canvasId = canvasId; + + /** + * WebGL context options + */ + this.options = options || {}; + + this.canvas = (this.options.simulateWebGLContextLost) + ? WebGLDebugUtils.makeLostContextSimulatingCanvas(canvas) + : canvas; + + this.ssaaMultiplier = this.options.ssaaMultiplier || 1; + + // If the canvas uses css styles to specify the sizes make sure the basic + // width and height attributes match or the WebGL context will use 300 x 150 + + this.canvas.width = this.canvas.clientWidth * this.ssaaMultiplier; + this.canvas.height = this.canvas.clientHeight * this.ssaaMultiplier; + + /** + * Attributes given when initialising the WebGL context + */ + this.contextAttr = contextAttr; + + /** + * The WebGL context + */ + this.gl = null; + + this.initWebGL(); +}; + +/** + * Names of recognised WebGL contexts + */ +SceneJS_Canvas.prototype._WEBGL_CONTEXT_NAMES = [ + "webgl", + "experimental-webgl", + "webkit-3d", + "moz-webgl", + "moz-glweb20" +]; + +/** + * Initialise the WebGL context + + */ +SceneJS_Canvas.prototype.initWebGL = function () { + + for (var i = 0; !this.gl && i < this._WEBGL_CONTEXT_NAMES.length; i++) { + try { + this.gl = this.canvas.getContext(this._WEBGL_CONTEXT_NAMES[i], this.contextAttr); + } catch (e) { // Try with next context name + } + } + + if (!this.gl) { + throw SceneJS_error.fatalError( + SceneJS.errors.WEBGL_NOT_SUPPORTED, + 'Failed to get a WebGL context'); + } + + this.UINT_INDEX_ENABLED = !!this.gl.getExtension("OES_element_index_uint"); +}; + + +/** + * Simulate a lost WebGL context. + * Only works if the simulateWebGLContextLost was given as an option to the canvas' constructor. + */ +SceneJS_Canvas.prototype.loseWebGLContext = function () { + if (this.options.simulateWebGLContextLost) { + this.canvas.loseContext(); + } +}; + +/** + * Set canvas size multiplier for supersample anti-aliasing + */ +SceneJS_Canvas.prototype.setSSAAMultiplier = function (ssaaMultiplier) { + this.ssaaMultiplier = ssaaMultiplier; + this.canvas.width = this.canvas.clientWidth * ssaaMultiplier; + this.canvas.height = this.canvas.clientHeight * ssaaMultiplier; +}; + + +;/** + * @class A container for a scene graph and its display + * + * + * @private + */ +var SceneJS_Engine = function (json, options) { + json.type = "scene"; // The type property supplied by user on the root JSON node is ignored - would always be 'scene' + + /** + * ID of this engine, also the ID of this engine's {@link SceneJS.Scene} + * @type String + */ + this.id = json.id; + + + /** + * Number of times the scene is drawn each time it's rendered. + *

This is useful for when we need to do things like render for left and right eyes. + * @type {*|number} + */ + this._numPasses = json.numPasses || 1; + + /** + * Canvas and GL context for this engine + */ + this.canvas = new SceneJS_Canvas(this.id, json.canvasId, json.contextAttr, options); + + /** + * Manages firing of and subscription to events + */ + this.events = new SceneJS_eventManager(); + + /** + * State core factory - creates, stores, shares and destroys cores + */ + this._coreFactory = new SceneJS_CoreFactory(); + + /** + * Manages creation, recycle and destruction of {@link SceneJS.Node} instances for this engine's scene graph + */ + this._nodeFactory = new SceneJS_NodeFactory(); + + /** + * The engine's scene renderer + * @type SceneJS_Display + */ + this.display = new SceneJS_Display({ + canvas: this.canvas, + transparent: json.transparent, + dof: json.dof + }); + + /** + * Flags the entirety of the scene graph as needing to be (re)compiled into the display + */ + this.sceneDirty = false; + + /** + * Flag set when at least one branch of the scene graph needs recompilation + */ + this._sceneBranchesDirty = false; + + /** + * List of nodes scheduled for destruction by #destroyNode + * Destructions are done in a batch at the end of each render so as not to disrupt the render. + */ + this._nodesToDestroy = []; + + /** + * Number of nodes in destruction list + */ + this._numNodesToDestroy = 0; + + /** + * Frame rate. 0 means as fast as the browser will render. + */ + this.fps = json.fps || 0; + + /** + * Flag which is set while this engine is running - set after call to #start, unset after #stop or #pause + */ + this.running = false; + + /** + * Flag which is set while this engine is paused - set after call to #pause, unset after #stop or #start + */ + this.paused = false; + + /** + * Flag set once this engine has been destroyed + */ + this.destroyed = false; + + /** + * The current scene graph status + */ + this.sceneStatus = { + nodes: {}, // Status for each node + numTasks: 0 // Number of loads currently in progress + }; + + var self = this; + + + // Create scene root first, then create its subnodes + // This way nodes can access the scene in their constructors + var nodes = json.nodes; + json.nodes = null; + this.scene = this.createNode(json); // Create scene root + + if (nodes) { + json.nodes = nodes; + this.scene.addNodes(nodes); // then create sub-nodes + } + + this.canvas.canvas.addEventListener(// WebGL context lost + "webglcontextlost", + function (event) { + event.preventDefault(); + self.stop(); + SceneJS_events.fireEvent(SceneJS_events.WEBGL_CONTEXT_LOST, { scene: self.scene }); + }, + false); + + this.canvas.canvas.addEventListener(// WebGL context recovered + "webglcontextrestored", + function (event) { + self.canvas.initWebGL(); + self._coreFactory.webglRestored(); // Reallocate WebGL resources for node state cores + self.display.webglRestored(); // Reallocate shaders and re-cache shader var locations for display state chunks + SceneJS_events.fireEvent(SceneJS_events.WEBGL_CONTEXT_RESTORED, { scene: self.scene }); + self.start(); + }, + false); +}; + +/** + * Sets the number of times the scene is drawn on each render. + *

This is useful for when we need to do things like render for left and right eyes. + * @param {Number} numPasses The number of times the scene is drawn on each frame. + * @see #getTagMask + * @see SceneJS.Tag + */ +SceneJS_Engine.prototype.setNumPasses = function (numPasses) { + this._numPasses = numPasses; +}; + +/** + * Simulate a lost WebGL context. + * Only works if the simulateWebGLContextLost was given as an option to the engine's constructor. + */ +SceneJS_Engine.prototype.loseWebGLContext = function () { + this.canvas.loseWebGLContext(); +}; + +/** + * Gets/loads the given node type + * + * @param {String} type Node type name + * @param {Function(Function)} ok Callback fired when type loaded, returns the type constructor + */ +SceneJS_Engine.prototype.getNodeType = function (type, ok) { + SceneJS_NodeFactory.getNodeType(type, ok); +}; + +/** + * Returns true if the given node type is currently loaded (ie. load not required) + * @param type + */ +SceneJS_Engine.prototype.hasNodeType = function (type) { + return !!SceneJS_NodeFactory.nodeTypes[type]; +}; + +/** + * Recursively parse the given JSON scene graph representation and return a scene (sub)graph. + * + * @param {Object} json JSON definition of a scene graph or subgraph + * @param {Function} ok Callback fired when node created, with the node as argument + */ +SceneJS_Engine.prototype.createNode = function (json, ok) { + + // Do buffered node destroys - don't want olds nodes + // hanging around whose IDs may clash with the new node + this._doDestroyNodes(); + + json.type = json.type || "node"; // Nodes are SceneJS.Node type by default + var core = this._coreFactory.getCore(json.type, json.coreId); // Create or share a core + var self = this; + + return this._nodeFactory.getNode( + this, + json, + core, + function (node) { + + // Create child nodes + if (!node._fromPlugin && json.nodes) { + var numNodes = 0; + for (var i = 0, len = json.nodes.length; i < len; i++) { + self.createNode( + json.nodes[i], + function (childNode) { + node.addNode(childNode); + if (++numNodes == len) { + if (ok) { + ok(node); + } + self.scene.publish("nodes/" + node.id, node); + } + }); + } + } else { + if (ok) { + ok(node); + self.scene.publish("nodes/" + node.id, node); + } + } + }); +}; + +/** + * Performs pending node destructions. When destroyed, each node and its core is released back to the + * node and core pools for reuse, respectively. + */ +SceneJS_Engine.prototype._doDestroyNodes = function () { + var node; + while (this._numNodesToDestroy > 0) { + node = this._nodesToDestroy[--this._numNodesToDestroy]; + node._doDestroy(); + this._coreFactory.putCore(node._core); // Release state core for reuse + this._nodeFactory.putNode(node); // Release node for reuse + } +}; + +/** + * Finds the node with the given ID in this engine's scene graph + * @return {SceneJS.Node} The node if found, else null + */ +SceneJS_Engine.prototype.findNode = function (nodeId) { + return this._nodeFactory.nodes.items[nodeId]; +}; + +/** Finds nodes in this engine's scene graph that have nodes IDs matching the given regular expression + * @param {String} nodeIdRegex Regular expression to match on node IDs + * @return {[SceneJS.Node]} Array of nodes whose IDs match the given regex + */ +SceneJS_Engine.prototype.findNodes = function (nodeIdRegex) { + + var regex = new RegExp(nodeIdRegex); + var nodes = []; + var nodeMap = this._nodeFactory.nodes.items; + + for (var nodeId in nodeMap) { + if (nodeMap.hasOwnProperty(nodeId)) { + + if (regex.test(nodeId)) { + nodes.push(nodeMap[nodeId]); + } + } + } + + return nodes; +}; + +/** + * Tests whether a core of the given ID exists for the given node type + * @param {String} type Node type + * @param {String} coreId + * @returns Boolean + */ +SceneJS_Engine.prototype.hasCore = function (type, coreId) { + return this._coreFactory.hasCore(type, coreId); +}; + +/** + * Schedules the given subtree of this engine's {@link SceneJS.Scene} for recompilation + * + * @param {SceneJS.Node} node Root node of the subtree to recompile + */ +SceneJS_Engine.prototype.branchDirty = function (node) { + + if (this.sceneDirty) { + return; // Whole scene will recompile anyway + } + + /* Dealing with some weirdness with the embedded window and iframe / window fascism. + */ + if (node == window) { + return; + } + + node.branchDirty = true; + node.dirty = true; + + for (var n = node.parent; n && !(n.dirty || n.branchDirty); n = n.parent) { // Flag path down to this node + n.dirty = true; + } + + this._sceneBranchesDirty = true; +}; + +/** + * Renders a single frame. Does any pending scene compilations or draw graph updates first. + * Ordinarily the frame is rendered only if compilations or draw graph updates were performed, + * but may be forced to render the frame regardless. + * + * @param {*} params Rendering parameters + * @param {Boolean} params.clear True to clear the display first (default) + */ +SceneJS_Engine.prototype.renderFrame = function (params) { + + var rendered = false; + + if (this._needCompile() || (params && params.force)) { + +// // Render display graph +// this.display.render(params); + + var time = (new Date()).getTime(); + + var force = params && params.force; + + // Render the scene once for each pass + for (var i = 0; i < this._numPasses; i++) { + + // Notify that render is upcoming + this.scene.publish("rendering", { + pass: i + }); + + // Compile scene graph to display graph, if necessary + this._doCompile(); + + // Render display graph + // Clear buffers only on first frame + this.display.render({ + clear: i == 0, + force: force + }); + + // Notify that render completed + this.scene.publish("rendered", { + sceneId: this.id, + time: time, + pass: i + }); + + rendered = true; + } + } + + return rendered; +}; + +/** + * Starts the render loop on this engine. + */ +SceneJS_Engine.prototype.start = function () { + + if (!this.running) { // Do nothing if already started + + this.running = true; + this.paused = false; + this.sceneDirty = true; + + var self = this; + var fnName = "__scenejs_sceneLoop" + this.id; + var sleeping = false; + var time = (new Date()).getTime(); + var prevTime = time; + var startTime = time; + var scene = this.scene; + var rendered = false; + var canvas = this.canvas.canvas; + var width; + var height; + var lastWidth = null; + var lastHeight = null; + + // Notify started + this.events.fireEvent("started", { + sceneId: self.id, + startTime: startTime + }); + + function draw() { + rendered = false; + + // Render the scene once for each pass + for (var i = 0; i < self._numPasses; i++) { + + if (self._needCompile() || rendered) { + + sleeping = false; + + // Notify we're about to do a render + scene.publish("rendering", { + pass: i + }); + + // Compile scene graph to display graph, if necessary + self._doCompile(); + + // Render display graph + // Clear buffers only on first frame + self.display.render({ + clear: i == 0 + }); + + // Notify that we've just done a render + scene.publish("rendered", { + sceneId: self.id, + time: time, + pass: i + }); + + rendered = true; + } + } + + // If any of the passes did not render anything, then put the render loop to sleep again + if (!rendered) { + if (!sleeping) { + scene.publish("sleep", { + sceneId: self.id, + startTime: startTime, + prevTime: time, + time: time + }); + } + sleeping = true; + } + } + + // Animation frame callback + window[fnName] = function () { + + var ssaaMultiplier = self.canvas.ssaaMultiplier || 1; + + width = canvas.width = canvas.clientWidth * ssaaMultiplier; + height = canvas.height = canvas.clientHeight * ssaaMultiplier; + + if (width != lastWidth || height != lastHeight) { + scene.publish("canvasSize", { + width: width, + height: height, + aspect: width / height + }); + self.display.imageDirty = true; + lastWidth = width; + lastHeight = height; + } + + if (self.running && !self.paused) { + + time = (new Date()).getTime(); + + scene.publish("tick", { + sceneId: self.id, + startTime: startTime, + prevTime: prevTime, + time: time + }); + + prevTime = time; + + if (!self.running) { // "tick" handler have destroyed scene + return; + } + + requestAnimationFrame(draw); + } + + if (self.running) { + if (self.fps > 0) { + setTimeout(window[fnName], 1000 / self.fps); + } else { + requestAnimationFrame(window[fnName]); + } + } + }; + + setTimeout(window[fnName], 0); + } +}; + +/** + * Performs a pick on this engine and returns a hit record containing at least the name of the picked + * scene object (as configured by SceneJS.Name nodes) and the canvas pick coordinates. Ordinarily, picking + * is the simple GPU color-name mapped method, but this method can instead perform a ray-intersect pick + * when the 'rayPick' flag is set on the options parameter for this method. For that mode, this method will + * also find the intersection point on the picked object's near surface with a ray cast from the eye that passes + * through the mouse position on the projection plane. + * + * @param {Number} canvasX X-axis canvas pick coordinate + * @param {Number} canvasY Y-axis canvas pick coordinate + * @param options Pick options + * @param options.rayPick Performs additional ray-intersect pick when true + * @returns The pick record + */ +SceneJS_Engine.prototype.pick = function (canvasX, canvasY, options) { + + // Do any pending scene compilations + if (this._needCompile()) { + this._doCompile(); + } + + var hit = this.display.pick({ + canvasX: canvasX, + canvasY: canvasY, + rayPick: options ? options.rayPick : false + }); + + return hit; +}; + +/** + * Reads colors of pixels from the last rendered frame. + */ +SceneJS_Engine.prototype.readPixels = function (entries, size) { + + // Do any pending scene compilations + if (this._needCompile()) { + this._doCompile(); + } + + return this.display.readPixels(entries, size); +}; + +/** + * Returns true if view needs refreshing from scene + * @returns {Boolean} + * @private + */ +SceneJS_Engine.prototype._needCompile = function () { + return (this.display.imageDirty // Frame buffer needs redraw + || this.display.drawListDirty // Draw list needs rebuild + || this.display.stateSortDirty // Draw list needs to redetermine state order + || this.display.stateOrderDirty // Draw list needs state sort + || this.display.objectListDirty // Draw list needs to be rebuilt + || this._sceneBranchesDirty // One or more branches in scene graph need (re)compilation + || this.sceneDirty); // Whole scene needs recompilation +}; + +/** + * Performs any pending scene compilations or display rebuilds + */ +SceneJS_Engine.prototype._doCompile = function () { + if (this._sceneBranchesDirty || this.sceneDirty) { // Need scene graph compilation + this._sceneBranchesDirty = false; + SceneJS_events.fireEvent(SceneJS_events.SCENE_COMPILING, { // Notify compilation support start + engine: this // Compilation support modules get ready + }); + this.pubSubProxy = new SceneJS_PubSubProxy(this.scene, null); + var ctx = { + pubSubProxy: this.pubSubProxy + }; + this.scene._compileNodes(ctx); // Begin depth-first compilation descent into scene sub-nodes + this.sceneDirty = false; + } + this._doDestroyNodes(); // Garbage collect destroyed nodes - node destructions set imageDirty true +}; + +/** + * Pauses/unpauses the render loop + * @param {Boolean} doPause Pauses or unpauses the render loop + */ +SceneJS_Engine.prototype.pause = function (doPause) { + this.paused = doPause; +}; + +/** + * Stops the render loop + */ +SceneJS_Engine.prototype.stop = function () { + if (this.running) { + this.running = false; + this.paused = false; + window["__scenejs_sceneLoop" + this.id] = null; + // this.events.fireEvent("stopped", { sceneId: this.id }); + } +}; + +/** + * Destroys a node within this engine's {@link SceneJS.Scene} + * + * @param {SceneJS.Node} node Node to destroy + */ +SceneJS_Engine.prototype.destroyNode = function (node) { + + /* The node is actually scheduled for lazy destruction within the next invocation of #_tryCompile + */ + this._nodesToDestroy[this._numNodesToDestroy++] = node; + + /* Stop tracking node's status + */ + var nodeStatus = this.sceneStatus.nodes[node.id]; + + if (nodeStatus) { + this.sceneStatus.numTasks -= nodeStatus.numTasks; + delete this.sceneStatus.nodes[node.id]; + } +}; + +/** + * Destroys this engine + */ +SceneJS_Engine.prototype.destroy = function () { + this.destroyed = true; + // this.events.fireEvent("destroyed", { sceneId: this.id }); +}; + +/*--------------------------------------------------------------------------------------------------------------------- + * JavaScript augmentations to support render loop + *--------------------------------------------------------------------------------------------------------------------*/ + +if (!self.Int32Array) { + self.Int32Array = Array; + self.Float32Array = Array; +} + +// Ripped off from THREE.js - https://github.com/mrdoob/three.js/blob/master/src/Three.js +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + +(function () { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] + || window[vendors[x] + 'RequestCancelAnimationFrame']; + } + + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; +}()); +;/** + * Backend module that provides single point through which exceptions may be raised + * + * @class SceneJS_error + * @private + */ +var SceneJS_error = new (function() { + + var activeSceneId; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, // Set default logging for scene root + function(params) { + activeSceneId = params.engine.id; + }); + + SceneJS_events.addListener( + SceneJS_events.RESET, + function() { + activeSceneId = null; + }, + 100000); // Really low priority - must be reset last + + this.fatalError = function(code, message) { + if (typeof code == "string") { + message = code; + code = SceneJS.errors.ERROR; + } + var error = { + errorName: SceneJS.errors._getErrorName(code) || "ERROR", + code: code, + exception: message, + fatal: true + }; + if (activeSceneId) { + error.sceneId = activeSceneId; + } + SceneJS_events.fireEvent(SceneJS_events.ERROR, error); + return message; + }; + + this.error = function(code, message) { + var error = { + errorName: SceneJS.errors._getErrorName(code) || "ERROR", + code: code, + exception: message, + fatal: false + }; + if (activeSceneId) { + error.sceneId = activeSceneId; + } + SceneJS_events.fireEvent(SceneJS_events.ERROR, error); + }; +})(); + +(function() { + SceneJS.errors = {}; + + var n = 0; + SceneJS.errors.ERROR = n++; + SceneJS.errors.INVALID_FRAMEBUFFER = n++; + SceneJS.errors.WEBGL_NOT_SUPPORTED = n++; + SceneJS.errors.WEBGL_CONTEXT_LOST = n++; + SceneJS.errors.NODE_CONFIG_EXPECTED = n++; + SceneJS.errors.ILLEGAL_NODE_CONFIG = n++; + SceneJS.errors.SHADER_COMPILATION_FAILURE = n++; + SceneJS.errors.SHADER_LINK_FAILURE = n++; + SceneJS.errors.CANVAS_NOT_FOUND = n++; + SceneJS.errors.OUT_OF_VRAM = n++; + SceneJS.errors.WEBGL_UNSUPPORTED_NODE_CONFIG = n++; + SceneJS.errors.NODE_NOT_FOUND = n++; + SceneJS.errors.NODE_ILLEGAL_STATE = n++; + SceneJS.errors.ID_CLASH = n++; + SceneJS.errors.PLUGIN_INVALID = n++; +})(); + +SceneJS.errors._getErrorName = function(code) { + for (var key in SceneJS.errors) { + if (SceneJS.errors.hasOwnProperty(key) && SceneJS.errors[key] == code) { + return key; + } + } + return null; +}; + +;/** + * Backend that manages configurations. + * + * @class SceneJS_configsModule + * @private + */ +var SceneJS_configsModule = new (function () { + + this.configs = {}; + var subs = {}; + + /** + * Set a config + * @param path + * @param data + */ + this.setConfigs = function (path, data) { + // Update configs + if (!path) { + this.configs = data; + } else { + var parts = path.split("."); + var cfg = this.configs; + var subCfg; + var name; + for (var i = 0; i < parts.length - 1; i++) { + name = parts[i]; + subCfg = cfg[name]; + if (!subCfg) { + subCfg = cfg[name] = {}; + } + cfg = subCfg; + } + cfg[parts.length - 1] = data; + } + // Notify subscribers + var list = subs[path || "_all"]; + if (list) { + for (var i = 0, len = list.length; i < len; i++) { + list[i](cfg); + } + } + + SceneJS.publish("configs", this.configs); + }; + + /** + * Get a config + * @param path + * @return {*} + */ + this.getConfigs = function (path) { + if (!path) { + return this.configs; + } else { + var cfg = this.configs; + var parts = path.split("."); + for (var i = 0; cfg && i < parts.length; i++) { + cfg = cfg[parts[i]]; + } + return (cfg != undefined) ? cfg : {}; + } + }; + + /** + * Subscribe to updates to a config + * @param path + * @param ok + */ + this.on = function (path, ok) { + path = path || "_all"; + (subs[path] || (subs[path] = [])).push(ok); + ok(this.getConfigs(path)); + }; + +})(); + +/** Sets configurations. + */ +SceneJS.configure = SceneJS.setConfigs = SceneJS.setDebugConfigs = function () { + if (arguments.length == 1) { + SceneJS_configsModule.setConfigs(null, arguments[0]); + } else if (arguments.length == 2) { + SceneJS_configsModule.setConfigs(arguments[0], arguments[1]); + } else { + throw SceneJS_error.fatalError("Illegal arguments given to SceneJS.setDebugs - should be either ({String}:name, {Object}:cfg) or ({Object}:cfg)"); + } +}; + +/** Gets configurations + */ +SceneJS.getConfigs = SceneJS.getDebugConfigs = function (path) { + return SceneJS_configsModule.getConfigs(path); +}; + +;/** + * @class Manages logging + * @private + */ +SceneJS.log = new (function() { + + var activeSceneId; + var funcs = null; + var queues = {}; + var indent = 0; + var indentStr = ""; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, // Set default logging for scene root + function(params) { + activeSceneId = params.engine.id; + }); + + SceneJS_events.addListener( + SceneJS_events.RESET, + function() { + queues = {}; + funcs = null; + activeSceneId = null; + }, + 100000); // Really low priority - must be reset last + + this._setIndent = function(_indent) { + indent = _indent; + var indentArray = []; + for (var i = 0; i < indent; i++) { + indentArray.push("----"); + } + indentStr = indentArray.join(""); + }; + + this.error = function(msg) { + this._log("error", msg); + }; + + this.warn = function(msg) { + this._log("warn", msg); + }; + + this.info = function(msg) { + this._log("info", msg); + }; + + this.debug = function(msg) { + this._log("debug", msg); + }; + + this.setFuncs = function(l) { + if (l) { + funcs = l; + for (var channel in queues) { + this._flush(channel); + } + } + }; + + this._flush = function(channel) { + var queue = queues[channel]; + if (queue) { + var func = funcs ? funcs[channel] : null; + if (func) { + for (var i = 0; i < queue.length; i++) { + func(queue[i]); + } + queues[channel] = []; + } + } + }; + + this._log = function(channel, message) { + if (SceneJS._isArray(message)) { + for (var i = 0; i < message.length; i++) { + this.__log(channel, message[i]); + } + } else { + this.__log(channel, message); + } + }; + + this.__log = function(channel, message) { + message = indentStr + message; + + if (funcs && funcs[channel]) { + funcs[channel](message); + + } else if (console && console[channel]) { + console[channel](message); + } + }; + + this.getFuncs = function() { + return funcs; + }; + +})();;/* + * Optimizations made based on glMatrix by Brandon Jones + */ + +/* + * Copyright (c) 2010 Brandon Jones + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + */ + + +/** + * @param u vec3 + * @param v vec3 + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, u otherwise + * @private + */ +var SceneJS_math_divVec3 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] / v[0]; + dest[1] = u[1] / v[1]; + dest[2] = u[2] / v[2]; + + return dest; +}; + +/** + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_negateVector4 = function(v, dest) { + if (!dest) { + dest = v; + } + dest[0] = -v[0]; + dest[1] = -v[1]; + dest[2] = -v[2]; + dest[3] = -v[3]; + + return dest; +}; + +/** + * @param u vec4 + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, u otherwise + * @private + */ +var SceneJS_math_addVec4 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] + v[0]; + dest[1] = u[1] + v[1]; + dest[2] = u[2] + v[2]; + dest[3] = u[3] + v[3]; + + return dest; +}; + + +/** + * @param v vec4 + * @param s scalar + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_addVec4s = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] + s; + dest[1] = v[1] + s; + dest[2] = v[2] + s; + dest[3] = v[3] + s; + + return dest; +}; + +/** + * @param u vec3 + * @param v vec3 + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, u otherwise + * @private + */ +var SceneJS_math_addVec3 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] + v[0]; + dest[1] = u[1] + v[1]; + dest[2] = u[2] + v[2]; + + return dest; +}; + +/** + * @param v vec3 + * @param s scalar + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, v otherwise + * @private + */ +var SceneJS_math_addVec3s = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] + s; + dest[1] = v[1] + s; + dest[2] = v[2] + s; + + return dest; +}; + +/** @private */ +var SceneJS_math_addScalarVec4 = function(s, v, dest) { + return SceneJS_math_addVec4s(v, s, dest); +}; + +/** + * @param u vec4 + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, u otherwise + * @private + */ +var SceneJS_math_subVec4 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] - v[0]; + dest[1] = u[1] - v[1]; + dest[2] = u[2] - v[2]; + dest[3] = u[3] - v[3]; + + return dest; +}; + +/** + * @param u vec3 + * @param v vec3 + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, v otherwise + * @private + */ +var SceneJS_math_subVec3 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] - v[0]; + dest[1] = u[1] - v[1]; + dest[2] = u[2] - v[2]; + + return dest; +}; + +var SceneJS_math_lerpVec3 = function(t, t1, t2, p1, p2) { + var f2 = (t - t1) / (t2 - t1); + var f1 = 1.0 - f2; + return { + x: p1.x * f1 + p2.x * f2, + y: p1.y * f1 + p2.y * f2, + z: p1.z * f1 + p2.z * f2 + }; +}; + + +/** + * @param u vec2 + * @param v vec2 + * @param dest vec2 - optional destination + * @return {vec2} dest if specified, u otherwise + * @private + */ +var SceneJS_math_subVec2 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] - v[0]; + dest[1] = u[1] - v[1]; + + return dest; +}; + +/** + * @param v vec4 + * @param s scalar + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_subVec4Scalar = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] - s; + dest[1] = v[1] - s; + dest[2] = v[2] - s; + dest[3] = v[3] - s; + + return dest; +}; + +/** + * @param v vec4 + * @param s scalar + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_subScalarVec4 = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = s - v[0]; + dest[1] = s - v[1]; + dest[2] = s - v[2]; + dest[3] = s - v[3]; + + return dest; +}; + +/** + * @param u vec4 + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, u otherwise + * @private + */ +var SceneJS_math_mulVec4 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] * v[0]; + dest[1] = u[1] * v[1]; + dest[2] = u[2] * v[2]; + dest[3] = u[3] * v[3]; + + return dest; +}; + +/** + * @param v vec4 + * @param s scalar + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_mulVec4Scalar = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] * s; + dest[1] = v[1] * s; + dest[2] = v[2] * s; + dest[3] = v[3] * s; + + return dest; +}; + + +/** + * @param v vec3 + * @param s scalar + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, v otherwise + * @private + */ +var SceneJS_math_mulVec3Scalar = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] * s; + dest[1] = v[1] * s; + dest[2] = v[2] * s; + + return dest; +}; + +/** + * @param v vec2 + * @param s scalar + * @param dest vec2 - optional destination + * @return {vec2} dest if specified, v otherwise + * @private + */ +var SceneJS_math_mulVec2Scalar = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] * s; + dest[1] = v[1] * s; + + return dest; +}; + + +/** + * @param u vec4 + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, u otherwise + * @private + */ +var SceneJS_math_divVec4 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + dest[0] = u[0] / v[0]; + dest[1] = u[1] / v[1]; + dest[2] = u[2] / v[2]; + dest[3] = u[3] / v[3]; + + return dest; +}; + +/** + * @param v vec3 + * @param s scalar + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, v otherwise + * @private + */ +var SceneJS_math_divScalarVec3 = function(s, v, dest) { + if (!dest) { + dest = v; + } + + dest[0] = s / v[0]; + dest[1] = s / v[1]; + dest[2] = s / v[2]; + + return dest; +}; + +/** + * @param v vec3 + * @param s scalar + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, v otherwise + * @private + */ +var SceneJS_math_divVec3s = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] / s; + dest[1] = v[1] / s; + dest[2] = v[2] / s; + + return dest; +}; + +/** + * @param v vec4 + * @param s scalar + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_divVec4s = function(v, s, dest) { + if (!dest) { + dest = v; + } + + dest[0] = v[0] / s; + dest[1] = v[1] / s; + dest[2] = v[2] / s; + dest[3] = v[3] / s; + + return dest; +}; + + +/** + * @param s scalar + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_divScalarVec4 = function(s, v, dest) { + if (!dest) { + dest = v; + } + + dest[0] = s / v[0]; + dest[1] = s / v[1]; + dest[2] = s / v[2]; + dest[3] = s / v[3]; + + return dest; +}; + + +/** @private */ +var SceneJS_math_dotVector4 = function(u, v) { + return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2] + u[3] * v[3]); +}; + +/** @private */ +var SceneJS_math_cross3Vec4 = function(u, v) { + var u0 = u[0], u1 = u[1], u2 = u[2]; + var v0 = v[0], v1 = v[1], v2 = v[2]; + return [ + u1 * v2 - u2 * v1, + u2 * v0 - u0 * v2, + u0 * v1 - u1 * v0, + 0.0]; +}; + +/** + * @param u vec3 + * @param v vec3 + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, u otherwise + * @private + */ +var SceneJS_math_cross3Vec3 = function(u, v, dest) { + if (!dest) { + dest = u; + } + + var x = u[0], y = u[1], z = u[2]; + var x2 = v[0], y2 = v[1], z2 = v[2]; + + dest[0] = y * z2 - z * y2; + dest[1] = z * x2 - x * z2; + dest[2] = x * y2 - y * x2; + + return dest; +}; + +/** @private */ +var SceneJS_math_sqLenVec4 = function(v) { + return SceneJS_math_dotVector4(v, v); +}; + +/** @private */ +var SceneJS_math_lenVec4 = function(v) { + return Math.sqrt(SceneJS_math_sqLenVec4(v)); +}; + +/** @private */ +var SceneJS_math_dotVector3 = function(u, v) { + return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]); +}; + +/** @private */ +var SceneJS_math_dotVector2 = function(u, v) { + return (u[0] * v[0] + u[1] * v[1]); +}; + +/** @private */ +var SceneJS_math_sqLenVec3 = function(v) { + return SceneJS_math_dotVector3(v, v); +}; + +/** @private */ +var SceneJS_math_sqLenVec2 = function(v) { + return SceneJS_math_dotVector2(v, v); +}; + +/** @private */ +var SceneJS_math_lenVec3 = function(v) { + return Math.sqrt(SceneJS_math_sqLenVec3(v)); +}; + +/** @private */ +var SceneJS_math_lenVec2 = function(v) { + return Math.sqrt(SceneJS_math_sqLenVec2(v)); +}; + +/** + * @param v vec3 + * @param dest vec3 - optional destination + * @return {vec3} dest if specified, v otherwise + * @private + */ +var SceneJS_math_rcpVec3 = function(v, dest) { + return SceneJS_math_divScalarVec3(1.0, v, dest); +}; + +/** + * @param v vec4 + * @param dest vec4 - optional destination + * @return {vec4} dest if specified, v otherwise + * @private + */ +var SceneJS_math_normalizeVec4 = function(v, dest) { + var f = 1.0 / SceneJS_math_lenVec4(v); + return SceneJS_math_mulVec4Scalar(v, f, dest); +}; + +/** @private */ +var SceneJS_math_normalizeVec3 = function(v, dest) { + var f = 1.0 / SceneJS_math_lenVec3(v); + return SceneJS_math_mulVec3Scalar(v, f, dest); +}; + +// @private +var SceneJS_math_normalizeVec2 = function(v, dest) { + var f = 1.0 / SceneJS_math_lenVec2(v); + return SceneJS_math_mulVec2Scalar(v, f, dest); +}; + +/** @private */ +var SceneJS_math_mat4 = function() { + return new Array(16); +}; + +/** @private */ +var SceneJS_math_dupMat4 = function(m) { + return m.slice(0, 16); +}; + +/** @private */ +var SceneJS_math_getCellMat4 = function(m, row, col) { + return m[row + col * 4]; +}; + +/** @private */ +var SceneJS_math_setCellMat4 = function(m, row, col, s) { + m[row + col * 4] = s; +}; + +/** @private */ +var SceneJS_math_getRowMat4 = function(m, r) { + return [m[r], m[r + 4], m[r + 8], m[r + 12]]; +}; + +/** @private */ +var SceneJS_math_setRowMat4 = function(m, r, v) { + m[r] = v[0]; + m[r + 4] = v[1]; + m[r + 8] = v[2]; + m[r + 12] = v[3]; +}; + +/** @private */ +var SceneJS_math_setRowMat4c = function(m, r, x, y, z, w) { + SceneJS_math_setRowMat4(m, r, [x,y,z,w]); +}; + +/** @private */ +var SceneJS_math_setRowMat4s = function(m, r, s) { + SceneJS_math_setRowMat4c(m, r, s, s, s, s); +}; + +/** @private */ +var SceneJS_math_getColMat4 = function(m, c) { + var i = c * 4; + return [m[i], m[i + 1],m[i + 2],m[i + 3]]; +}; + +/** @private */ +var SceneJS_math_setColMat4v = function(m, c, v) { + var i = c * 4; + m[i] = v[0]; + m[i + 1] = v[1]; + m[i + 2] = v[2]; + m[i + 3] = v[3]; +}; + +/** @private */ +var SceneJS_math_setColMat4c = function(m, c, x, y, z, w) { + SceneJS_math_setColMat4v(m, c, [x,y,z,w]); +}; + +/** @private */ +var SceneJS_math_setColMat4Scalar = function(m, c, s) { + SceneJS_math_setColMat4c(m, c, s, s, s, s); +}; + +/** @private */ +var SceneJS_math_mat4To3 = function(m) { + return [ + m[0],m[1],m[2], + m[4],m[5],m[6], + m[8],m[9],m[10] + ]; +}; + +/** @private */ +var SceneJS_math_m4s = function(s) { + return [ + s,s,s,s, + s,s,s,s, + s,s,s,s, + s,s,s,s + ]; +}; + +/** @private */ +var SceneJS_math_setMat4ToZeroes = function() { + return SceneJS_math_m4s(0.0); +}; + +/** @private */ +var SceneJS_math_setMat4ToOnes = function() { + return SceneJS_math_m4s(1.0); +}; + +/** @private */ +var SceneJS_math_diagonalMat4v = function(v) { + return [ + v[0], 0.0, 0.0, 0.0, + 0.0,v[1], 0.0, 0.0, + 0.0, 0.0, v[2],0.0, + 0.0, 0.0, 0.0, v[3] + ]; +}; + +/** @private */ +var SceneJS_math_diagonalMat4c = function(x, y, z, w) { + return SceneJS_math_diagonalMat4v([x,y,z,w]); +}; + +/** @private */ +var SceneJS_math_diagonalMat4s = function(s) { + return SceneJS_math_diagonalMat4c(s, s, s, s); +}; + +/** @private */ +var SceneJS_math_identityMat4 = function() { + return SceneJS_math_diagonalMat4v([1.0,1.0,1.0,1.0]); +}; + +/** @private */ +var SceneJS_math_isIdentityMat4 = function(m) { + if (m[0] !== 1.0 || m[1] !== 0.0 || m[2] !== 0.0 || m[3] !== 0.0 || + m[4] !== 0.0 || m[5] !== 1.0 || m[6] !== 0.0 || m[7] !== 0.0 || + m[8] !== 0.0 || m[9] !== 0.0 || m[10] !== 1.0 || m[11] !== 0.0 || + m[12] !== 0.0 || m[13] !== 0.0 || m[14] !== 0.0 || m[15] !== 1.0) + { + return false; + } + + return true; +}; + +/** + * @param m mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, m otherwise + * @private + */ +var SceneJS_math_negateMat4 = function(m, dest) { + if (!dest) { + dest = m; + } + + dest[0] = -m[0]; + dest[1] = -m[1]; + dest[2] = -m[2]; + dest[3] = -m[3]; + dest[4] = -m[4]; + dest[5] = -m[5]; + dest[6] = -m[6]; + dest[7] = -m[7]; + dest[8] = -m[8]; + dest[9] = -m[9]; + dest[10] = -m[10]; + dest[11] = -m[11]; + dest[12] = -m[12]; + dest[13] = -m[13]; + dest[14] = -m[14]; + dest[15] = -m[15]; + + return dest; +}; + +/** + * @param a mat4 + * @param b mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, a otherwise + * @private + */ +var SceneJS_math_addMat4 = function(a, b, dest) { + if (!dest) { + dest = a; + } + + dest[0] = a[0] + b[0]; + dest[1] = a[1] + b[1]; + dest[2] = a[2] + b[2]; + dest[3] = a[3] + b[3]; + dest[4] = a[4] + b[4]; + dest[5] = a[5] + b[5]; + dest[6] = a[6] + b[6]; + dest[7] = a[7] + b[7]; + dest[8] = a[8] + b[8]; + dest[9] = a[9] + b[9]; + dest[10] = a[10] + b[10]; + dest[11] = a[11] + b[11]; + dest[12] = a[12] + b[12]; + dest[13] = a[13] + b[13]; + dest[14] = a[14] + b[14]; + dest[15] = a[15] + b[15]; + + return dest; +}; + +/** + * @param m mat4 + * @param s scalar + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, m otherwise + * @private + */ +var SceneJS_math_addMat4Scalar = function(m, s, dest) { + if (!dest) { + dest = m; + } + + dest[0] = m[0] + s; + dest[1] = m[1] + s; + dest[2] = m[2] + s; + dest[3] = m[3] + s; + dest[4] = m[4] + s; + dest[5] = m[5] + s; + dest[6] = m[6] + s; + dest[7] = m[7] + s; + dest[8] = m[8] + s; + dest[9] = m[9] + s; + dest[10] = m[10] + s; + dest[11] = m[11] + s; + dest[12] = m[12] + s; + dest[13] = m[13] + s; + dest[14] = m[14] + s; + dest[15] = m[15] + s; + + return dest; +}; + +/** @private */ +var SceneJS_math_addScalarMat4 = function(s, m, dest) { + return SceneJS_math_addMat4Scalar(m, s, dest); +}; + +/** + * @param a mat4 + * @param b mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, a otherwise + * @private + */ +var SceneJS_math_subMat4 = function(a, b, dest) { + if (!dest) { + dest = a; + } + + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; + dest[3] = a[3] - b[3]; + dest[4] = a[4] - b[4]; + dest[5] = a[5] - b[5]; + dest[6] = a[6] - b[6]; + dest[7] = a[7] - b[7]; + dest[8] = a[8] - b[8]; + dest[9] = a[9] - b[9]; + dest[10] = a[10] - b[10]; + dest[11] = a[11] - b[11]; + dest[12] = a[12] - b[12]; + dest[13] = a[13] - b[13]; + dest[14] = a[14] - b[14]; + dest[15] = a[15] - b[15]; + + return dest; +}; + +/** + * @param m mat4 + * @param s scalar + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, m otherwise + * @private + */ +var SceneJS_math_subMat4Scalar = function(m, s, dest) { + if (!dest) { + dest = m; + } + + dest[0] = m[0] - s; + dest[1] = m[1] - s; + dest[2] = m[2] - s; + dest[3] = m[3] - s; + dest[4] = m[4] - s; + dest[5] = m[5] - s; + dest[6] = m[6] - s; + dest[7] = m[7] - s; + dest[8] = m[8] - s; + dest[9] = m[9] - s; + dest[10] = m[10] - s; + dest[11] = m[11] - s; + dest[12] = m[12] - s; + dest[13] = m[13] - s; + dest[14] = m[14] - s; + dest[15] = m[15] - s; + + return dest; +}; + +/** + * @param s scalar + * @param m mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, m otherwise + * @private + */ +var SceneJS_math_subScalarMat4 = function(s, m, dest) { + if (!dest) { + dest = m; + } + + dest[0] = s - m[0]; + dest[1] = s - m[1]; + dest[2] = s - m[2]; + dest[3] = s - m[3]; + dest[4] = s - m[4]; + dest[5] = s - m[5]; + dest[6] = s - m[6]; + dest[7] = s - m[7]; + dest[8] = s - m[8]; + dest[9] = s - m[9]; + dest[10] = s - m[10]; + dest[11] = s - m[11]; + dest[12] = s - m[12]; + dest[13] = s - m[13]; + dest[14] = s - m[14]; + dest[15] = s - m[15]; + + return dest; +}; + +/** + * @param a mat4 + * @param b mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, a otherwise + * @private + */ +var SceneJS_math_mulMat4 = function(a, b, dest) { + if (!dest) { + dest = a; + } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; + var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; + var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; + var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; + + var b00 = b[0], b01 = b[1], b02 = b[2], b03 = b[3]; + var b10 = b[4], b11 = b[5], b12 = b[6], b13 = b[7]; + var b20 = b[8], b21 = b[9], b22 = b[10], b23 = b[11]; + var b30 = b[12], b31 = b[13], b32 = b[14], b33 = b[15]; + + dest[0] = b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30; + dest[1] = b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31; + dest[2] = b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32; + dest[3] = b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33; + dest[4] = b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30; + dest[5] = b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31; + dest[6] = b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32; + dest[7] = b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33; + dest[8] = b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30; + dest[9] = b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31; + dest[10] = b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32; + dest[11] = b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33; + dest[12] = b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30; + dest[13] = b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31; + dest[14] = b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32; + dest[15] = b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33; + + return dest; +}; + +/** + * @param m mat4 + * @param s scalar + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, m otherwise + * @private + */ +var SceneJS_math_mulMat4s = function(m, s, dest) +{ + if (!dest) { + dest = m; + } + + dest[0] = m[0] * s; + dest[1] = m[1] * s; + dest[2] = m[2] * s; + dest[3] = m[3] * s; + dest[4] = m[4] * s; + dest[5] = m[5] * s; + dest[6] = m[6] * s; + dest[7] = m[7] * s; + dest[8] = m[8] * s; + dest[9] = m[9] * s; + dest[10] = m[10] * s; + dest[11] = m[11] * s; + dest[12] = m[12] * s; + dest[13] = m[13] * s; + dest[14] = m[14] * s; + dest[15] = m[15] * s; + + return dest; +}; + +/** + * @param m mat4 + * @param v vec4 + * @return {vec4} + * @private + */ +var SceneJS_math_mulMat4v4 = function(m, v) { + var v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + + return [ + m[0] * v0 + m[4] * v1 + m[8] * v2 + m[12] * v3, + m[1] * v0 + m[5] * v1 + m[9] * v2 + m[13] * v3, + m[2] * v0 + m[6] * v1 + m[10] * v2 + m[14] * v3, + m[3] * v0 + m[7] * v1 + m[11] * v2 + m[15] * v3 + ]; +}; + +/** + * @param mat mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, mat otherwise + * @private + */ +var SceneJS_math_transposeMat4 = function(mat, dest) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + var m4 = mat[4], m14 = mat[14], m8 = mat[8]; + var m13 = mat[13], m12 = mat[12], m9 = mat[9]; + if (!dest || mat == dest) { + var a01 = mat[1], a02 = mat[2], a03 = mat[3]; + var a12 = mat[6], a13 = mat[7]; + var a23 = mat[11]; + + mat[1] = m4; + mat[2] = m8; + mat[3] = m12; + mat[4] = a01; + mat[6] = m9; + mat[7] = m13; + mat[8] = a02; + mat[9] = a12; + mat[11] = m14; + mat[12] = a03; + mat[13] = a13; + mat[14] = a23; + return mat; + } + + dest[0] = mat[0]; + dest[1] = m4; + dest[2] = m8; + dest[3] = m12; + dest[4] = mat[1]; + dest[5] = mat[5]; + dest[6] = m9; + dest[7] = m13; + dest[8] = mat[2]; + dest[9] = mat[6]; + dest[10] = mat[10]; + dest[11] = m14; + dest[12] = mat[3]; + dest[13] = mat[7]; + dest[14] = mat[11]; + dest[15] = mat[15]; + return dest; +}; + +/** @private */ +var SceneJS_math_determinantMat4 = function(mat) { + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; + var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; + var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + return a30 * a21 * a12 * a03 - a20 * a31 * a12 * a03 - a30 * a11 * a22 * a03 + a10 * a31 * a22 * a03 + + a20 * a11 * a32 * a03 - a10 * a21 * a32 * a03 - a30 * a21 * a02 * a13 + a20 * a31 * a02 * a13 + + a30 * a01 * a22 * a13 - a00 * a31 * a22 * a13 - a20 * a01 * a32 * a13 + a00 * a21 * a32 * a13 + + a30 * a11 * a02 * a23 - a10 * a31 * a02 * a23 - a30 * a01 * a12 * a23 + a00 * a31 * a12 * a23 + + a10 * a01 * a32 * a23 - a00 * a11 * a32 * a23 - a20 * a11 * a02 * a33 + a10 * a21 * a02 * a33 + + a20 * a01 * a12 * a33 - a00 * a21 * a12 * a33 - a10 * a01 * a22 * a33 + a00 * a11 * a22 * a33; +}; + +/** + * @param mat mat4 + * @param dest mat4 - optional destination + * @return {mat4} dest if specified, mat otherwise + * @private + */ +var SceneJS_math_inverseMat4 = function(mat, dest) { + if (!dest) { + dest = mat; + } + + // Cache the matrix values (makes for huge speed increases!) + var a00 = mat[0], a01 = mat[1], a02 = mat[2], a03 = mat[3]; + var a10 = mat[4], a11 = mat[5], a12 = mat[6], a13 = mat[7]; + var a20 = mat[8], a21 = mat[9], a22 = mat[10], a23 = mat[11]; + var a30 = mat[12], a31 = mat[13], a32 = mat[14], a33 = mat[15]; + + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; + + // Calculate the determinant (inlined to avoid double-caching) + var invDet = 1 / (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06); + + dest[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; + dest[1] = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; + dest[2] = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; + dest[3] = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; + dest[4] = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; + dest[5] = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; + dest[6] = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; + dest[7] = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; + dest[8] = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; + dest[9] = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; + dest[10] = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; + dest[11] = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; + dest[12] = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; + dest[13] = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; + dest[14] = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; + dest[15] = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; + + return dest; +}; + +/** @private */ +var SceneJS_math_traceMat4 = function(m) { + return (m[0] + m[5] + m[10] + m[15]); +}; + +/** @private */ +var SceneJS_math_translationMat4v = function(v) { + var m = SceneJS_math_identityMat4(); + m[12] = v[0]; + m[13] = v[1]; + m[14] = v[2]; + return m; +}; + +/** @private */ +var SceneJS_math_translationMat4c = function(x, y, z) { + return SceneJS_math_translationMat4v([x,y,z]); +}; + +/** @private */ +var SceneJS_math_translationMat4s = function(s) { + return SceneJS_math_translationMat4c(s, s, s); +}; + +/** @private */ +var SceneJS_math_rotationMat4v = function(anglerad, axis) { + var ax = SceneJS_math_normalizeVec4([axis[0],axis[1],axis[2],0.0]); + var s = Math.sin(anglerad); + var c = Math.cos(anglerad); + var q = 1.0 - c; + + var x = ax[0]; + var y = ax[1]; + var z = ax[2]; + + var xy,yz,zx,xs,ys,zs; + + //xx = x * x; used once + //yy = y * y; used once + //zz = z * z; used once + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * s; + ys = y * s; + zs = z * s; + + var m = SceneJS_math_mat4(); + + m[0] = (q * x * x) + c; + m[1] = (q * xy) + zs; + m[2] = (q * zx) - ys; + m[3] = 0.0; + + m[4] = (q * xy) - zs; + m[5] = (q * y * y) + c; + m[6] = (q * yz) + xs; + m[7] = 0.0; + + m[8] = (q * zx) + ys; + m[9] = (q * yz) - xs; + m[10] = (q * z * z) + c; + m[11] = 0.0; + + m[12] = 0.0; + m[13] = 0.0; + m[14] = 0.0; + m[15] = 1.0; + + return m; +}; + +/** @private */ +var SceneJS_math_rotationMat4c = function(anglerad, x, y, z) { + return SceneJS_math_rotationMat4v(anglerad, [x,y,z]); +}; + +/** @private */ +var SceneJS_math_scalingMat4v = function(v) { + var m = SceneJS_math_identityMat4(); + m[0] = v[0]; + m[5] = v[1]; + m[10] = v[2]; + return m; +}; + +/** @private */ +var SceneJS_math_scalingMat4c = function(x, y, z) { + return SceneJS_math_scalingMat4v([x,y,z]); +}; + +/** @private */ +var SceneJS_math_scalingMat4s = function(s) { + return SceneJS_math_scalingMat4c(s, s, s); +}; + +/** + * Default lookat properties - eye at 0,0,1, looking at 0,0,0, up vector pointing up Y-axis + */ +var SceneJS_math_LOOKAT_OBJ = { + eye: {x: 0, y:0, z:10.0 }, + look: {x:0, y:0, z:0.0 }, + up: {x:0, y:1, z:0.0 } +}; + +/** + * Default lookat properties in array form - eye at 0,0,1, looking at 0,0,0, up vector pointing up Y-axis + */ +var SceneJS_math_LOOKAT_ARRAYS = { + eye: [0, 0, 10.0], + look: [0, 0, 0.0 ], + up: [0, 1, 0.0 ] +}; + +/** + * Default orthographic projection properties + */ +var SceneJS_math_ORTHO_OBJ = { + left: -1.0, + right: 1.0, + bottom: -1.0, + near: 0.1, + top: 1.0, + far: 5000.0 +}; + +/** + * @param pos vec3 position of the viewer + * @param target vec3 point the viewer is looking at + * @param up vec3 pointing "up" + * @param dest mat4 Optional, mat4 frustum matrix will be written into + * + * @return {mat4} dest if specified, a new mat4 otherwise + */ +var SceneJS_math_lookAtMat4v = function(pos, target, up, dest) { + if (!dest) { + dest = SceneJS_math_mat4(); + } + + var posx = pos[0], + posy = pos[1], + posz = pos[2], + upx = up[0], + upy = up[1], + upz = up[2], + targetx = target[0], + targety = target[1], + targetz = target[2]; + + if (posx == targetx && posy == targety && posz == targetz) { + return SceneJS_math_identityMat4(); + } + + var z0,z1,z2,x0,x1,x2,y0,y1,y2,len; + + //vec3.direction(eye, center, z); + z0 = posx - targetx; + z1 = posy - targety; + z2 = posz - targetz; + + // normalize (no check needed for 0 because of early return) + len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); + z0 *= len; + z1 *= len; + z2 *= len; + + //vec3.normalize(vec3.cross(up, z, x)); + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + //vec3.normalize(vec3.cross(z, x, y)); + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + + len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + dest[0] = x0; + dest[1] = y0; + dest[2] = z0; + dest[3] = 0; + dest[4] = x1; + dest[5] = y1; + dest[6] = z1; + dest[7] = 0; + dest[8] = x2; + dest[9] = y2; + dest[10] = z2; + dest[11] = 0; + dest[12] = -(x0 * posx + x1 * posy + x2 * posz); + dest[13] = -(y0 * posx + y1 * posy + y2 * posz); + dest[14] = -(z0 * posx + z1 * posy + z2 * posz); + dest[15] = 1; + + return dest; +}; + +/** @private */ +var SceneJS_math_lookAtMat4c = function(posx, posy, posz, targetx, targety, targetz, upx, upy, upz) { + return SceneJS_math_lookAtMat4v([posx,posy,posz], [targetx,targety,targetz], [upx,upy,upz]); +}; + +/** @private */ +var SceneJS_math_orthoMat4c = function(left, right, bottom, top, near, far, dest) { + if (!dest) { + dest = SceneJS_math_mat4(); + } + var rl = (right - left); + var tb = (top - bottom); + var fn = (far - near); + + dest[0] = 2.0 / rl; + dest[1] = 0.0; + dest[2] = 0.0; + dest[3] = 0.0; + + dest[4] = 0.0; + dest[5] = 2.0 / tb; + dest[6] = 0.0; + dest[7] = 0.0; + + dest[8] = 0.0; + dest[9] = 0.0; + dest[10] = -2.0 / fn; + dest[11] = 0.0; + + dest[12] = -(left + right) / rl; + dest[13] = -(top + bottom) / tb; + dest[14] = -(far + near) / fn; + dest[15] = 1.0; + + return dest; +}; + +/** @private */ +var SceneJS_math_frustumMat4v = function(fmin, fmax) { + var fmin4 = [fmin[0],fmin[1],fmin[2],0.0]; + var fmax4 = [fmax[0],fmax[1],fmax[2],0.0]; + var vsum = SceneJS_math_mat4(); + SceneJS_math_addVec4(fmax4, fmin4, vsum); + var vdif = SceneJS_math_mat4(); + SceneJS_math_subVec4(fmax4, fmin4, vdif); + var t = 2.0 * fmin4[2]; + + var m = SceneJS_math_mat4(); + var vdif0 = vdif[0], vdif1 = vdif[1], vdif2 = vdif[2]; + + m[0] = t / vdif0; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + + m[4] = 0.0; + m[5] = t / vdif1; + m[6] = 0.0; + m[7] = 0.0; + + m[8] = vsum[0] / vdif0; + m[9] = vsum[1] / vdif1; + m[10] = -vsum[2] / vdif2; + m[11] = -1.0; + + m[12] = 0.0; + m[13] = 0.0; + m[14] = -t * fmax4[2] / vdif2; + m[15] = 0.0; + + return m; +}; + +/** @private */ +var SceneJS_math_frustumMatrix4 = function(left, right, bottom, top, near, far, dest) { + if (!dest) { + dest = SceneJS_math_mat4(); + } + var rl = (right - left); + var tb = (top - bottom); + var fn = (far - near); + dest[0] = (near * 2) / rl; + dest[1] = 0; + dest[2] = 0; + dest[3] = 0; + dest[4] = 0; + dest[5] = (near * 2) / tb; + dest[6] = 0; + dest[7] = 0; + dest[8] = (right + left) / rl; + dest[9] = (top + bottom) / tb; + dest[10] = -(far + near) / fn; + dest[11] = -1; + dest[12] = 0; + dest[13] = 0; + dest[14] = -(far * near * 2) / fn; + dest[15] = 0; + return dest; +}; + + +/** @private */ +var SceneJS_math_perspectiveMatrix4 = function(fovyrad, aspectratio, znear, zfar) { + var pmin = []; + var pmax = []; + + pmin[2] = znear; + pmax[2] = zfar; + + pmax[1] = pmin[2] * Math.tan(fovyrad / 2.0); + pmin[1] = -pmax[1]; + + pmax[0] = pmax[1] * aspectratio; + pmin[0] = -pmax[0]; + + return SceneJS_math_frustumMat4v(pmin, pmax); +}; + +/** @private */ +var SceneJS_math_transformPoint3 = function(m, p) { + var p0 = p[0], p1 = p[1], p2 = p[2]; + return [ + (m[0] * p0) + (m[4] * p1) + (m[8] * p2) + m[12], + (m[1] * p0) + (m[5] * p1) + (m[9] * p2) + m[13], + (m[2] * p0) + (m[6] * p1) + (m[10] * p2) + m[14], + (m[3] * p0) + (m[7] * p1) + (m[11] * p2) + m[15] + ]; +}; + + +/** @private */ +var SceneJS_math_transformPoints3 = function(m, points) { + var result = new Array(points.length); + var len = points.length; + var p0, p1, p2; + var pi; + + // cache values + var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3]; + var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7]; + var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11]; + var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15]; + + for (var i = 0; i < len; ++i) { + // cache values + pi = points[i]; + p0 = pi[0]; + p1 = pi[1]; + p2 = pi[2]; + + result[i] = [ + (m0 * p0) + (m4 * p1) + (m8 * p2) + m12, + (m1 * p0) + (m5 * p1) + (m9 * p2) + m13, + (m2 * p0) + (m6 * p1) + (m10 * p2) + m14, + (m3 * p0) + (m7 * p1) + (m11 * p2) + m15 + ]; + } + + return result; +}; + +/** @private */ +var SceneJS_math_transformVector3 = function(m, v) { + var v0 = v[0], v1 = v[1], v2 = v[2]; + return [ + (m[0] * v0) + (m[4] * v1) + (m[8] * v2), + (m[1] * v0) + (m[5] * v1) + (m[9] * v2), + (m[2] * v0) + (m[6] * v1) + (m[10] * v2) + ]; +}; + +var SceneJS_math_transformVector4 = function(m, v) { + var v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + return [ + m[ 0] * v0 + m[ 4] * v1 + m[ 8] * v2 + m[12] * v3, + m[ 1] * v0 + m[ 5] * v1 + m[ 9] * v2 + m[13] * v3, + m[ 2] * v0 + m[ 6] * v1 + m[10] * v2 + m[14] * v3, + m[ 3] * v0 + m[ 7] * v1 + m[11] * v2 + m[15] * v3 + ]; +}; + +/** @private */ +var SceneJS_math_projectVec4 = function(v) { + var f = 1.0 / v[3]; + return [v[0] * f, v[1] * f, v[2] * f, 1.0]; +}; + + +/** @private */ +var SceneJS_math_Plane3 = function (normal, offset, normalize) { + this.normal = [0.0, 0.0, 1.0 ]; + + this.offset = 0.0; + if (normal && offset) { + var normal0 = normal[0], normal1 = normal[1], normal2 = normal[2]; + this.offset = offset; + + if (normalize) { + var s = Math.sqrt( + normal0 * normal0 + + normal1 * normal1 + + normal2 * normal2 + ); + if (s > 0.0) { + s = 1.0 / s; + this.normal[0] = normal0 * s; + this.normal[1] = normal1 * s; + this.normal[2] = normal2 * s; + this.offset *= s; + } + } + } +}; + +/** @private */ +var SceneJS_math_MAX_DOUBLE = Number.POSITIVE_INFINITY; +/** @private */ +var SceneJS_math_MIN_DOUBLE = Number.NEGATIVE_INFINITY; + +/** @private + * + */ +var SceneJS_math_Box3 = function(min, max) { + this.min = min || [ SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE ]; + this.max = max || [ SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE ]; + + /** @private */ + this.init = function(min, max) { + this.min[0] = min[0]; + this.min[1] = min[1]; + this.min[2] = min[2]; + this.max[0] = max[0]; + this.max[1] = max[1]; + this.max[2] = max[2]; + return this; + }; + + /** @private */ + this.fromPoints = function(points) { + var pointsLength = points.length; + + for (var i = 0; i < pointsLength; ++i) { + var points_i3 = points[i][3]; + var pDiv0 = points[i][0] / points_i3; + var pDiv1 = points[i][1] / points_i3; + var pDiv2 = points[i][2] / points_i3; + + if (pDiv0 < this.min[0]) { + this.min[0] = pDiv0; + } + if (pDiv1 < this.min[1]) { + this.min[1] = pDiv1; + } + if (pDiv2 < this.min[2]) { + this.min[2] = pDiv2; + } + + if (pDiv0 > this.max[0]) { + this.max[0] = pDiv0; + } + if (pDiv1 > this.max[1]) { + this.max[1] = pDiv1; + } + if (pDiv2 > this.max[2]) { + this.max[2] = pDiv2; + } + } + return this; + }; + + /** @private */ + this.isEmpty = function() { + return ( + (this.min[0] >= this.max[0]) && + (this.min[1] >= this.max[1]) && + (this.min[2] >= this.max[2]) + ); + }; + + /** @private */ + this.getCenter = function() { + return [ + (this.max[0] + this.min[0]) / 2.0, + (this.max[1] + this.min[1]) / 2.0, + (this.max[2] + this.min[2]) / 2.0 + ]; + }; + + /** @private */ + this.getSize = function() { + return [ + (this.max[0] - this.min[0]), + (this.max[1] - this.min[1]), + (this.max[2] - this.min[2]) + ]; + }; + + /** @private */ + this.getFacesAreas = function() { + var s = this.size; + return [ + (s[1] * s[2]), + (s[0] * s[2]), + (s[0] * s[1]) + ]; + }; + + /** @private */ + this.getSurfaceArea = function() { + var a = this.getFacesAreas(); + return ((a[0] + a[1] + a[2]) * 2.0); + }; + + /** @private */ + this.getVolume = function() { + var s = this.size; + return (s[0] * s[1] * s[2]); + }; + + /** @private */ + this.getOffset = function(half_delta) { + this.min[0] -= half_delta; + this.min[1] -= half_delta; + this.min[2] -= half_delta; + this.max[0] += half_delta; + this.max[1] += half_delta; + this.max[2] += half_delta; + return this; + }; +}; + +/** @private + * + * @param min + * @param max + */ +var SceneJS_math_AxisBox3 = function(min, max) { + var min0 = min[0], min1 = min[1], min2 = min[2]; + var max0 = max[0], max1 = max[1], max2 = max[2]; + + this.verts = [ + [min0, min1, min2], + [max0, min1, min2], + [max0, max1, min2], + [min0, max1, min2], + + [min0, min1, max2], + [max0, min1, max2], + [max0, max1, max2], + [min0, max1, max2] + ]; + + /** @private */ + this.toBox3 = function() { + var box = new SceneJS_math_Box3(); + for (var i = 0; i < 8; ++i) { + var v = this.verts[i]; + for (var j = 0; j < 3; ++j) { + if (v[j] < box.min[j]) { + box.min[j] = v[j]; + } + if (v[j] > box.max[j]) { + box.max[j] = v[j]; + } + } + } + }; +}; + +/** @private + * + * @param center + * @param radius + */ +var SceneJS_math_Sphere3 = function(center, radius) { + this.center = [center[0], center[1], center[2] ]; + this.radius = radius; + + /** @private */ + this.isEmpty = function() { + return (this.radius === 0.0); + }; + + /** @private */ + this.surfaceArea = function() { + return (4.0 * Math.PI * this.radius * this.radius); + }; + + /** @private */ + this.getVolume = function() { + var thisRadius = this.radius; + return ((4.0 / 3.0) * Math.PI * thisRadius * thisRadius * thisRadius); + }; +}; + +/** Creates billboard matrix from given view matrix + * @private + */ +var SceneJS_math_billboardMat = function(viewMatrix) { + var rotVec = [ + SceneJS_math_getColMat4(viewMatrix, 0), + SceneJS_math_getColMat4(viewMatrix, 1), + SceneJS_math_getColMat4(viewMatrix, 2) + ]; + + var scaleVec = [ + SceneJS_math_lenVec4(rotVec[0]), + SceneJS_math_lenVec4(rotVec[1]), + SceneJS_math_lenVec4(rotVec[2]) + ]; + + var scaleVecRcp = SceneJS_math_mat4(); + SceneJS_math_rcpVec3(scaleVec, scaleVecRcp); + var sMat = SceneJS_math_scalingMat4v(scaleVec); + //var sMatInv = SceneJS_math_scalingMat4v(scaleVecRcp); + + SceneJS_math_mulVec4Scalar(rotVec[0], scaleVecRcp[0]); + SceneJS_math_mulVec4Scalar(rotVec[1], scaleVecRcp[1]); + SceneJS_math_mulVec4Scalar(rotVec[2], scaleVecRcp[2]); + + var rotMatInverse = SceneJS_math_identityMat4(); + + SceneJS_math_setRowMat4(rotMatInverse, 0, rotVec[0]); + SceneJS_math_setRowMat4(rotMatInverse, 1, rotVec[1]); + SceneJS_math_setRowMat4(rotMatInverse, 2, rotVec[2]); + + //return rotMatInverse; + //return SceneJS_math_mulMat4(sMatInv, SceneJS_math_mulMat4(rotMatInverse, sMat)); + return SceneJS_math_mulMat4(rotMatInverse, sMat); + // return SceneJS_math_mulMat4(sMat, SceneJS_math_mulMat4(rotMatInverse, sMat)); + //return SceneJS_math_mulMat4(sMatInv, SceneJS_math_mulMat4(rotMatInverse, sMat)); +}; + +/** @private */ +var SceneJS_math_FrustumPlane = function(nx, ny, nz, offset) { + var s = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz); + this.normal = [nx * s, ny * s, nz * s]; + this.offset = offset * s; + this.testVertex = [ + (this.normal[0] >= 0.0) ? (1) : (0), + (this.normal[1] >= 0.0) ? (1) : (0), + (this.normal[2] >= 0.0) ? (1) : (0)]; +}; + +/** @private */ +var SceneJS_math_OUTSIDE_FRUSTUM = 3; +/** @private */ +var SceneJS_math_INTERSECT_FRUSTUM = 4; +/** @private */ +var SceneJS_math_INSIDE_FRUSTUM = 5; + +/** @private */ +var SceneJS_math_Frustum = function(viewMatrix, projectionMatrix, viewport) { + var m = SceneJS_math_mat4(); + SceneJS_math_mulMat4(projectionMatrix, viewMatrix, m); + + // cache m indexes + var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3]; + var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7]; + var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11]; + var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15]; + + //var q = [ m[3], m[7], m[11] ]; just reuse m indexes instead of making new var + var planes = [ + new SceneJS_math_FrustumPlane(m3 - m0, m7 - m4, m11 - m8, m15 - m12), + new SceneJS_math_FrustumPlane(m3 + m0, m7 + m4, m11 + m8, m15 + m12), + new SceneJS_math_FrustumPlane(m3 - m1, m7 - m5, m11 - m9, m15 - m13), + new SceneJS_math_FrustumPlane(m3 + m1, m7 + m5, m11 + m9, m15 + m13), + new SceneJS_math_FrustumPlane(m3 - m2, m7 - m6, m11 - m10, m15 - m14), + new SceneJS_math_FrustumPlane(m3 + m2, m7 + m6, m11 + m10, m15 + m14) + ]; + + /* Resources for LOD + */ + var rotVec = [ + SceneJS_math_getColMat4(viewMatrix, 0), + SceneJS_math_getColMat4(viewMatrix, 1), + SceneJS_math_getColMat4(viewMatrix, 2) + ]; + + var scaleVec = [ + SceneJS_math_lenVec4(rotVec[0]), + SceneJS_math_lenVec4(rotVec[1]), + SceneJS_math_lenVec4(rotVec[2]) + ]; + + var scaleVecRcp = SceneJS_math_rcpVec3(scaleVec); + var sMat = SceneJS_math_scalingMat4v(scaleVec); + var sMatInv = SceneJS_math_scalingMat4v(scaleVecRcp); + + SceneJS_math_mulVec4Scalar(rotVec[0], scaleVecRcp[0]); + SceneJS_math_mulVec4Scalar(rotVec[1], scaleVecRcp[1]); + SceneJS_math_mulVec4Scalar(rotVec[2], scaleVecRcp[2]); + + var rotMatInverse = SceneJS_math_identityMat4(); + + SceneJS_math_setRowMat4(rotMatInverse, 0, rotVec[0]); + SceneJS_math_setRowMat4(rotMatInverse, 1, rotVec[1]); + SceneJS_math_setRowMat4(rotMatInverse, 2, rotVec[2]); + + if (!this.matrix) { + this.matrix = SceneJS_math_mat4(); + } + SceneJS_math_mulMat4(projectionMatrix, viewMatrix, this.matrix); + if (!this.billboardMatrix) { + this.billboardMatrix = SceneJS_math_mat4(); + } + SceneJS_math_mulMat4(sMatInv, SceneJS_math_mulMat4(rotMatInverse, sMat), this.billboardMatrix); + this.viewport = viewport.slice(0, 4); + + /** @private */ + this.textAxisBoxIntersection = function(box) { + var ret = SceneJS_math_INSIDE_FRUSTUM; + var bminmax = [ box.min, box.max ]; + var plane = null; + + for (var i = 0; i < 6; ++i) { + plane = planes[i]; + if (((plane.normal[0] * bminmax[plane.testVertex[0]][0]) + + (plane.normal[1] * bminmax[plane.testVertex[1]][1]) + + (plane.normal[2] * bminmax[plane.testVertex[2]][2]) + + (plane.offset)) < 0.0) { + return SceneJS_math_OUTSIDE_FRUSTUM; + } + if (((plane.normal[0] * bminmax[1 - plane.testVertex[0]][0]) + + (plane.normal[1] * bminmax[1 - plane.testVertex[1]][1]) + + (plane.normal[2] * bminmax[1 - plane.testVertex[2]][2]) + + (plane.offset)) < 0.0) { + ret = SceneJS_math_INTERSECT_FRUSTUM; + } + } + return ret; + }; + + /** @private */ + this.getProjectedSize = function(box) { + var diagVec = SceneJS_math_mat4(); + SceneJS_math_subVec3(box.max, box.min, diagVec); + + var diagSize = SceneJS_math_lenVec3(diagVec); + + var size = Math.abs(diagSize); + + var p0 = [ + (box.min[0] + box.max[0]) * 0.5, + (box.min[1] + box.max[1]) * 0.5, + (box.min[2] + box.max[2]) * 0.5, + 0.0]; + + var halfSize = size * 0.5; + var p1 = [ -halfSize, 0.0, 0.0, 1.0 ]; + var p2 = [ halfSize, 0.0, 0.0, 1.0 ]; + + p1 = SceneJS_math_mulMat4v4(this.billboardMatrix, p1); + p1 = SceneJS_math_addVec4(p1, p0); + p1 = SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix, p1)); + + p2 = SceneJS_math_mulMat4v4(this.billboardMatrix, p2); + p2 = SceneJS_math_addVec4(p2, p0); + p2 = SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix, p2)); + + return viewport[2] * Math.abs(p2[0] - p1[0]); + }; + + + this.getProjectedState = function(modelCoords) { + var viewCoords = SceneJS_math_transformPoints3(this.matrix, modelCoords); + + //var canvasBox = { + // min: [10000000, 10000000 ], + // max: [-10000000, -10000000] + //}; + // separate variables instead of indexing an array + var canvasBoxMin0 = 10000000, canvasBoxMin1 = 10000000; + var canvasBoxMax0 = -10000000, canvasBoxMax1 = -10000000; + + var v, x, y; + + var arrLen = viewCoords.length; + for (var i = 0; i < arrLen; ++i) { + v = SceneJS_math_projectVec4(viewCoords[i]); + x = v[0]; + y = v[1]; + + if (x < -0.5) { + x = -0.5; + } + + if (y < -0.5) { + y = -0.5; + } + + if (x > 0.5) { + x = 0.5; + } + + if (y > 0.5) { + y = 0.5; + } + + + if (x < canvasBoxMin0) { + canvasBoxMin0 = x; + } + if (y < canvasBoxMin1) { + canvasBoxMin1 = y; + } + + if (x > canvasBoxMax0) { + canvasBoxMax0 = x; + } + if (y > canvasBoxMax1) { + canvasBoxMax1 = y; + } + } + + canvasBoxMin0 += 0.5; + canvasBoxMin1 += 0.5; + canvasBoxMax0 += 0.5; + canvasBoxMax1 += 0.5; + + // cache viewport indexes + var viewport2 = viewport[2], viewport3 = viewport[3]; + + canvasBoxMin0 = (canvasBoxMin0 * (viewport2 + 15)); + canvasBoxMin1 = (canvasBoxMin1 * (viewport3 + 15)); + canvasBoxMax0 = (canvasBoxMax0 * (viewport2 + 15)); + canvasBoxMax1 = (canvasBoxMax1 * (viewport3 + 15)); + + var diagCanvasBoxVec = SceneJS_math_mat4(); + SceneJS_math_subVec2([canvasBoxMax0, canvasBoxMax1], + [canvasBoxMin0, canvasBoxMin1], + diagCanvasBoxVec); + var diagCanvasBoxSize = SceneJS_math_lenVec2(diagCanvasBoxVec); + + if (canvasBoxMin0 < 0) { + canvasBoxMin0 = 0; + } + if (canvasBoxMax0 > viewport2) { + canvasBoxMax0 = viewport2; + } + + if (canvasBoxMin1 < 0) { + canvasBoxMin1 = 0; + } + if (canvasBoxMax1 > viewport3) { + canvasBoxMax1 = viewport3; + } + return { + canvasBox: { + min: [canvasBoxMin0, canvasBoxMin1 ], + max: [canvasBoxMax0, canvasBoxMax1 ] + }, + canvasSize: diagCanvasBoxSize + }; + }; +}; + +var SceneJS_math_identityQuaternion = function() { + return [ 0.0, 0.0, 0.0, 1.0 ]; +}; + +var SceneJS_math_angleAxisQuaternion = function(x, y, z, degrees) { + var angleRad = (degrees / 180.0) * Math.PI; + var halfAngle = angleRad / 2.0; + var fsin = Math.sin(halfAngle); + return [ + fsin * x, + fsin * y, + fsin * z, + Math.cos(halfAngle) + ]; +}; + +var SceneJS_math_mulQuaternions = function(p, q) { + var p0 = p[0], p1 = p[1], p2 = p[2], p3 = p[3]; + var q0 = q[0], q1 = q[1], q2 = q[2], q3 = q[3]; + return [ + p3 * q0 + p0 * q3 + p1 * q2 - p2 * q1, + p3 * q1 + p1 * q3 + p2 * q0 - p0 * q2, + p3 * q2 + p2 * q3 + p0 * q1 - p1 * q0, + p3 * q3 - p0 * q0 - p1 * q1 - p2 * q2 + ]; +}; + +var SceneJS_math_newMat4FromQuaternion = function(q) { + var q0 = q[0], q1 = q[1], q2 = q[2], q3 = q[3]; + var tx = 2.0 * q0; + var ty = 2.0 * q1; + var tz = 2.0 * q2; + var twx = tx * q3; + var twy = ty * q3; + var twz = tz * q3; + var txx = tx * q0; + var txy = ty * q0; + var txz = tz * q0; + var tyy = ty * q1; + var tyz = tz * q1; + var tzz = tz * q2; + var m = SceneJS_math_identityMat4(); + SceneJS_math_setCellMat4(m, 0, 0, 1.0 - (tyy + tzz)); + SceneJS_math_setCellMat4(m, 0, 1, txy - twz); + SceneJS_math_setCellMat4(m, 0, 2, txz + twy); + SceneJS_math_setCellMat4(m, 1, 0, txy + twz); + SceneJS_math_setCellMat4(m, 1, 1, 1.0 - (txx + tzz)); + SceneJS_math_setCellMat4(m, 1, 2, tyz - twx); + SceneJS_math_setCellMat4(m, 2, 0, txz - twy); + SceneJS_math_setCellMat4(m, 2, 1, tyz + twx); + SceneJS_math_setCellMat4(m, 2, 2, 1.0 - (txx + tyy)); + return m; +}; + + +//var SceneJS_math_slerp(t, q1, q2) { +// var result = SceneJS_math_identityQuaternion(); +// var cosHalfAngle = q1[3] * q2[3] + q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2]; +// if (Math.abs(cosHalfAngle) >= 1) { +// return [ q1[0],q1[1], q1[2], q1[3] ]; +// } else { +// var halfAngle = Math.acos(cosHalfAngle); +// var sinHalfAngle = Math.sqrt(1 - cosHalfAngle * cosHalfAngle); +// if (Math.abs(sinHalfAngle) < 0.001) { +// return [ +// q1[0] * 0.5 + q2[0] * 0.5, +// q1[1] * 0.5 + q2[1] * 0.5, +// q1[2] * 0.5 + q2[2] * 0.5, +// q1[3] * 0.5 + q2[3] * 0.5 +// ]; +// } else { +// var a = Math.sin((1 - t) * halfAngle) / sinHalfAngle; +// var b = Math.sin(t * halfAngle) / sinHalfAngle; +// return [ +// q1[0] * a + q2[0] * b, +// q1[1] * a + q2[1] * b, +// q1[2] * a + q2[2] * b, +// q1[3] * a + q2[3] * b +// ]; +// } +// } +//} + +var SceneJS_math_slerp = function(t, q1, q2) { + //var result = SceneJS_math_identityQuaternion(); + var q13 = q1[3] * 0.0174532925; + var q23 = q2[3] * 0.0174532925; + var cosHalfAngle = q13 * q23 + q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2]; + if (Math.abs(cosHalfAngle) >= 1) { + return [ q1[0],q1[1], q1[2], q1[3] ]; + } else { + var halfAngle = Math.acos(cosHalfAngle); + var sinHalfAngle = Math.sqrt(1 - cosHalfAngle * cosHalfAngle); + if (Math.abs(sinHalfAngle) < 0.001) { + return [ + q1[0] * 0.5 + q2[0] * 0.5, + q1[1] * 0.5 + q2[1] * 0.5, + q1[2] * 0.5 + q2[2] * 0.5, + q1[3] * 0.5 + q2[3] * 0.5 + ]; + } else { + var a = Math.sin((1 - t) * halfAngle) / sinHalfAngle; + var b = Math.sin(t * halfAngle) / sinHalfAngle; + return [ + q1[0] * a + q2[0] * b, + q1[1] * a + q2[1] * b, + q1[2] * a + q2[2] * b, + (q13 * a + q23 * b) * 57.295779579 + ]; + } + } +}; + +var SceneJS_math_normalizeQuaternion = function(q) { + var len = SceneJS_math_lenVec4([q[0], q[1], q[2], q[3]]); + return [ q[0] / len, q[1] / len, q[2] / len, q[3] / len ]; +}; + +var SceneJS_math_conjugateQuaternion = function(q) { + return[-q[0],-q[1],-q[2],q[3]]; +}; + +var SceneJS_math_angleAxisFromQuaternion = function(q) { + q = SceneJS_math_normalizeQuaternion(q); + var q3 = q[3]; + var angle = 2 * Math.acos(q3); + var s = Math.sqrt(1 - q3 * q3); + if (s < 0.001) { // test to avoid divide by zero, s is always positive due to sqrt + return { + x : q[0], + y : q[1], + z : q[2], + angle: angle * 57.295779579 + }; + } else { + return { + x : q[0] / s, + y : q[1] / s, + z : q[2] / s, + angle: angle * 57.295779579 + }; + } +}; +;/** + * Backend that tracks statistics on loading states of nodes during scene traversal. + * + * This supports the "loading-status" events that we can listen for on scene nodes. + * + * When a node with that listener is pre-visited, it will call getStatus on this module to + * save a copy of the status. Then when it is post-visited, it will call diffStatus on this + * module to find the status for its sub-nodes, which it then reports through the "loading-status" event. + * + * @private + */ +var SceneJS_sceneStatusModule = new (function () { + + // Public activity summary + this.sceneStatus = {}; + + // IDs of all tasks + var taskIds = new SceneJS_Map(); + var tasks = {}; + + var sceneStates = {}; + + var self = this; + + SceneJS_events.addListener( + SceneJS_events.SCENE_DESTROYED, + function (params) { + var sceneId = params.engine.id; + delete self.sceneStatus[sceneId]; + delete sceneStates[sceneId]; + }); + + /** Notifies that a node has begun loading some data + */ + this.taskStarted = function (node, description) { + + var popups = SceneJS_configsModule.configs.statusPopups !== false; + + var scene = node.getScene(); + var sceneId = scene.getId(); + var nodeId = node.getId(); + var canvas = scene.getCanvas(); + + var taskId = taskIds.addItem(); + + // Update public info + var status = this.sceneStatus[sceneId]; + if (!status) { + status = this.sceneStatus[sceneId] = { + numTasks: 0 + }; + } + status.numTasks++; + + // Track node + var sceneState = sceneStates[sceneId]; + if (!sceneState) { + sceneState = sceneStates[sceneId] = { + sceneId: sceneId, + nodeStates: {}, + scene: scene, + popupContainer: popups ? createPopupContainer(canvas) : null, + descCounts: {} + }; + } + var descCount = sceneState.descCounts[description]; + if (descCount == undefined) { + descCount = sceneState.descCounts[description] = 0; + } + sceneState.descCounts[description]++; + var nodeState = sceneState.nodeStates[nodeId]; + if (!nodeState) { + nodeState = sceneState.nodeStates[nodeId] = { + nodeId: nodeId, + numTasks: 0, + tasks: {} + }; + } + description = description + " " + sceneState.descCounts[description] + "..."; + nodeState.numTasks++; + var task = { + sceneState: sceneState, + nodeState: nodeState, + description: description, + element: popups ? createPopup(sceneState.popupContainer, description) : null + }; + nodeState.tasks[taskId] = task; + tasks[taskId] = task; + return taskId; + }; + + function createPopupContainer(canvas) { + var body = document.getElementsByTagName("body")[0]; + var div = document.createElement('div'); + var style = div.style; + style.position = "absolute"; + style.width = "200px"; + style.right = "10px"; + style.top = "0"; + style.padding = "10px"; + style["z-index"] = "10000"; + body.appendChild(div); + return div; + } + + function createPopup(popupContainer, description) { + var div = document.createElement('div'); + var style = div.style; + style["font-family"] = "Helvetica"; + style["font-size"] = "14px"; + style.padding = "5px"; + style.margin = "4px"; + style["padding-left"] = "12px"; + style["border"] = "1px solid #000055"; + style.color = "black"; + style.background = "#AAAAAA"; + style.opacity = "0.8"; + style["border-radius"] = "3px"; + style["-moz-border-radius"] = "3px"; + style["box-shadow"] = "3px 3px 3px #444444"; + div.innerHTML = description; + popupContainer.appendChild(div); + return div; + } + + /** Notifies that a load has finished loading some data + */ + this.taskFinished = function (taskId) { + if (taskId == -1 || taskId == null) { + return null; + } + var task = tasks[taskId]; + if (!task) { + return null; + } + var sceneState = task.sceneState; + this.sceneStatus[sceneState.sceneId].numTasks--; + if (task.element) { + dismissPopup(task.element); + } + var nodeState = task.nodeState; + if (--nodeState.numTasks < 0) { + nodeState.numTasks = 0; + } + delete nodeState.tasks[taskId]; + if (nodeState.numTasks == 0) { + delete sceneState.nodeStates[nodeState.nodeId]; + } + return null; + }; + + function dismissPopup(element) { + element.style.background = "#AAFFAA"; + var opacity = 0.8; + var interval = setInterval(function () { + if (opacity <= 0) { + element.parentNode.removeChild(element); + clearInterval(interval); + } else { + element.style.opacity = opacity; + opacity -= 0.1; + } + }, 100); + } + + /** Notifies that a task has failed + */ + this.taskFailed = function (taskId) { + if (taskId == -1 || taskId == null) { + return null; + } + var task = tasks[taskId]; + if (!task) { + return null; + } + var popups = !!SceneJS_configsModule.configs.statusPopups; + var sceneState = task.sceneState; + this.sceneStatus[sceneState.sceneId].numTasks--; + if (popups) { + failPopup(task.element); + } + var nodeState = task.nodeState; + nodeState.numTasks--; + delete nodeState.tasks[taskId]; + if (nodeState.numTasks == 0) { + delete task.sceneState.nodeStates[nodeState.nodeId]; + } + return null; + }; + + function failPopup(element) { + element.style.background = "#FFAAAA"; + } +})();;SceneJS._webgl = {}; +;/** Buffer for vertices and indices + * + * @private + * @param gl WebGL gl + * @param type Eg. ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER + * @param values WebGL array wrapper + * @param numItems Count of items in array wrapper + * @param itemSize Size of each item + * @param usage Eg. STATIC_DRAW + */ + +SceneJS._webgl.ArrayBuffer = function (gl, type, values, numItems, itemSize, usage) { + + /** + * True when this buffer is allocated and ready to go + * @type {boolean} + */ + this.allocated = false; + + this.gl = gl; + this.type = type; + this.numItems = numItems; + this.itemSize = itemSize; + this.usage = usage; + + this._allocate(values, numItems); +}; + +/** + * Allocates this buffer + * + * @param values + * @param numItems + * @private + */ +SceneJS._webgl.ArrayBuffer.prototype._allocate = function (values, numItems) { + this.allocated = false; + this.handle = this.gl.createBuffer(); + if (!this.handle) { + throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM, "Failed to allocate WebGL ArrayBuffer"); + } + if (this.handle) { + this.gl.bindBuffer(this.type, this.handle); + this.gl.bufferData(this.type, values, this.usage); + this.gl.bindBuffer(this.type, null); + this.numItems = numItems; + this.length = values.length; + this.allocated = true; + } +}; + +/** + * Updates values within this buffer, reallocating if needed + * + * @param data + * @param offset + */ +SceneJS._webgl.ArrayBuffer.prototype.setData = function (data, offset) { + if (!this.allocated) { + return; + } + if (data.length > this.length) { + // Needs reallocation + this.destroy(); + this._allocate(data, data.length); + } else { + // No reallocation needed + if (offset || offset === 0) { + this.gl.bufferSubData(this.type, offset, data); + } else { + this.gl.bufferData(this.type, data); + } + } +}; + +/** + * Unbinds this buffer on WebGL + */ +SceneJS._webgl.ArrayBuffer.prototype.unbind = function () { + if (!this.allocated) { + return; + } + this.gl.bindBuffer(this.type, null); +}; + +/** + * Destroys this buffer + */ +SceneJS._webgl.ArrayBuffer.prototype.destroy = function () { + if (!this.allocated) { + return; + } + this.gl.deleteBuffer(this.handle); + this.handle = null; + this.allocated = false; +}; + + +SceneJS._webgl.ArrayBuffer.prototype.bind = function () { + if (!this.allocated) { + return; + } + this.gl.bindBuffer(this.type, this.handle); +}; + + +; +/** An attribute within a shader + */ +SceneJS._webgl.Attribute = function (gl, program, name, type, size, location) { + + this.gl = gl; + this.location = location; + + this.bindFloatArrayBuffer = function (buffer) { + if (buffer) { + buffer.bind(); + gl.enableVertexAttribArray(location); + gl.vertexAttribPointer(location, buffer.itemSize, gl.FLOAT, false, 0, 0); // Vertices are not homogeneous - no w-element + } + }; +}; + +SceneJS._webgl.Attribute.prototype.bindInterleavedFloatArrayBuffer = function (components, stride, byteOffset) { + this.gl.enableVertexAttribArray(this.location); + this.gl.vertexAttribPointer(this.location, components, this.gl.FLOAT, false, stride, byteOffset); // Vertices are not homogeneous - no w-element +}; +; +/** Maps SceneJS node parameter names to WebGL enum names + * @private + */ +SceneJS._webgl.enumMap = { + funcAdd: "FUNC_ADD", + funcSubtract: "FUNC_SUBTRACT", + funcReverseSubtract: "FUNC_REVERSE_SUBTRACT", + zero: "ZERO", + one: "ONE", + srcColor: "SRC_COLOR", + oneMinusSrcColor: "ONE_MINUS_SRC_COLOR", + dstColor: "DST_COLOR", + oneMinusDstColor: "ONE_MINUS_DST_COLOR", + srcAlpha: "SRC_ALPHA", + oneMinusSrcAlpha: "ONE_MINUS_SRC_ALPHA", + dstAlpha: "DST_ALPHA", + oneMinusDstAlpha: "ONE_MINUS_DST_ALPHA", + contantColor: "CONSTANT_COLOR", + oneMinusConstantColor: "ONE_MINUS_CONSTANT_COLOR", + constantAlpha: "CONSTANT_ALPHA", + oneMinusConstantAlpha: "ONE_MINUS_CONSTANT_ALPHA", + srcAlphaSaturate: "SRC_ALPHA_SATURATE", + front: "FRONT", + back: "BACK", + frontAndBack: "FRONT_AND_BACK", + never: "NEVER", + less: "LESS", + equal: "EQUAL", + lequal: "LEQUAL", + greater: "GREATER", + notequal: "NOTEQUAL", + gequal: "GEQUAL", + always: "ALWAYS", + cw: "CW", + ccw: "CCW", + linear: "LINEAR", + nearest: "NEAREST", + linearMipMapNearest: "LINEAR_MIPMAP_NEAREST", + nearestMipMapNearest: "NEAREST_MIPMAP_NEAREST", + nearestMipMapLinear: "NEAREST_MIPMAP_LINEAR", + linearMipMapLinear: "LINEAR_MIPMAP_LINEAR", + repeat: "REPEAT", + clampToEdge: "CLAMP_TO_EDGE", + mirroredRepeat: "MIRRORED_REPEAT", + alpha: "ALPHA", + rgb: "RGB", + rgba: "RGBA", + luminance: "LUMINANCE", + luminanceAlpha: "LUMINANCE_ALPHA", + textureBinding2D: "TEXTURE_BINDING_2D", + textureBindingCubeMap: "TEXTURE_BINDING_CUBE_MAP", + compareRToTexture: "COMPARE_R_TO_TEXTURE", // Hardware Shadowing Z-depth, + unsignedByte: "UNSIGNED_BYTE" +}; + +;SceneJS._webgl.RenderBuffer = function (cfg) { + + /** + * True as soon as this buffer is allocated and ready to go + */ + this.allocated = false; + + /** + * The canvas, to synch buffer size with when its dimensions change + */ + this.canvas = cfg.canvas; + + /** + * WebGL context + */ + this.gl = cfg.canvas.gl; + + /** + * Buffer resources, set up in #_touch + */ + this.buf = null; + + /** + * True while this buffer is bound + * @type {boolean} + */ + this.bound = false; +}; + +/** + * Called after WebGL context is restored. + */ +SceneJS._webgl.RenderBuffer.prototype.webglRestored = function (_gl) { + this.gl = _gl; + this.buf = null; + this.allocated = false; + this.bound = false; +}; + +/** + * Binds this buffer + */ +SceneJS._webgl.RenderBuffer.prototype.bind = function () { + this._touch(); + if (this.bound) { + return; + } + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.buf.framebuf); + this.bound = true; +}; + +SceneJS._webgl.RenderBuffer.prototype._touch = function () { + var width = this.canvas.canvas.width; + var height = this.canvas.canvas.height; + if (this.buf) { // Currently have a buffer + if (this.buf.width == width && this.buf.height == height) { // Canvas size unchanged, buffer still good + return; + } else { // Buffer needs reallocation for new canvas size + this.gl.deleteTexture(this.buf.texture); + this.gl.deleteFramebuffer(this.buf.framebuf); + this.gl.deleteRenderbuffer(this.buf.renderbuf); + } + } + + this.buf = { + framebuf: this.gl.createFramebuffer(), + renderbuf: this.gl.createRenderbuffer(), + texture: this.gl.createTexture(), + width: width, + height: height + }; + + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.buf.framebuf); + this.gl.bindTexture(this.gl.TEXTURE_2D, this.buf.texture); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); + this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); + + try { + // Do it the way the spec requires + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null); + } catch (exception) { + // Workaround for what appears to be a Minefield bug. + var textureStorage = new WebGLUnsignedByteArray(width * height * 3); + this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, textureStorage); + } + + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, this.buf.renderbuf); + this.gl.renderbufferStorage(this.gl.RENDERBUFFER, this.gl.DEPTH_COMPONENT16, width, height); + this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, this.buf.texture, 0); + this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER, this.gl.DEPTH_ATTACHMENT, this.gl.RENDERBUFFER, this.buf.renderbuf); + this.gl.bindTexture(this.gl.TEXTURE_2D, null); + this.gl.bindRenderbuffer(this.gl.RENDERBUFFER, null); + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null); + + // Verify framebuffer is OK + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.buf.framebuf); + + if (!this.gl.isFramebuffer(this.buf.framebuf)) { + throw SceneJS_error.fatalError(SceneJS.errors.INVALID_FRAMEBUFFER, "Invalid framebuffer"); + } + + var status = this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER); + + switch (status) { + + case this.gl.FRAMEBUFFER_COMPLETE: + break; + + case this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + + case this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + + case this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + + case this.gl.FRAMEBUFFER_UNSUPPORTED: + throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED"); + + default: + throw SceneJS_error.fatalError(SceneJS.errors.ERROR, "Incomplete framebuffer: " + status); + } + + this.bound = false; +}; + +/** + * Clears this renderbuffer + */ +SceneJS._webgl.RenderBuffer.prototype.clear = function () { + if (!this.bound) { + throw "Render buffer not bound"; + } + this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); + this.gl.disable(this.gl.BLEND); +}; + +/** + * Reads buffer pixel at given coordinates + */ +SceneJS._webgl.RenderBuffer.prototype.read = function (pickX, pickY) { + var x = pickX; + var y = this.canvas.canvas.height - pickY; + var pix = new Uint8Array(4); + this.gl.readPixels(x, y, 1, 1, this.gl.RGBA, this.gl.UNSIGNED_BYTE, pix); + return pix; +}; + +/** + * Unbinds this renderbuffer + */ +SceneJS._webgl.RenderBuffer.prototype.unbind = function () { + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null); + this.bound = false; +}; + +/** Returns the texture + */ +SceneJS._webgl.RenderBuffer.prototype.getTexture = function () { + var self = this; + return { + bind: function (unit) { + if (self.buf && self.buf.texture) { + self.gl.activeTexture(self.gl["TEXTURE" + unit]); + self.gl.bindTexture(self.gl.TEXTURE_2D, self.buf.texture); + return true; + } + return false; + }, + unbind: function (unit) { + if (self.buf && self.buf.texture) { + self.gl.activeTexture(self.gl["TEXTURE" + unit]); + self.gl.bindTexture(self.gl.TEXTURE_2D, null); + } + } + }; +}; + +/** Destroys this buffer + */ +SceneJS._webgl.RenderBuffer.prototype.destroy = function () { + if (this.buf) { + this.gl.deleteTexture(this.buf.texture); + this.gl.deleteFramebuffer(this.buf.framebuf); + this.gl.deleteRenderbuffer(this.buf.renderbuf); + this.buf = null; + this.bound = false; + } +};;/** + * @class Wrapper for a WebGL program + * + * @param hash SceneJS-managed ID for program + * @param gl WebGL gl + * @param vertexSources Source codes for vertex shaders + * @param fragmentSources Source codes for fragment shaders + * @param logging Program and shaders will write to logging's debug channel as they compile and link + */ +SceneJS._webgl.Program = function (gl, vertexSources, fragmentSources) { + + /** + * True as soon as this program is allocated and ready to go + * @type {boolean} + */ + this.allocated = false; + + this.gl = gl; + + this._uniforms = {}; + this._samplers = {}; + this._attributes = {}; + + this.uniformValues = []; + + this.materialSettings = { + specularColor: [0, 0, 0], + specular: 0, + shine: 0, + emit: 0, + alpha: 0 + }; + + // Create shaders from sources + + this._shaders = []; + + var a, i, u, u_name, location, shader; + + for (i = 0; i < vertexSources.length; i++) { + this._shaders.push(new SceneJS._webgl.Shader(gl, gl.VERTEX_SHADER, vertexSources[i])); + } + + for (i = 0; i < fragmentSources.length; i++) { + this._shaders.push(new SceneJS._webgl.Shader(gl, gl.FRAGMENT_SHADER, fragmentSources[i])); + } + + // Create program, attach shaders, link and validate program + + this.handle = gl.createProgram(); + + if (this.handle) { + + for (i = 0; i < this._shaders.length; i++) { + shader = this._shaders[i]; + if (shader.valid) { + gl.attachShader(this.handle, shader.handle); + } + } + + gl.linkProgram(this.handle); + + // Discover uniforms and samplers + + var numUniforms = gl.getProgramParameter(this.handle, gl.ACTIVE_UNIFORMS); + var valueIndex = 0; + for (i = 0; i < numUniforms; ++i) { + u = gl.getActiveUniform(this.handle, i); + if (u) { + u_name = u.name; + if (u_name[u_name.length - 1] == "\u0000") { + u_name = u_name.substr(0, u_name.length - 1); + } + location = gl.getUniformLocation(this.handle, u_name); + if ((u.type == gl.SAMPLER_2D) || (u.type == gl.SAMPLER_CUBE) || (u.type == 35682)) { + this._samplers[u_name] = new SceneJS._webgl.Sampler(gl, this.handle, u_name, u.type, u.size, location); + } else { + this._uniforms[u_name] = new SceneJS._webgl.Uniform(gl, this.handle, u_name, u.type, u.size, location, valueIndex); + this.uniformValues[valueIndex] = null; + ++valueIndex; + } + } + } + + // Discover attributes + + var numAttribs = gl.getProgramParameter(this.handle, gl.ACTIVE_ATTRIBUTES); + for (i = 0; i < numAttribs; i++) { + a = gl.getActiveAttrib(this.handle, i); + if (a) { + location = gl.getAttribLocation(this.handle, a.name); + this._attributes[a.name] = new SceneJS._webgl.Attribute(gl, this.handle, a.name, a.type, a.size, location); + } + } + + // Program allocated + this.allocated = true; + + } // if (this.handle) +}; + + +SceneJS._webgl.Program.prototype.bind = function () { + if (!this.allocated) { + return; + } + this.gl.useProgram(this.handle); +}; + +SceneJS._webgl.Program.prototype.getUniformLocation = function (name) { + if (!this.allocated) { + return; + } + var u = this._uniforms[name]; + if (u) { + return u.getLocation(); + } +}; + +SceneJS._webgl.Program.prototype.getUniform = function (name) { + if (!this.allocated) { + return; + } + var u = this._uniforms[name]; + if (u) { + return u; + } +}; + +SceneJS._webgl.Program.prototype.getAttribute = function (name) { + if (!this.allocated) { + return; + } + var attr = this._attributes[name]; + if (attr) { + return attr; + } +}; + +SceneJS._webgl.Program.prototype.bindFloatArrayBuffer = function (name, buffer) { + if (!this.allocated) { + return; + } + var attr = this._attributes[name]; + if (attr) { + attr.bindFloatArrayBuffer(buffer); + } +}; + +SceneJS._webgl.Program.prototype.bindTexture = function (name, texture, unit) { + if (!this.allocated) { + return false; + } + var sampler = this._samplers[name]; + if (sampler) { + return sampler.bindTexture(texture, unit); + } else { + return false; + } +}; + +SceneJS._webgl.Program.prototype.destroy = function () { + if (!this.allocated) { + return; + } + this.gl.deleteProgram(this.handle); + for (var s in this._shaders) { + this.gl.deleteShader(this._shaders[s].handle); + } + this.handle = null; + this._attributes = null; + this._uniforms = null; + this._samplers = null; + this.allocated = false; +}; + + +SceneJS._webgl.Program.prototype.setUniform = function (name, value) { + if (!this.allocated) { + return; + } + var u = this._uniforms[name]; + if (u) { + if (this.uniformValues[u.index] !== value || !u.numberValue) { + u.setValue(value); + this.uniformValues[u.index] = value; + } + } +}; +;SceneJS._webgl.Sampler = function (gl, program, name, type, size, location) { + + this.bindTexture = function (texture, unit) { + if (texture.bind(unit)) { + gl.uniform1i(location, unit); + return true; + } + return false; + }; +}; +;/** + * A vertex/fragment shader in a program + * + * @private + * @param gl WebGL gl + * @param gl.VERTEX_SHADER | gl.FRAGMENT_SHADER + * @param source Source code for shader + * @param logging Shader will write logging's debug channel as it compiles + */ +SceneJS._webgl.Shader = function (gl, type, source) { + + /** + * True as soon as this shader is allocated and ready to go + * @type {boolean} + */ + this.allocated = false; + + this.handle = gl.createShader(type); + + if (!this.handle) { + throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM, "Failed to create WebGL shader"); + } + + gl.shaderSource(this.handle, source); + gl.compileShader(this.handle); + + this.valid = (gl.getShaderParameter(this.handle, gl.COMPILE_STATUS) != 0); + + if (!this.valid) { + + if (!gl.isContextLost()) { // Handled explicitely elsewhere, so wont rehandle here + + SceneJS.log.error("Shader program failed to compile: " + gl.getShaderInfoLog(this.handle)); + SceneJS.log.error("Shader source:"); + var lines = source.split('\n'); + for (var j = 0; j < lines.length; j++) { + SceneJS.log.error((j + 1) + ": " + lines[j]); + } + + throw SceneJS_error.fatalError( + SceneJS.errors.SHADER_COMPILATION_FAILURE, "Shader program failed to compile"); + } + } + + this.allocated = true; +}; +; +SceneJS._webgl.Texture2D = function (gl, cfg) { + /** + * True as soon as this texture is allocated and ready to go + * @type {boolean} + */ + this.allocated = false; + + this.target = cfg.target || gl.TEXTURE_2D; + this.minFilter = cfg.minFilter; + this.magFilter = cfg.magFilter; + this.wrapS = cfg.wrapS; + this.wrapT = cfg.wrapT; + this.update = cfg.update; // For dynamically-sourcing textures (ie movies etc) + this.texture = cfg.texture; + this.format = gl.RGBA; + this.isDepth = false; + this.depthMode = 0; + this.depthCompareMode = 0; + this.depthCompareFunc = 0; + + try { + gl.bindTexture(this.target, this.texture); + + if (cfg.minFilter) { + gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, cfg.minFilter); + } + + if (cfg.magFilter) { + gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, cfg.magFilter); + } + + if (cfg.wrapS) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, cfg.wrapS); + } + + if (cfg.wrapT) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, cfg.wrapT); + } + + if (cfg.minFilter == gl.NEAREST_MIPMAP_NEAREST || + cfg.minFilter == gl.LINEAR_MIPMAP_NEAREST || + cfg.minFilter == gl.NEAREST_MIPMAP_LINEAR || + cfg.minFilter == gl.LINEAR_MIPMAP_LINEAR) { + gl.generateMipmap(this.target); + } + + gl.bindTexture(this.target, null); + + this.allocated = true; + + } catch (e) { + throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM, "Failed to create texture: " + e.message || e); + } + + this.bind = function (unit) { + if (!this.allocated) { + return; + } + if (this.texture) { + gl.activeTexture(gl["TEXTURE" + unit]); + gl.bindTexture(this.target, this.texture); + if (this.update) { + this.update(gl); + } + return true; + } + return false; + }; + + this.unbind = function (unit) { + if (!this.allocated) { + return; + } + if (this.texture) { + gl.activeTexture(gl["TEXTURE" + unit]); + gl.bindTexture(this.target, null); + } + }; + + this.destroy = function () { + if (!this.allocated) { + return; + } + if (this.texture) { + gl.deleteTexture(this.texture); + this.texture = null; + } + }; +}; + +SceneJS._webgl.clampImageSize = function (image, numPixels) { + var n = image.width * image.height; + if (n > numPixels) { + var ratio = numPixels / n; + + var width = image.width * ratio; + var height = image.height * ratio; + + var canvas = document.createElement("canvas"); + + canvas.width = SceneJS._webgl.nextHighestPowerOfTwo(width); + canvas.height = SceneJS._webgl.nextHighestPowerOfTwo(height); + + var ctx = canvas.getContext("2d"); + + ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height); + + image = canvas; + } + return image; +}; + +SceneJS._webgl.ensureImageSizePowerOfTwo = function (image) { + if (!SceneJS._webgl.isPowerOfTwo(image.width) || !SceneJS._webgl.isPowerOfTwo(image.height)) { + var canvas = document.createElement("canvas"); + canvas.width = SceneJS._webgl.nextHighestPowerOfTwo(image.width); + canvas.height = SceneJS._webgl.nextHighestPowerOfTwo(image.height); + var ctx = canvas.getContext("2d"); + ctx.drawImage(image, + 0, 0, image.width, image.height, + 0, 0, canvas.width, canvas.height); + image = canvas; + } + return image; +}; + +SceneJS._webgl.isPowerOfTwo = function (x) { + return (x & (x - 1)) == 0; +}; + +SceneJS._webgl.nextHighestPowerOfTwo = function (x) { + --x; + for (var i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; +}; + +;SceneJS._webgl.Uniform = function (gl, program, name, type, size, location, index, logging) { + + var func = null; + + var value = null; + + if (type === gl.BOOL) { + + func = function (v) { + if (value === v) { + return; + } + value = v; + gl.uniform1i(location, v); + }; + + } else if (type === gl.BOOL_VEC2) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; + gl.uniform2iv(location, v); + }; + + } else if (type === gl.BOOL_VEC3) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; + gl.uniform3iv(location, v); + }; + + } else if (type === gl.BOOL_VEC4) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; + gl.uniform4iv(location, v); + }; + + } else if (type === gl.INT) { + + func = function (v) { + if (value === v) { + return; + } + value = v; + gl.uniform1iv(location, v); + }; + + } else if (type === gl.INT_VEC2) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; + gl.uniform2iv(location, v); + }; + + } else if (type === gl.INT_VEC3) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; + gl.uniform3iv(location, v); + }; + + } else if (type === gl.INT_VEC4) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; + gl.uniform4iv(location, v); + }; + + } else if (type === gl.FLOAT) { + + func = function (v) { + if (value === v) { + return; + } + value = v; + gl.uniform1f(location, v); + }; + + } else if (type === gl.FLOAT_VEC2) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1]) { + return; + } + value = v; + gl.uniform2fv(location, v); + }; + + } else if (type === gl.FLOAT_VEC3) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2]) { + return; + } + value = v; + gl.uniform3fv(location, v); + }; + + } else if (type === gl.FLOAT_VEC4) { + + func = function (v) { + if (value !== null && value[0] === v[0] && value[1] === v[1] && value[2] === v[2] && value[3] === v[3]) { + return; + } + value = v; + gl.uniform4fv(location, v); + }; + + } else if (type === gl.FLOAT_MAT2) { + + func = function (v) { + gl.uniformMatrix2fv(location, gl.FALSE, v); + }; + + } else if (type === gl.FLOAT_MAT3) { + + func = function (v) { + gl.uniformMatrix3fv(location, gl.FALSE, v); + }; + + } else if (type === gl.FLOAT_MAT4) { + + func = function (v) { + gl.uniformMatrix4fv(location, gl.FALSE, v); + }; + + } else { + throw "Unsupported shader uniform type: " + type; + } + + this.setValue = func; + + this.getLocation = function () { + return location; + }; + + // This is just an integer key for caching the uniform's value, more efficient than caching by name. + this.index = index; +}; + + + + + + + + + + +;/** + * Manages scene node event listeners + * @private + */ +var SceneJS_nodeEventsModule = new (function () { + + var idStack = []; + var listenerStack = []; + var stackLen = 0; + var dirty; + + var defaultCore = { + type:"listeners", + stateId:SceneJS._baseStateId++, + empty:true, + listeners:[] + }; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function () { + stackLen = 0; + dirty = true; + }); + + SceneJS_events.addListener( + SceneJS_events.OBJECT_COMPILING, + function (params) { + if (dirty) { + if (stackLen > 0) { + var core = { + type:"listeners", + stateId:idStack[stackLen - 1], + listeners:listenerStack.slice(0, stackLen) + }; + params.display.renderListeners = core; + } else { + params.display.renderListeners = defaultCore; + } + dirty = false; + } + }); + + + this.preVisitNode = function (node) { + + var renderedSubs = node._topicSubs["rendered"]; // DEPRECATED in V3.2 + var worldPosSubs = node._topicSubs["worldPos"]; + var viewPosSubs = node._topicSubs["viewPos"]; + var cameraPosSubs = node._topicSubs["cameraPos"]; + var projPosSubs = node._topicSubs["projPos"]; + var canvasPosSubs = node._topicSubs["canvasPos"]; + + if (renderedSubs || worldPosSubs || viewPosSubs || cameraPosSubs || projPosSubs || canvasPosSubs) { + idStack[stackLen] = node.id; + + listenerStack[stackLen] = function (event) { + + // Don't retain - callback must get positions for + // required coordinate via methods on the event object. + // That's dirty, therefore deprecated. + if (renderedSubs) { + node.publish("rendered", event, true); // DEPRECATED in V3.2 + } + + // Publish retained positions for coordinate systems where subscribed + if (worldPosSubs) { + node.publish("worldPos", event.getWorldPos()); + } + if (viewPosSubs) { + node.publish("viewPos", event.getViewPos()); + } + if (cameraPosSubs) { + node.publish("cameraPos", event.getCameraPos()); + } + if (projPosSubs) { + node.publish("projPos", event.getProjPos()); + } + if (canvasPosSubs) { + node.publish("canvasPos", event.getCanvasPos()); + } + }; + + stackLen++; + dirty = true; + } + }; + + this.postVisitNode = function (node) { + if (node.id == idStack[stackLen - 1]) { + stackLen--; + dirty = true; + } + }; + +})(); + +;/** + * @class Holds state for one or more {@link SceneJS.Node}s. + * + *

Each {@link SceneJS.Node} has a state core to hold its state, and the core may be shared by other + * {@link SceneJS.Nodes}s of the same type.

+ * + *

The state held by core is rendered by a {@link SceneJS_Chunk} + * + * @private + */ +var SceneJS_Core = function(type) { + + /** + * The state core type, which will be the same value as the type property on the {@link SceneJS.Node}s that use the core + * @type String + * @see SceneJS.Node#type + */ + this.type = type; + + /** + * The state core ID, unique within the scene. This ID may be either a string assigned by the application layer via + * scene node configs, or a number that is automatically generated by the {@link SceneJS_CoreFactory} managing + * this core instance. + * @type String|Number + */ + this.coreId = null; + + /** + * Uniquely identifies this state core within a {@link SceneJS_Display}. + * + * This ID is used by a {@link SceneJS_Display} to reduce redundant state changes when rendering a sequence of cores, + * where as a {@link SceneJS_Display} renders a frame it avoids applying consecutive cores that have the + * same value for this ID. + * + * @type Number + */ + this.stateId = null; + + /** + * Count of {@link SceneJS.Node} instances this core holds state for + */ + this.useCount = 0; +};;/** + * @class Manages creation, recycle and destruction of {@link SceneJS_Core} instances + * @private + */ +var SceneJS_CoreFactory = function () { + + this._stateMap = new SceneJS_Map(null, SceneJS._baseStateId); // For creating unique state IDs for cores + + this._cores = {}; // Map of cores for each type +}; + +/** + * State core classes provided by this factory + * @type {SceneJS.Core} + */ +SceneJS_CoreFactory.coreTypes = {}; // Supported core classes, installed by #createCoreType + +/** + * Creates a core class for instantiation by this factory + * @param {String} type Name of type, eg. "camera" + * @param {Node} [superType] Class of super type - SceneJS.Node by default + * @returns The new node class + */ +SceneJS_CoreFactory.createCoreType = function (type, superType) { + // + // var supa = SceneJS_CoreFactory.coreTypes[superType]; + // + // if (!supa) { + // supa = SceneJS.Core; // Super class is Core by default + // } + // + // var nodeType = function() { // Create the class + // supa.apply(this, arguments); + // this.type = type; + // }; + // + // nodeType.prototype = new supa(); // Inherit from base class + // nodeType.prototype.constructor = nodeType; + // + // SceneJS_CoreFactory.nodeTypes[type] = nodeType; + // + // return nodeType; +}; + +SceneJS_CoreFactory.addCoreBuilder = function (type, factory) { + +}; + +/* HACK - allows different types of node to have same type of core, eg. "rotate" and "translate" nodes can both have an "xform" core + */ +SceneJS_CoreFactory.coreAliases = { + "rotate":"xform", + "translate":"xform", + "scale":"xform", + "matrix":"xform", + "xform":"xform" +}; + +/** + * Gets a core of the given type from this factory. Reuses any existing existing core of the same type and ID. + * + * The caller (a scene node) will then augment the core with type-specific attributes and methods. + * + * @param {String} type Type name of core, e.g. "material", "texture" + * @param {String} coreId ID for the core, unique among all cores of the given type within this factory + * @returns {Core} The core + */ +SceneJS_CoreFactory.prototype.getCore = function (type, coreId) { + + /* HACK - allows different types of node to have same type of core, eg. "rotate" and "translate" nodes can both have an "xform" core + */ + var alias = SceneJS_CoreFactory.coreAliases[type]; + if (alias) { + type = alias; + } + + var cores = this._cores[type]; + + if (!cores) { + cores = this._cores[type] = {}; + } + + var core; + + if (coreId) { // Attempt to reuse a core + + core = cores[coreId]; + + if (core) { + core.useCount++; + return core; + } + } + + core = new SceneJS_Core(type); + core.useCount = 1; // One user so far + + core.stateId = this._stateMap.addItem(core); + core.coreId = (coreId != undefined && coreId != null) ? coreId : core.stateId; // Use state ID as core ID by default + + cores[core.coreId] = core; + + return core; +}; + + +/** + * Tests if a core of the given type and ID currently exists within this factory. + * + * @param {String} type Type name of core, e.g. "material", "texture" + * @param {String} coreId ID for the core, unique among all cores of the given type within this factory + * @returns {Boolean} True if the core exists + */ +SceneJS_CoreFactory.prototype.hasCore = function (type, coreId) { + // HACK - allows different types of node to have same type of core, eg. "rotate" and "translate" nodes can both have an "xform" core + var alias = SceneJS_CoreFactory.coreAliases[type]; + if (alias) { + type = alias; + } + var cores = this._cores[type]; + return cores && cores[coreId]; +}; + +/** + * Releases a state core back to this factory, destroying it if the core's use count is then zero. + * @param {Core} core Core to release + */ +SceneJS_CoreFactory.prototype.putCore = function (core) { + + if (core.useCount == 0) { + return; // In case of excess puts + } + + if (--core.useCount <= 0) { // Release shared core if use count now zero + + var cores = this._cores[core.type]; + + delete cores[core.coreId]; + + this._stateMap.removeItem(core.stateId); // Release state ID for reuse + } +}; + +/** + * Reallocates WebGL resources for cores within this factory + */ +SceneJS_CoreFactory.prototype.webglRestored = function () { + + var cores; + var core; + + for (var type in this._cores) { + if (this._cores.hasOwnProperty(type)) { + + cores = this._cores[type]; + + if (cores) { + + for (var coreId in cores) { + if (cores.hasOwnProperty(coreId)) { + + core = cores[coreId]; + + if (core && core.webglRestored) { // Method augmented on core by user + core.webglRestored(); + } + } + } + } + } + } +}; +;/** + * @class The basic scene graph node type + */ +SceneJS.Node = function () { +}; + +/** + * @class Basic scene graph node + */ +SceneJS.Node.prototype.constructor = SceneJS.Node; + +/** + * Called by SceneJS_Engine after it has instantiated the node + * + * @param {SceneJS_Engine} engine The engine which will manage this node + * @param {SceneJS_Core} core The core which will hold state for this node, may be shared with other nodes of the same type + * @param cfg Configuration for this node + * @param {String} cfg.id ID for the node, unique among all nodes in the scene + * @param {String} cfg.type type Type of this node (eg. "material", "texture" etc) + * @param {Object} cfg.data Optional arbitrary JSON object to attach to node + * @param {String} nodeId Optional ID for node + */ +SceneJS.Node.prototype._construct = function (engine, core, cfg, nodeId) { + + /** + * Engine that manages this node + * @type SceneJS_Engine + */ + this._engine = engine; + + /** + * The core which holds state for this node, may be shared with other nodes of the same type + * @type SceneJS_Core + */ + this._core = core; + + /** + * The core ID + * @type {String|Number} + */ + this.coreId = core.coreId; + + /** + * ID of this node, unique within its scene. The ID is a string if it was defined by the application + * via the node's JSON configuration, otherwise it is a number if it was left to SceneJS to automatically create. + * @type String|Number + */ + this.id = cfg.id || cfg.nodeId || nodeId; + + /** + * Type of this node (eg. "material", "texture" etc) + * @type String + */ + this.type = cfg.type || "node"; + + /** + * Optional arbitrary JSON object attached to this node + * @type JSON + */ + this.data = cfg.data; + + /** + * Parent node + * @type SceneJS.Node + */ + this.parent = null; + + /** + * Child nodes + * @type SceneJS.Node[] + */ + this.nodes = []; + + // Pub/sub support + this._handleMap = new SceneJS_Map(); // Subscription handle pool + this._topicSubs = {}; // A [handle -> callback] map for each topic name + this._handleTopics = {}; // Maps handles to topic names + this._topicPubs = {}; // Maps topics to publications + + /** + * + */ + this._listeners = {}; + + /** + * + */ + this._numListeners = 0; // Useful for quick check whether node observes any events + + /** + * + */ + this.dirty = false; + + /** + * + */ + this.branchDirty = false; + + if (this._init) { + this._init(cfg); + } +}; + +/** + * Notifies that an asynchronous task has started on this node + * @param {String} [description] Description - will be "Task" by default + * @return {String} Unique ID for the task, which may be given to {@link #taskFinished} or {@link #taskFailed} + */ +SceneJS.Node.prototype.taskStarted = function (description) { + return SceneJS_sceneStatusModule.taskStarted(this, description || "Task"); +}; + +/** + * Notifies that a task, whose initiation was previously notified with {@link #taskStarted}, + * has now completed successfully. + * @param {String} taskId Unique ID for the task, which was got with {@link #taskStarted} + * @return null + */ +SceneJS.Node.prototype.taskFinished = function (taskId) { + return SceneJS_sceneStatusModule.taskFinished(taskId); +}; + +/** + * Notifies that a task, whose initiation was previously notified with {@link #taskStarted}, + * has failed. + * @param {String} taskId Unique ID for the task, which was got with {@link #taskStarted} + * @return null + */ +SceneJS.Node.prototype.taskFailed = function (taskId) { + return SceneJS_sceneStatusModule.taskFailed(taskId); +}; + +/** + * Logs a message in the context of this node + * @param {String} [channel] Logging channel - "error", "warn" or "info" (default) + * @param {String} msg Message to log + */ +SceneJS.Node.prototype.log = function () { + var channel; + var msg; + if (arguments.length == 1) { + channel = "info"; + msg = arguments[0]; + } else if (arguments.length == 2) { + channel = arguments[0]; + msg = arguments[1]; + } + switch (channel) { + case "warn": + msg = "WARN; [SceneJS.Node type=" + this.type + ", id=" + this.id + "] : " + msg; + break; + case "error": + msg = "ERROR; [SceneJS.Node type=" + this.type + ", id=" + this.id + "] : " + msg; + break; + default: + msg = "INFO; [SceneJS.Node type=" + this.type + ", id=" + this.id + "] : " + msg; + break; + } + + if (console[channel]) { + console[channel](msg); + } else { + console.log(msg); + } +}; + +/** + * Publishes to a topic on this node. + * + * Immediately notifies existing subscriptions to that topic, and unless the "forget' parameter is + * true, retains the publication to give to any subsequent notifications on that topic as they are made. + * + * @param {String} topic Publication topic + * @param {Object} pub The publication + * @param {Boolean} [forget] When true, the publication will be sent to subscribers then forgotten, so that any + * subsequent subscribers will not receive it + */ +SceneJS.Node.prototype.publish = function (topic, pub, forget) { + if (!forget) { + this._topicPubs[topic] = pub; // Save notification + } + if (this._topicSubs[topic]) { // Notify subscriptions + var subsForTopic = this._topicSubs[topic]; + for (var handle in subsForTopic) { + if (subsForTopic.hasOwnProperty(handle)) { + subsForTopic[handle].call(this, pub); + } + } + } +}; + +/** + * Removes a topic publication + * + * Immediately notifies existing subscriptions to that topic, sending them each a null publication. + * + * @param topic Publication topic + * @private + */ +SceneJS.Node.prototype.unpublish = function (topic) { + var subsForTopic = this._topicSubs[topic]; + if (subsForTopic) { // Notify subscriptions + for (var handle in subsForTopic) { + if (subsForTopic.hasOwnProperty(handle)) { + subsForTopic[handle].call(this, null); + } + } + } + delete this._topicPubs[topic]; +}; + + +/** + * Listen for data changes at a particular location on this node + * + *

Your callback will be triggered for + * the initial data and again whenever the data changes. Use {@link #off} to stop receiving updates.

+ * + *

The callback is be called with this node as scope.

+ * + * @param {String} location Publication location + * @param {Function(data)} callback Called when fresh data is available at the location + * @return {String} Handle to the subscription, which may be used to unsubscribe with {@link #off}. + */ +SceneJS.Node.prototype.on = function (topic, callback) { + var subsForTopic = this._topicSubs[topic]; + if (!subsForTopic) { + subsForTopic = {}; + this._topicSubs[topic] = subsForTopic; + } + var handle = this._handleMap.addItem(); // Create unique handle + subsForTopic[handle] = callback; + this._handleTopics[handle] = topic; + var pub = this._topicPubs[topic]; + if (pub) { // A publication exists, notify callback immediately + callback.call(this, pub); + } + //else { + if (topic == "rendered") { + this._engine.branchDirty(this); + } +// if (topic == "tick") { +// this._engine.scene.on("tick",callback); +// } + // } + return handle; +}; + +/** + * Unsubscribes from a publication on this node that was previously made with {@link #on}. + * @param handle Publication handle + */ +SceneJS.Node.prototype.off = function (handle) { + var topic = this._handleTopics[handle]; + if (topic) { + delete this._handleTopics[handle]; + var topicSubs = this._topicSubs[topic]; + if (topicSubs) { + delete topicSubs[handle]; + } + this._handleMap.removeItem(handle); // Release handle + if (topic == "rendered") { + this._engine.branchDirty(this); + } + } +// else { +// this._engine.scene.off(handle); +// } +}; + +/** + * Listens for exactly one data update at the specified location on this node, and then stops listening. + *

This is equivalent to calling {@link #on}, and then calling {@link #off} inside the callback function.

+ * @param {String} location Data location to listen to + * @param {Function(data)} callback Called when fresh data is available at the location + */ +SceneJS.Node.prototype.once = function (topic, callback) { + var self = this; + var sub = this.on(topic, + function (pub) { + self.off(sub); + callback(pub); + }); +}; + +/** + * Returns this node's {@link SceneJS.Scene} + */ +SceneJS.Node.prototype.getScene = function () { + return this._engine.scene; +}; + +/** + * Returns the ID of this node's core + */ +SceneJS.Node.prototype.getCoreId = function () { + return this._core.coreId; +}; + +/** + * Get the node's ID + * + */ +SceneJS.Node.prototype.getID = function () { + return this.id; +}; + +/** + * Alias for getID + * @function + */ +SceneJS.Node.prototype.getId = function () { + return this.id; +}; + +/** + * Alias for getID + * @function + */ +SceneJS.Node.prototype.getNodeId = function () { + return this.id; +}; + + +/** + * Returns the node's type. For the Node base class, it is "node", overridden in sub-classes. + */ +SceneJS.Node.prototype.getType = function () { + return this.type; +}; + +/** + * Returns the data object attached to this node. + */ +SceneJS.Node.prototype.getData = function () { + return this.data; +}; + +/** + * Sets a data object on this node. + */ +SceneJS.Node.prototype.setData = function (data) { + this.data = data; + return this; +}; + +/** + * Returns the number of child nodes + */ +SceneJS.Node.prototype.getNumNodes = function () { + return this.nodes.length; +}; + +/** Returns child nodes + * @returns {Array} Child nodes + */ +SceneJS.Node.prototype.getNodes = function () { + return this.nodes.slice(0); +}; + +/** Returns child node at given index. Returns null if no node at that index. + * @param {Number} index The child index + * @returns {Node} Child node, or null if not found + */ +SceneJS.Node.prototype.getNodeAt = function (index) { + if (index < 0 || index >= this.nodes.length) { + return null; + } + return this.nodes[index]; +}; + +/** Returns first child node. Returns null if no child nodes. + * @returns {Node} First child node, or null if not found + */ +SceneJS.Node.prototype.getFirstNode = function () { + if (this.nodes.length == 0) { + return null; + } + return this.nodes[0]; +}; + +/** Returns last child node. Returns null if no child nodes. + * @returns {Node} Last child node, or null if not found + */ +SceneJS.Node.prototype.getLastNode = function () { + if (this.nodes.length == 0) { + return null; + } + return this.nodes[this.nodes.length - 1]; +}; + +/** Returns child node with the given ID. + * Returns null if no such child node found. + */ +SceneJS.Node.prototype.getNode = function (id) { + for (var i = 0; i < this.nodes.length; i++) { + if (this.nodes[i].id == id) { + return this.nodes[i]; + } + } + return null; +}; + +/** Disconnects the child node at the given index from its parent node + * @param {int} index Child node index + * @returns {Node} The disconnected child node if located, else null + */ +SceneJS.Node.prototype.disconnectNodeAt = function (index) { + var r = this.nodes.splice(index, 1); + if (r.length > 0) { + r[0].parent = null; + this._engine.display.objectListDirty = true; + return r[0]; + } else { + return null; + } +}; + +/** Disconnects the child node from its parent, given as a node object + * @param {String | Node} id The target child node, or its ID + * @returns {Node} The removed child node if located + */ +SceneJS.Node.prototype.disconnect = function () { + if (this.parent) { + for (var i = 0; i < this.parent.nodes.length; i++) { + if (this.parent.nodes[i] === this) { + var node = this.parent.disconnectNodeAt(i); + this.parent = null; + return node; + } + } + this.parent = null; + } + return null; +}; + +/** Removes the child node at the given index + * @param {int} index Child node index + */ +SceneJS.Node.prototype.removeNodeAt = function (index) { + var child = this.disconnectNodeAt(index); + if (child) { + child.destroy(); + this._engine.display.objectListDirty = true; + } +}; + +/** Removes the child node, given as either a node object or an ID string. + * @param {String | Node} id The target child node, or its ID + * @returns {Node} The removed child node if located + */ +SceneJS.Node.prototype.removeNode = function (node) { + + if (!node) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Node#removeNode - node argument undefined"); + } + + if (!node._compile) { + if (typeof node == "string") { + var gotNode = this._engine.findNode(node); + if (!gotNode) { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_NOT_FOUND, + "Node#removeNode - node not found anywhere: '" + node + "'"); + } + node = gotNode; + } + } + + if (node._compile) { // instance of node + for (var i = 0; i < this.nodes.length; i++) { + if (this.nodes[i] === node) { + var removedNode = this.removeNodeAt(i); + this._engine.display.objectListDirty = true; + return removedNode; + } + } + } + + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_NOT_FOUND, + "Node#removeNode - child node not found: " + (node._compile ? ": " + node.id : node)); +}; + +/** Disconnects all child nodes from their parent node and returns them in an array. + */ +SceneJS.Node.prototype.disconnectNodes = function () { + var len = this.nodes.length; + for (var i = 0; i < len; i++) { // Unlink nodes from this + this.nodes[i].parent = null; + } + var nodes = this.nodes; + this.nodes = []; + this._engine.display.objectListDirty = true; + return nodes; +}; + +/** Removes all child nodes and returns them in an array. + */ +SceneJS.Node.prototype.removeNodes = function () { + var nodes = this.disconnectNodes(); + for (var i = 0; i < nodes.length; i++) { + nodes[i].destroy(); + this._engine.display.objectListDirty = true; + } +}; + +/** Destroys this node and moves children up to parent, inserting them where this node resided. + */ +SceneJS.Node.prototype.splice = function () { + + var i, len; + + if (this.parent == null) { + return null; + } + var parent = this.parent; + var nodes = this.disconnectNodes(); + for (i = 0, len = nodes.length; i < len; i++) { // Link this node's nodes to new parent + nodes[i].parent = this.parent; + } + for (i = 0, len = parent.nodes.length; i < len; i++) { // Replace node on parent's nodes with this node's nodes + if (parent.nodes[i] === this) { + + parent.nodes.splice.apply(parent.nodes, [i, 1].concat(nodes)); + + this.nodes = []; + this.parent = null; + + this.destroy(); + + this._engine.branchDirty(parent); + + return parent; + } + } +}; + +/** Appends multiple child nodes + */ +SceneJS.Node.prototype.addNodes = function (nodes, ok) { + + if (!nodes) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Node#addNodes - nodes argument is undefined"); + } + + var node; + var result = []; + var numNodes = nodes.length; + + for (var i = nodes.length - 1; i >= 0; i--) { + var nodeAttr = nodes[i]; + if (nodeAttr.type == "node" || this._engine.hasNodeType(nodeAttr.type)) { + + // Add loaded node type synchronously + + node = this.addNode(nodeAttr); + result[i] = node; + if (--numNodes == 0) { + if (ok) { + ok(nodes); + } + return nodes; + } + } else { + + // Load node type and instantiate it asynchronously + + var self = this; + (function () { + var nodei = i; + self.addNode(nodeAttr, + function (node) { + result[nodei] = node; + if (--numNodes == 0) { + if (ok) { + ok(nodes); + } + } + }); + })(); + } + } + return null; +}; + +/** Appends a child node + */ +SceneJS.Node.prototype.addNode = function (node, ok) { + + node = node || {}; + + // Graft node object + if (node._compile) { + if (node.parent != null) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Node#addNode - node argument is still attached to another parent"); + } + this.nodes.push(node); + node.parent = this; + this._engine.branchDirty(node); + if (ok) { + ok(node); + } + return node; + } + + // Graft node object by ID reference + if (typeof node == "string") { + var gotNode = this._engine.findNode(node); + if (!gotNode) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Node#addNode - node not found: '" + node + "'"); + } + node = gotNode; + if (node.parent != null) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Node#addNode - node argument is still attached to another parent"); + } + this.nodes.push(node); + node.parent = this; + this._engine.branchDirty(node); + if (ok) { + ok(node); + } + return node; + } + + // Create node + + node.type = node.type || "node"; + + if (node.type == "node" || this._engine.hasNodeType(node.type)) { + + // Root node's type is already loaded, so we are able + // to create the root synchronously. When the caller + // is creating a core node type, then by this contract + // it can rely on the return value + + node = this._engine.createNode(node); + this.nodes.push(node); + node.parent = this; + this._engine.branchDirty(node); + if (ok) { + ok(node); + } + return node; + + } else { + + // Otherwise the root node's type needs to be loaded, + // so we need to create it asynchronously. By this contract, + // the Caller would not rely on synchronous creation of + // non-core types. + var self = this; + this._engine.createNode(node, + function (node) { + self.nodes.push(node); + node.parent = self; + self._engine.branchDirty(node); + if (ok) { + ok(node); + } + }); + return null; + } +}; + +/** Inserts a subgraph into child nodes + * @param {Node} node Child node + * @param {int} i Index for new child node + * @return {Node} The child node + */ +SceneJS.Node.prototype.insertNode = function (node, i) { + + if (!node) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Node#insertNode - node argument is undefined"); + } + + if (!node._compile) { // JSON node definition + node = this._engine.createNode(node); // Create node + } + + if (!node._compile) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Node#insertNode - node argument is not a SceneJS.Node"); + } + + if (node.parent != null) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Node#insertNode - node argument is still attached to another parent"); + } + + if (i === undefined || i === null) { + node.addNodes(this.disconnectNodes()); + this.addNode(node); + + } else if (i < 0) { + + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Node#insertNode - node index out of range: -1"); + + } else if (i >= this.nodes.length) { + this.nodes.push(node); + } else { + this.nodes.splice(i, 0, node); + } + + node.parent = this; + return node; +}; + +/** Calls the given function on each node in the subgraph rooted by this node, including this node. + * The callback takes each node as it's sole argument and traversal stops as soon as the function returns + * true and returns the node. + * @param {function(Node)} func The function + */ +SceneJS.Node.prototype.mapNodes = function (func) { + if (func(this)) { + return this; + } + var result; + for (var i = 0; i < this.nodes.length; i++) { + result = this.nodes[i].mapNodes(func); + if (result) { + return result; + } + } + return null; +}; + +/** + * Registers a listener for a given event on this node. If the event type + * is not supported by this node type, then the listener will never be called. + *

Example: + *


+ * var node = new Node();
+ *
+ * node.addListener(
+ *
+ *              // eventName
+ *              "some-event",
+ *
+ *              // handler
+ *              function(node,      // Node we are listening to
+ *                       params) {  // Whatever params accompany the event type
+ *
+ *                     // ...
+ *              }
+ * );
+ *
+ *
+ * 
+ * + * @param {String} eventName One of the event types supported by this node + * @param {Function} fn - Handler function that be called as specified + * @param options - Optional options for the handler as specified + * @return {Node} this + */ +SceneJS.Node.prototype.addListener = function (eventName, fn, options) { + var list = this._listeners[eventName]; + if (!list) { + list = []; + this._listeners[eventName] = list; + } + list.push({ + eventName:eventName, + fn:fn, + options:options || {} + }); + this._numListeners++; + return this; +}; + +/** + * Fires an event at this node, immediately calling listeners registered for the event + */ +SceneJS.Node.prototype._fireEvent = function (eventName, params, options) { + var list = this._listeners[eventName]; + if (list) { + if (!params) { + params = {}; + } + var event = { + name:eventName, + params:params, + options:options || {} + }; + var listener; + for (var i = 0, len = list.length; i < len; i++) { + listener = list[i]; + if (listener.options.scope) { + listener.fn.call(listener.options.scope, event); + } else { + listener.fn.call(this, event); + } + } + } +}; + +/** + * Removes a handler that is registered for the given event on this node. + * Does nothing if no such handler registered. + */ +SceneJS.Node.prototype.removeListener = function (eventName, fn) { + var list = this._listeners[eventName]; + if (!list) { + return null; + } + for (var i = 0; i < list.length; i++) { + if (list[i].fn == fn) { + list.splice(i, 1); + return fn; + } + } + this._numListeners--; + return null; +}; + +/** + * Returns true if this node has any listeners for the given event + */ +SceneJS.Node.prototype.hasListener = function (eventName) { + return this._listeners[eventName]; +}; + +/** + * Returns true if this node has any listeners at all. + */ +SceneJS.Node.prototype.hasListeners = function () { + return (this._numListeners > 0); +}; + +/** Removes all listeners registered on this node. + */ +SceneJS.Node.prototype.removeListeners = function () { + this._listeners = {}; + this._numListeners = 0; + return this; +}; + +/** + * Returns the parent node + * @return {SceneJS.Node} + */ +SceneJS.Node.prototype.getParent = function (type) { + return this.parent; +}; + +/** + * Finds the first node of given type on path to root. + * @param {String} type Parent type to find on path to root + * @return {SceneJS.Node} + */ +SceneJS.Node.prototype.getParentOfType = function (type) { + var parent = this.parent; + while (parent && parent.type != type) { + parent = parent.parent; + } + return parent; +}; + +/** + * Iterates over parent nodes on the path from the selected node to the root, executing a function + * for each. + * If the function returns true at any node, then traversal stops and a selector is + * returned for that node. + * @param {Function(node, index)} fn Function to execute on each instance node + * @return {Object} Selector for selected node, if any + */ +SceneJS.Node.prototype.eachParent = function (fn) { + + if (!fn) { + throw "SceneJS.Node.eachParent param 'fn' is null or undefined"; + } + + var count = 0; + var node = this; + + while (node.parent) { + if (fn.call(node.parent, count++) === true) { + return node.parent; + } + node = node.parent; + } + + return null; +}; + +/** Returns true if a child node matching given ID or index exists on this node + * @param {Number|String} node Child node index or ID + */ +SceneJS.Node.prototype.hasNode = function (node) { + + if (node === null || node === undefined) { + throw "SceneJS.Node.hasNode param 'node' is null or undefined"; + } + + var type = typeof node; + var nodeGot; + + if (type == "number") { + nodeGot = this.getNodeAt(node); + + } else if (type == "string") { + nodeGot = this.getNode(node); + + } else { + throw "SceneJS.Node.hasNode param 'node' should be either an index number or an ID string"; + } + + return (nodeGot != undefined && nodeGot != null); +}; + +/** Selects a child node matching given ID or index + * @param {Number|String} node Child node index or ID + */ +SceneJS.Node.prototype.node = function (node) { + + if (node === null || node === undefined) { + throw "SceneJS.Node.node param 'node' is null or undefined"; + } + + var type = typeof node; + var nodeGot; + + if (type == "number") { + nodeGot = this.getNodeAt(node); + + } else if (type == "string") { + nodeGot = this.getNode(node); + + } else { + throw "SceneJS.Node.node param 'node' should be either an index number or an ID string"; + } + + if (!nodeGot) { + throw "SceneJS.Node.node - node not found: '" + node + "'"; + } + + return nodeGot; +}; + +/** + * Iterates over sub-nodes of the selected node, executing a function + * for each. With the optional options object we can configure is depth-first or breadth-first order. + * If neither, then only the child nodes are iterated. + * If the function returns true at any node, then traversal stops and a selector is + * returned for that node. + * @param {Function(index, node)} fn Function to execute on each child node + * @return {Object} Selector for selected node, if any + */ +SceneJS.Node.prototype.eachNode = function (fn, options) { + + if (!fn) { + throw "SceneJS.Node.eachNode param 'fn' is null or undefined"; + } + + if (typeof fn != "function") { + throw "SceneJS.Node.eachNode param 'fn' should be a function"; + } + + var stoppedNode; + options = options || {}; + var count = 0; + + if (options.andSelf) { + if (fn.call(this, count++) === true) { + return this; + } + } + + if (!options.depthFirst && !options.breadthFirst) { + stoppedNode = this._iterateEachNode(fn, this, count); + + } else if (options.depthFirst) { + stoppedNode = this._iterateEachNodeDepthFirst(fn, this, count, false); // Not below root yet + + } else { + // TODO: breadth-first + } + + if (stoppedNode) { + return stoppedNode; + } + + return undefined; // IDE happy now +}; + +SceneJS.Node.prototype.numNodes = function () { + return this.nodes.length; +}; + +SceneJS.Node.prototype._iterateEachNode = function (fn, node, count) { + + var len = node.nodes.length; + var child; + + for (var i = 0; i < len; i++) { + child = node.nodes[i]; + + if (fn.call(child, count++) === true) { + return child; + } + } + + return null; +}; + +SceneJS.Node.prototype._iterateEachNodeDepthFirst = function (fn, node, count, belowRoot) { + + if (belowRoot) { + + /* Visit this node - if we are below root, because entry point visits the root + */ + if (fn.call(node, count++) === true) { + return node; + } + } + + belowRoot = true; + + /* Iterate nodes + */ + var len = node.nodes.length; + var child; + for (var i = 0; i < len; i++) { + child = this._iterateEachNodeDepthFirst(fn, node.nodes[i], count, belowRoot); + if (child) { + return child; + } + } + + return null; +}; + +/** Returns either all child or all sub-nodes of the given type, depending on whether search is recursive or not. + */ +SceneJS.Node.prototype.findNodesByType = function (type, recursive) { + return this._findNodesByType(type, [], recursive); +}; + +SceneJS.Node.prototype._findNodesByType = function (type, list, recursive) { + var i; + for (i = 0; i < this.nodes.length; i++) { + var node = this.nodes[i]; + if (node.type == type) { + list.push(node); + } + } + if (recursive) { + for (i = 0; i < this.nodes.length; i++) { + this.nodes[i]._findNodesByType(type, list, recursive); + } + } + return list; +}; + +/** Finds the first node on path up to root whose type equals that given + */ +SceneJS.Node.prototype.findParentByType = function (type) { + var parent = this.parent; + while (parent && parent.type != type) { + parent = parent.parent; + } + return parent; +}; + + +/** + * Given a map of name-value pairs, calls a getter method for each name, + * feeding into it the corresponding value. + * + * @param attr + * @param value + * @return {*} + */ +SceneJS.Node.prototype.set = function (attr, value) { + + if (typeof attr == "object") { // Attribute map - recurse for each attribute + for (var subAttr in attr) { + if (attr.hasOwnProperty(subAttr)) { + this.set(subAttr, attr[subAttr]); + } + } + return; + } + + if (this._set) { + var method = this._set[attr]; + if (method) { + return method.call(this, value); + } + } + + return this._createAccessor("set", attr, value); +}; + +SceneJS.Node.prototype.get = function (attr) { + + if (this._get) { + var method = this._get[attr]; + if (method) { + return method.call(this); + } + } + + return this._createAccessor("get", attr); +}; + +SceneJS.Node.prototype.add = function (attr, value) { + + if (typeof attr == "object") { // Attribute map - recurse for each attribute + for (var subAttr in attr) { + if (attr.hasOwnProperty(subAttr)) { + this.add(subAttr, attr[subAttr]); + } + } + return; + } + + if (this._add) { + var method = this._add[attr]; + if (method) { + return method.call(this, value); + } + } + + return this._createAccessor("add", attr, value); +}; + +SceneJS.Node.prototype.inc = function (attr, value) { + + if (typeof attr == "object") { // Attribute map - recurse for each attribute + for (var subAttr in attr) { + if (attr.hasOwnProperty(subAttr)) { + this.inc(subAttr, attr[subAttr]); + } + } + return; + } + + if (this._inc) { + var method = this._inc[attr]; + if (method) { + return method.call(this, value); + } + } + + return this._createAccessor("inc", attr, value); +}; + +SceneJS.Node.prototype.insert = function (attr, value) { + + if (typeof attr == "object") { // Attribute map - recurse for each attribute + for (var subAttr in attr) { + if (attr.hasOwnProperty(subAttr)) { + this.insert(subAttr, attr[subAttr]); + } + } + return; + } + + if (this._set) { + var method = this._set[attr]; + if (method) { + return method.call(this, value); + } + } + + return this._createAccessor("insert", attr, value); +}; + +SceneJS.Node.prototype.remove = function (attr, value) { + + if (typeof attr == "object") { // Attribute map - recurse for each attribute + for (var subAttr in attr) { + if (attr.hasOwnProperty(subAttr)) { + this.remove(subAttr, attr[subAttr]); + } + } + return; + } + + if (this._remove) { + var method = this._remove[attr]; + if (method) { + return method.call(this, value); + } + } + + return this._createAccessor("remove", attr, value); +}; + +SceneJS.Node.prototype._createAccessor = function (op, attr, value) { + + var methodName = op + attr.substr(0, 1).toUpperCase() + attr.substr(1); + + var method = this[methodName]; + + if (!method) { + throw "Method not found on node: '" + methodName + "'"; + } + + //var proto = (this.type == "node") ? SceneJS.Node.prototype : this._engine.nodeTypes[this.type].prototype; + + var proto = this.__proto__; + + var accessors; + switch (op) { + case "set": + accessors = (proto._set || (proto._set = {})); + break; + + case "get": + accessors = (proto._get || (proto._get = {})); + break; + + case "inc": + accessors = (proto._inc || (proto._inc = {})); + break; + + case "add": + accessors = (proto._add || (proto._add = {})); + break; + + case "insert": + accessors = (proto._insert || (proto._insert = {})); + break; + + case "remove": + accessors = (proto._remove || (proto._remove = {})); + break; + } + + accessors[attr] = method; + + return method.call(this, value); // value can be undefined +}; + +/** Binds a listener to an event on the selected node + * + * @param {String} name Event name + * @param {Function} handler Event handler + */ +SceneJS.Node.prototype.bind = function (name, handler) { + + if (!name) { + throw "SceneJS.Node.bind param 'name' null or undefined"; + } + + if (typeof name != "string") { + throw "SceneJS.Node.bind param 'name' should be a string"; + } + + if (!handler) { + throw "SceneJS.Node.bind param 'handler' null or undefined"; + } + + if (typeof handler != "function") { + throw "SceneJS.Node.bind param 'handler' should be a function"; + } + + this.addListener(name, handler, { scope:this }); + + this._engine.branchDirty(this); + + return handler; +}; + +/** + * Returns an object containing the attributes that were given when creating the node. Obviously, the map will have + * the current values, plus any attributes that were later added through set/add methods on the node + * + */ +SceneJS.Node.prototype.getJSON = function () { + return this; +}; + + +SceneJS.Node.prototype._compile = function (ctx) { + if (this.preCompile) { + this.preCompile(); + } + this._compileNodes(ctx); + if (this.postCompile) { + this.postCompile(); + } +}; + +SceneJS.Node.prototype._compileNodes = function (ctx) { + + var renderSubs = this._topicSubs["rendered"]; + + if (renderSubs) { + SceneJS_nodeEventsModule.preVisitNode(this); + } + +// var tickSubs = this._topicSubs["tick"]; +// +// if (tickSubs) { +// ctx.pubSubProxy.on("tick", function(event) { +// this.publish("tick", event); +// }); +// } + + var child; + + for (var i = 0, len = this.nodes.length; i < len; i++) { + + child = this.nodes[i]; + + child.branchDirty = child.branchDirty || this.branchDirty; // Compile subnodes if scene branch dirty + + if (child.dirty || child.branchDirty || this._engine.sceneDirty) { // Compile nodes that are flagged dirty + child._compile(ctx); + child.dirty = false; + child.branchDirty = false; + } + } + + if (renderSubs) { + SceneJS_nodeEventsModule.postVisitNode(this); + } +}; + + + +/** + * Destroys this node. It is marked for destruction; when the next scene traversal begins (or the current one ends) + * it will be destroyed and removed from it's parent. + */ +SceneJS.Node.prototype.destroy = function () { + + if (!this.destroyed) { + + if (this.parent) { + + /* Remove from parent's child node list + */ + for (var i = 0; i < this.nodes.length; i++) { + if (this.parent.nodes[i].id === this.id) { + this.parent.nodes.splice(i, 1); + break; + } + } + } + + // Remove publication + this._engine.scene.unpublish("nodes/" + this.id); + + /* Recusrsively destroy child nodes without + * bothering to remove them from their parents + */ + this._destroyTree(); + + /* Need object list recompilation on display + */ + this._engine.display.objectListDirty = true; + } + + return this; +}; + +SceneJS.Node.prototype._destroyTree = function () { + + this.destroyed = true; + + this._engine.destroyNode(this); // Release node object + + for (var i = 0, len = this.nodes.length; i < len; i++) { + this.nodes[i]._destroyTree(); + } +}; + +/** + * Performs the actual destruction of this node, calling the node's optional template destroy method + */ +SceneJS.Node.prototype._doDestroy = function () { + + if (this._destroy) { // Call destruction handler for each node subclass + this._destroy(); + } + + return this; +};;SceneJS_PubSubProxy = function (scene, proxy) { + this.scene = scene; + this.proxy = proxy; + +}; + + + +;/** + * @class Manages creation, recycle and destruction of {@link SceneJS.Node} instances + * @private + */ +var SceneJS_NodeFactory = function () { + + /** Nodes created by this factory + * @type {SceneJS_Map} + */ + this.nodes = new SceneJS_Map({}); +}; + +/** + * Scene graph node classes provided by the SceneJS_NodeFactory class + * + * @type {[SceneJS.Node]} + */ +SceneJS_NodeFactory.nodeTypes = {}; + +/** + * Subscribers waiting for node types + * @type {Object} + * @private + */ +SceneJS_NodeFactory._subs = {}; + +/** + * Creates a node class for instantiation by this factory + * + * @param {String} typeName Name of type, eg. "rotate" + * @param {String} coreTypeName Optional name of core type for the node, eg. "xform" - defaults to type name of node + * @param {Function} [augment] Augments the basic node type with our custom node methods + * @returns The new node class + */ +SceneJS_NodeFactory.createNodeType = function (typeName, coreTypeName, augment) { + if (SceneJS_NodeFactory.nodeTypes[typeName]) { + throw "Node type already defined: " + typeName; + } + var nodeType = function () { // Create the class + SceneJS.Node.apply(this, arguments); + this.type = typeName; + }; + nodeType.prototype = new SceneJS.Node(); // Inherit from base class + nodeType.prototype.constructor = nodeType; + SceneJS_NodeFactory.nodeTypes[typeName] = nodeType; + + var type = SceneJS_NodeFactory.nodeTypes[typeName]; // Type has installed itself + if (!type) { + throw "Node type plugin did not install itself correctly"; + } + // Augment the basic node type + if (augment) { + augment(nodeType); + } + // Notify subscribers waiting for the type + var subs = SceneJS_NodeFactory._subs[typeName]; + if (subs) { + while (subs.length > 0) { + subs.pop()(type); + } + delete subs[typeName]; + } + return nodeType; +}; + +/** + * + */ +SceneJS_NodeFactory.prototype.getNode = function (engine, json, core, ok) { + json.type = json.type || "node"; // Nodes are SceneJS.Node type by default + var nodeType; + if (json.type == "node") { + nodeType = SceneJS.Node; + } else { + nodeType = SceneJS_NodeFactory.nodeTypes[json.type]; + } + if (nodeType) { + return this._createNode(nodeType, engine, json, core, ok); + } else { + var self = this; + this._getType( + engine, + json.type, + function (nodeType) { + self._createNode(nodeType, engine, json, core, ok); + }); + } +}; + +SceneJS_NodeFactory.prototype._createNode = function (nodeType, engine, json, core, ok) { + var node = new nodeType(); + var id = json.id || json.nodeId; // 'id' and 'nodeId' are aliases + if (id) { + this.nodes.addItem(id, node); + } else { + id = this.nodes.addItem(node); + } + node._construct(engine, core, json, id); // Instantiate node + if (ok) { + ok(node); + } + return node; +}; + +/** + * Returns installed type of given type and ID + */ +SceneJS_NodeFactory.prototype._getType = function (engine, typeName, ok) { + var type = SceneJS_NodeFactory.nodeTypes[typeName]; + if (type) { + ok(type); + return; + } + var subs = SceneJS_NodeFactory._subs[typeName] || (SceneJS_NodeFactory._subs[typeName] = []); + subs.push(ok); + if (subs.length > 1) { // Not first sub + return; + } + var taskId = SceneJS_sceneStatusModule.taskStarted(engine.scene, "Loading plugin"); + subs.push(function () { + SceneJS_sceneStatusModule.taskFinished(taskId); + }); + var self = this; + var typePath = SceneJS_configsModule.configs.pluginPath; + if (!typePath) { + throw "no typePath config"; // Build script error - should create this config + } + this._loadScript(typePath + "/node/" + typeName + ".js", + function () { + SceneJS_sceneStatusModule.taskFailed(taskId); + }); +}; + +SceneJS_NodeFactory.prototype._loadScript = function (url, error) { + var script = document.createElement("script"); + script.type = "text/javascript"; + script.src = url; + script.onerror = error; + document.getElementsByTagName("head")[0].appendChild(script); +}; + +/** + * Releases a node back to this factory + */ +SceneJS_NodeFactory.prototype.putNode = function (node) { + this.nodes.removeItem(node.id); +}; +;(function () { + + var defaultMatrix = SceneJS_math_perspectiveMatrix4( + 45, // fovy + 1, // aspect + 0.1, // near + 10000); // far + + var defaultMat = new Float32Array(defaultMatrix); + + // The default state core singleton for {@link SceneJS.Camera} nodes + var defaultCore = { + type: "camera", + stateId: SceneJS._baseStateId++, + matrix: defaultMatrix, + mat: defaultMat, + optics: { + type: "perspective", + fovy: 45.0, + aspect: 1.0, + near: 0.1, + far: 10000.0 + }, + checkAspect: function (core, aspect) { + if (core.optics.aspect != aspect) { + core.optics.aspect = aspect; + rebuildCore(this); + } + } + }; + + var coreStack = []; + var stackLen = 0; + + // Set default core on the display at the start of each new scene compilation + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.projTransform = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines the projection transform to apply to the {@link SceneJS.Geometry} nodes in its subgraph + * @extends SceneJS.Node + */ + SceneJS.Camera = SceneJS_NodeFactory.createNodeType("camera"); + + SceneJS.Camera.prototype._init = function (params) { + if (this._core.useCount == 1) { + + params.optics = params.optics || {}; + var canvas = this.getScene().getCanvas(); + params.optics.aspect = canvas.width / canvas.height; + this.setOptics(params.optics); // Can be undefined + + if (params.pan) { + this.setPan(params.pan); + } + + var self = this; + + this._canvasSizeSub = this.getScene().on("canvasSize", + function (c) { + self._core.optics.aspect = c.aspect; + rebuildCore(self._core); + self._engine.display.imageDirty = true; + }); + } + }; + + /** + * Returns the default camera projection matrix + * @return {Float32Array} + */ + SceneJS.Camera.getDefaultMatrix = function () { + return defaultMat; + }; + + SceneJS.Camera.prototype.setOptics = function (optics) { + var core = this._core; + if (!optics) { + core.optics = { + type: "perspective", + fovy: 60.0, + aspect: 1.0, + near: 0.1, + far: 10000.0 + }; + } else { + var type = optics.type || core.optics.type || "perspective"; + if (type == "ortho") { + core.optics = SceneJS._applyIf(SceneJS_math_ORTHO_OBJ, { + type: type, + left: optics.left, + bottom: optics.bottom, + near: optics.near, + right: optics.right, + top: optics.top, + far: optics.far + }); + } else if (type == "frustum") { + core.optics = { + type: type, + left: optics.left || -1.0, + bottom: optics.bottom || -1.0, + near: optics.near || 0.1, + right: optics.right || 1.00, + top: optics.top || 1.0, + far: optics.far || 10000.0 + }; + } else if (type == "perspective") { + core.optics = { + type: type, + fovy: optics.fovy || 60.0, + aspect: optics.aspect == undefined ? 1.0 : optics.aspect, + near: optics.near || 0.1, + far: optics.far || 10000.0 + }; + } else if (!optics.type) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Camera configuration invalid: optics type not specified - " + + "supported types are 'perspective', 'frustum' and 'ortho'"); + } else { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Camera configuration invalid: optics type not supported - " + + "supported types are 'perspective', 'frustum' and 'ortho'"); + } + } + this._core.optics.pan = optics.pan; + rebuildCore(this._core); + this.publish("matrix", this._core.matrix); + this._engine.display.imageDirty = true; + }; + + SceneJS.Camera.prototype.setPan = function (pan) { + this._core.pan = pan; + rebuildCore(this._core); + this.publish("matrix", this._core.matrix); + this._engine.display.imageDirty = true; + }; + + function rebuildCore(core) { + var optics = core.optics; + if (optics.type == "ortho") { + core.matrix = SceneJS_math_orthoMat4c( + optics.left, + optics.right, + optics.bottom, + optics.top, + optics.near, + optics.far); + + } else if (optics.type == "frustum") { + core.matrix = SceneJS_math_frustumMatrix4( + optics.left, + optics.right, + optics.bottom, + optics.top, + optics.near, + optics.far); + + } else if (optics.type == "perspective") { + core.matrix = SceneJS_math_perspectiveMatrix4( + optics.fovy * Math.PI / 180.0, + optics.aspect, + optics.near, + optics.far); + } + + if (core.pan) { + // Post-multiply a screen-space pan + var pan = core.pan; + var panMatrix = SceneJS_math_translationMat4v([pan.x || 0, pan.y || 0, pan.z || 0]); + core.matrix = SceneJS_math_mulMat4(panMatrix, core.matrix, []); + } + + if (!core.mat) { + core.mat = new Float32Array(core.matrix); + } else { + core.mat.set(core.matrix); + } + } + + SceneJS.Camera.prototype.getOptics = function () { + var optics = {}; + for (var key in this._core.optics) { + if (this._core.optics.hasOwnProperty(key)) { + optics[key] = this._core.optics[key]; + } + } + return optics; + }; + + SceneJS.Camera.prototype.getMatrix = function () { + return this._core.matrix.slice(0); + }; + + /** + * Compiles this camera node, setting this node's state core on the display, compiling sub-nodes, + * then restoring the previous camera state core back onto the display on exit. + */ + SceneJS.Camera.prototype._compile = function (ctx) { + this._engine.display.projTransform = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.projTransform = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + SceneJS.Camera.prototype._destroy = function () { + this.getScene().off(this._canvasSizeSub); + }; +})();;(function() { + + /** + * The default state core singleton for {@link SceneJS.Clips} nodes + */ + var defaultCore = { + type: "clips", + stateId: SceneJS._baseStateId++, + empty: true, + hash: "", + clips : [] + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function(params) { + params.engine.display.clips = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines one or more arbitrarily-aligned clip planes to clip the {@link SceneJS.Geometry} nodes in its subgraph + * @extends SceneJS.Node + */ + SceneJS.Clips = SceneJS_NodeFactory.createNodeType("clips"); + + SceneJS.Clips.prototype._init = function(params) { + + if (this._core.useCount == 1) { // This node defines the resource + + var clips = params.clips; + + if (!clips) { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "clips node attribute missing : 'clips'"); + } + + this._core.clips = this._core.clips || []; + + for (var i = 0, len = clips.length; i < len; i++) { + this._setClip(i, clips[i]); + } + } + }; + + SceneJS.Clips.prototype.setClips = function(clips) { + var indexNum; + for (var index in clips) { + if (clips.hasOwnProperty(index)) { + if (index != undefined || index != null) { + indexNum = parseInt(index); + if (indexNum < 0 || indexNum >= this._core.clips.length) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Invalid argument to set 'clips': index out of range (" + this._core.clips.length + " clips defined)"); + } + this._setClip(indexNum, clips[index] || {}); + } + } + } + this._engine.display.imageDirty = true; + }; + + SceneJS.Clips.prototype._setClip = function(index, cfg) { + + var clip = this._core.clips[index] || (this._core.clips[index] = {}); + + clip.normalAndDist = [cfg.x || 0, cfg.y || 0, cfg.z || 0, cfg.dist || 0]; + + var mode = cfg.mode || clip.mode || "disabled"; + + if (mode != "inside" && mode != "outside" && mode != "disabled") { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'"); + } + clip.mode = mode; + + this._core.hash = null; + }; + + SceneJS.Clips.prototype._compile = function(ctx) { + + if (!this._core.hash) { + this._core.hash = this._core.clips.length; + } + + this._engine.display.clips = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.clips = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + +})();;(function () { + + // The default state core singleton for {@link SceneJS.Enable} nodes + var defaultCore = { + stateId:SceneJS._baseStateId++, + type:"enable", + enabled:true + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.enable = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which enables or disables rendering for its subgraph + * @extends SceneJS.Node + */ + SceneJS.Enable = SceneJS_NodeFactory.createNodeType("enable"); + + SceneJS.Enable.prototype._init = function (params) { + if (this._core.useCount == 1) { // This node is first to reference the state core, so sets it up + this._core.enabled = true; + if (params.enabled != undefined) { + this.setEnabled(params.enabled); + } + } + }; + + SceneJS.Enable.prototype.setEnabled = function (enabled) { + if (enabled !== this._core.enabled) { + this._core.enabled = enabled; + this._engine.display.drawListDirty = true; + this.publish("enabled", enabled); + } + return this; + }; + + SceneJS.Enable.prototype.getEnabled = function () { + return this._core.enabled; + }; + + SceneJS.Enable.prototype._compile = function (ctx) { + this._engine.display.enable = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.enable = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})();;(function() { + + /** + * The default state core singleton for {@link SceneJS.Flags} nodes + */ + var defaultCore = { + + stateId: SceneJS._baseStateId++, + type: "flags", + + picking : true, // Picking enabled + clipping : true, // User-defined clipping enabled + enabled : true, // Node not culled from traversal + transparent: false, // Node transparent - works in conjunction with matarial alpha properties + backfaces: true, // Show backfaces + frontface: "ccw", // Default vertex winding for front face + reflective: true, // Reflects reflection node cubemap, if it exists, by default. + solid: true, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect + hash: "refl;s;" + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function(params) { + params.engine.display.flags = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which sets rendering mode flags for its subgraph + * @extends SceneJS.Node + */ + SceneJS.Flags = SceneJS_NodeFactory.createNodeType("flags"); + + SceneJS.Flags.prototype._init = function(params) { + + if (this._core.useCount == 1) { // This node is first to reference the state core, so sets it up + + this._core.picking = true; // Picking enabled + this._core.clipping = true; // User-defined clipping enabled + this._core.enabled = true; // Node not culled from traversal + this._core.transparent = false; // Node transparent - works in conjunction with matarial alpha properties + this._core.backfaces = true; // Show backfaces + this._core.frontface = "ccw"; // Default vertex winding for front face + this._core.reflective = true; // Reflects reflection node cubemap, if it exists, by default. + this._core.solid = true; // Renders backfaces without texture or shading, for a cheap solid cross-section effect + if (params.flags) { // 'flags' property is actually optional in the node definition + this.setFlags(params.flags); + } + } + }; + + SceneJS.Flags.prototype.setFlags = function(flags) { + + var core = this._core; + + if (flags.picking != undefined) { + core.picking = !!flags.picking; + this._engine.display.drawListDirty = true; + } + + if (flags.clipping != undefined) { + core.clipping = !!flags.clipping; + this._engine.display.imageDirty = true; + } + + if (flags.enabled != undefined) { + core.enabled = !!flags.enabled; + this._engine.display.drawListDirty = true; + } + + if (flags.transparent != undefined) { + core.transparent = !!flags.transparent; + this._engine.display.stateSortDirty = true; + } + + if (flags.backfaces != undefined) { + core.backfaces = !!flags.backfaces; + this._engine.display.imageDirty = true; + } + + if (flags.frontface != undefined) { + core.frontface = flags.frontface; + this._engine.display.imageDirty = true; + } + + if (flags.reflective != undefined) { + core.reflective = flags.reflective; + core.hash = core.reflective ? "refl" : ""; + this._engine.branchDirty(this); + } + + if (flags.solid != undefined) { + core.solid = flags.solid; + core.hash = core.reflective ? "refl" : ""; + this._engine.branchDirty(this); + } + + return this; + }; + + SceneJS.Flags.prototype.addFlags = function(flags) { + return this.setFlags(flags); + // var core = this._core; + // if (flags.picking != undefined) core.picking = flags.picking; + // if (flags.clipping != undefined) core.clipping = flags.clipping; + // if (flags.enabled != undefined) core.enabled = flags.enabled; + // if (flags.transparent != undefined) core.transparent = flags.transparent; + // if (flags.backfaces != undefined) core.backfaces = flags.backfaces; + // if (flags.frontface != undefined) core.frontface = flags.frontface; + // if (flags.backfaceLighting != undefined) core.backfaceLighting = flags.backfaceLighting; + // if (flags.backfaceTexturing != undefined) core.backfaceTexturing = flags.backfaceTexturing; + // return this; + }; + + SceneJS.Flags.prototype.getFlags = function() { + var core = this._core; + return { + picking : core.picking, + clipping : core.clipping, + enabled : core.enabled, + transparent: core.transparent, + backfaces: core.backfaces, + frontface: core.frontface, + reflective: core.reflective, + solid: core.solid + }; + }; + + SceneJS.Flags.prototype.setPicking = function(picking) { + picking = !!picking; + if (this._core.picking != picking) { + this._core.picking = picking; + this._engine.display.drawListDirty = true; + } + return this; + }; + + SceneJS.Flags.prototype.getPicking = function() { + return this._core.picking; + }; + + SceneJS.Flags.prototype.setClipping = function(clipping) { + clipping = !!clipping; + if (this._core.clipping != clipping) { + this._core.clipping = clipping; + this._engine.display.imageDirty = true; + } + return this; + }; + + SceneJS.Flags.prototype.getClipping = function() { + return this._core.clipping; + }; + + SceneJS.Flags.prototype.setEnabled = function(enabled) { + enabled = !!enabled; + if (this._core.enabled != enabled) { + this._core.enabled = enabled; + this._engine.display.drawListDirty = true; + } + return this; + }; + + SceneJS.Flags.prototype.getEnabled = function() { + return this._core.enabled; + }; + + SceneJS.Flags.prototype.setTransparent = function(transparent) { + transparent = !!transparent; + if (this._core.transparent != transparent) { + this._core.transparent = transparent; + this._engine.display.stateOrderDirty = true; + } + return this; + }; + + SceneJS.Flags.prototype.getTransparent = function() { + return this._core.transparent; + }; + + SceneJS.Flags.prototype.setBackfaces = function(backfaces) { + backfaces = !!backfaces; + if (this._core.backfaces != backfaces) { + this._core.backfaces = backfaces; + this._engine.display.imageDirty = true; + } + return this; + }; + + SceneJS.Flags.prototype.getBackfaces = function() { + return this._core.backfaces; + }; + + SceneJS.Flags.prototype.setFrontface = function(frontface) { + if (this._core.frontface != frontface) { + this._core.frontface = frontface; + this._engine.display.imageDirty = true; + } + return this; + }; + + SceneJS.Flags.prototype.getFrontface = function() { + return this._core.frontface; + }; + + SceneJS.Flags.prototype.setReflective = function(reflective) { + reflective = !!reflective; + if (this._core.reflective != reflective) { + this._core.reflective = reflective; + this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";"; + this._engine.branchDirty(this); + } + return this; + }; + + SceneJS.Flags.prototype.getReflective = function() { + return this._core.reflective; + }; + + SceneJS.Flags.prototype.setSolid = function(solid) { + solid = !!solid; + if (this._core.solid != solid) { + this._core.solid = solid; + this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s" : ";"; + this._engine.branchDirty(this); + } + return this; + }; + + SceneJS.Flags.prototype.getSolid = function() { + return this._core.solid; + }; + + + SceneJS.Flags.prototype._compile = function(ctx) { + this._engine.display.flags = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.flags = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})(); +;new (function () { + + var defaultCore = { + type: "renderTarget", + stateId: SceneJS._baseStateId++, + targets: null + }; + + // Map of nodes to cores, for reallocation on WebGL context restore + var nodeCoreMap = {}; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.renderTarget = defaultCore; + stackLen = 0; + }); + + // Reallocate VBOs when context restored after loss + SceneJS_events.addListener( + SceneJS_events.WEBGL_CONTEXT_RESTORED, + function () { + for (var nodeId in nodeCoreMap) { + if (nodeCoreMap.hasOwnProperty(nodeId)) { + nodeCoreMap[nodeId]._core.renderBuf.webglRestored(); + } + } + }); + + SceneJS.ColorTarget = SceneJS_NodeFactory.createNodeType("colorTarget"); + + SceneJS.ColorTarget.prototype._init = function (params) { + nodeCoreMap[this._core.coreId] = this; + this._core.bufType = "color"; + this._core.renderBuf = new SceneJS._webgl.RenderBuffer({ canvas: this._engine.canvas }); + }; + + SceneJS.ColorTarget.prototype._compile = function (ctx) { + if (!this.__core) { + this.__core = this._engine._coreFactory.getCore("renderTarget"); + } + var parentCore = this._engine.display.renderTarget; + if (!this._core.empty) { + this.__core.targets = (parentCore && parentCore.targets) ? parentCore.targets.concat([this._core]) : [this._core]; + } + coreStack[stackLen++] = this.__core; + this._engine.display.renderTarget = this.__core; + this._compileNodes(ctx); + this._engine.display.renderTarget = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + + SceneJS.ColorTarget.prototype._destroy = function () { + if (this._core) { + if (this._core.renderBuf) { + this._core.renderBuf.destroy(); + } + delete nodeCoreMap[this._core.coreId]; + } + }; +})();;new (function () { + + var defaultCore = { + type: "renderTarget", + stateId: SceneJS._baseStateId++, + targets: null + }; + + // Map of nodes to cores, for reallocation on WebGL context restore + var nodeCoreMap = {}; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.renderTarget = defaultCore; + stackLen = 0; + }); + + // Reallocate VBOs when context restored after loss + SceneJS_events.addListener( + SceneJS_events.WEBGL_CONTEXT_RESTORED, + function () { + for (var nodeId in nodeCoreMap) { + if (nodeCoreMap.hasOwnProperty(nodeId)) { + nodeCoreMap[nodeId]._buildNodeCore(); + } + } + }); + + SceneJS.DepthTarget = SceneJS_NodeFactory.createNodeType("depthTarget"); + + SceneJS.DepthTarget.prototype._init = function (params) { + nodeCoreMap[this._core.coreId] = this; + this._core.bufType = "depth"; + this._core.renderBuf = new SceneJS._webgl.RenderBuffer({ canvas: this._engine.canvas }); + }; + + SceneJS.DepthTarget.prototype._compile = function (ctx) { + if (!this.__core) { + this.__core = this._engine._coreFactory.getCore("renderTarget"); + } + var parentCore = this._engine.display.renderTarget; + if (!this._core.empty) { + this.__core.targets = (parentCore && parentCore.targets) ? parentCore.targets.concat([this._core]) : [this._core]; + } + coreStack[stackLen++] = this.__core; + this._engine.display.renderTarget = this.__core; + this._compileNodes(ctx); + this._engine.display.renderTarget = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + + SceneJS.DepthTarget.prototype._destroy = function () { + if (this._core) { + if (this._core.renderBuf) { + this._core.renderBuf.destroy(); + } + delete nodeCoreMap[this._core.coreId]; + } + }; +})();;new (function () { + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function () { + stackLen = 0; + }); + + /** + * @class Scene graph node that defines geometry. + * @extends SceneJS.Node + * When this node is at a leaf, it defines a scene object which inherits the state set up by all the nodes above it + * on the path up to the root. These nodes can be nested, so that child geometries inherit arrays + * defined by parent geometries. + */ + SceneJS.Geometry = SceneJS_NodeFactory.createNodeType("geometry"); + + SceneJS.Geometry.prototype._init = function (params) { + + if (this._core.useCount == 1) { // This node defines the core + + this._initNodeCore(params, { + origin: params.origin, + scale: params.scale, + autoNormals: params.normals == "auto" + }); + + this._buildNodeCore(this._engine.canvas.gl, this._core); + + var self = this; + + this._core.webglRestored = function () { + self._buildNodeCore(self._engine.canvas.gl, self._core); + }; + + } + }; + + /** + * Convert JSON arrays into typed arrays, + * apply optional baked Model-space transforms to positions + */ + SceneJS.Geometry.prototype._initNodeCore = function (data, options) { + + var self = this; + + options = options || {}; + + var primitive = data.primitive || "triangles"; + var core = this._core; + var IndexArrayType = this._engine.canvas.UINT_INDEX_ENABLED ? Uint32Array : Uint16Array; + + core.primitive = this._getPrimitiveType(primitive); + + // Generate normals + if (data.normals) { + if (primitive == "triangles") { + if (data.normals === "auto" || data.normals === true) { + if (data.positions && data.indices) { + this._buildNormals(data); // Auto normal generation - build normals array + } + } + } + } + + // Create typed arrays, apply any baked transforms + core.arrays = { + positions: data.positions + ? new Float32Array((options.scale || options.origin) + ? this._applyOptions(data.positions, options) + : data.positions) : undefined, + normals: data.normals ? new Float32Array(data.normals) : undefined, + uv: data.uv ? new Float32Array(data.uv) : undefined, + uv2: data.uv2 ? new Float32Array(data.uv2) : undefined, + colors: data.colors ? new Float32Array(data.colors) : undefined, + indices: data.indices ? new IndexArrayType(data.indices) : undefined + }; + + delete data.positions; + delete data.normals; + delete data.uv; + delete data.uv2; + delete data.indices; + delete data.colors; + + // Lazy-build tangents, only when needed as rendering + core.getTangentBuf = function () { + if (core.tangentBuf) { + return core.tangentBuf; + } + var arrays = core.arrays; + if (arrays.positions && arrays.indices && arrays.uv) { + var gl = self._engine.canvas.gl; + var tangents = new Float32Array(self._buildTangents(arrays)); // Build tangents array; + core.arrays.tangents = tangents; + var usage = gl.STATIC_DRAW; + return core.tangentBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, tangents, tangents.length, 3, usage); + } + } + }; + + /** + * Returns WebGL constant for primitive name + */ + SceneJS.Geometry.prototype._getPrimitiveType = function (primitive) { + + var gl = this._engine.canvas.gl; + + switch (primitive) { + + case "points": + return gl.POINTS; + + case "lines": + return gl.LINES; + + case "line-loop": + return gl.LINE_LOOP; + + case "line-strip": + return gl.LINE_STRIP; + + case "triangles": + return gl.TRIANGLES; + + case "triangle-strip": + return gl.TRIANGLE_STRIP; + + case "triangle-fan": + return gl.TRIANGLE_FAN; + + default: + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "geometry primitive unsupported: '" + + primitive + + "' - supported types are: 'points', 'lines', 'line-loop', " + + "'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'"); + } + }; + + /** + * Apply baked Model-space transformations to give position array + */ + SceneJS.Geometry.prototype._applyOptions = function (positions, options) { + + var positions2 = positions.slice ? positions.slice(0) : new Float32Array(positions); // HACK + + if (options.scale) { + + var scaleX = options.scale.x != undefined ? options.scale.x : 1.0; + var scaleY = options.scale.y != undefined ? options.scale.y : 1.0; + var scaleZ = options.scale.z != undefined ? options.scale.z : 1.0; + + for (var i = 0, len = positions2.length; i < len; i += 3) { + positions2[i ] *= scaleX; + positions2[i + 1] *= scaleY; + positions2[i + 2] *= scaleZ; + } + } + + if (options.origin) { + + var originX = options.origin.x != undefined ? options.origin.x : 0.0; + var originY = options.origin.y != undefined ? options.origin.y : 0.0; + var originZ = options.origin.z != undefined ? options.origin.z : 0.0; + + for (var i = 0, len = positions2.length; i < len; i += 3) { + positions2[i ] -= originX; + positions2[i + 1] -= originY; + positions2[i + 2] -= originZ; + } + } + + return positions2; + }; + + /** + * Destroy vertex buffers associated with given core + */ + var destroyBuffers = function (core) { + if (core.vertexBuf) { + core.vertexBuf.destroy(); + core.vertexBuf = null; + } + + if (core.normalBuf) { + core.normalBuf.destroy(); + core.normalBuf = null; + } + + if (core.uvBuf) { + core.uvBuf.destroy(); + core.uvBuf = null; + } + + if (core.uvBuf2) { + core.uvBuf2.destroy(); + core.uvBuf2 = null; + } + + if (core.colorBuf) { + core.colorBuf.destroy(); + core.colorBuf = null; + } + + if (core.tangentBuf) { + core.tangentBuf.destroy(); + core.tangentBuf = null; + } + + if (core.indexBuf) { + core.indexBuf.destroy(); + core.indexBuf = null; + } + + if (core.interleavedBuf) { + core.interleavedBuf.destroy(); + core.interleavedBuf = null; + } + }; + + /** + * Allocates WebGL buffers for geometry arrays + * + * In addition to initially allocating those, this is called to reallocate them after + * WebGL context is regained after being lost. + */ + SceneJS.Geometry.prototype._buildNodeCore = function (gl, core) { + + var usage = gl.STATIC_DRAW; //var usage = (!arrays.fixed) ? gl.STREAM_DRAW : gl.STATIC_DRAW; + + try { // TODO: Modify usage flags in accordance with how often geometry is evicted + + var arrays = core.arrays; + var canInterleave = (SceneJS.getConfigs("enableInterleaving") !== false); + var dataLength = 0; + var interleavedValues = 0; + var interleavedArrays = []; + var interleavedArrayStrides = []; + + var prepareInterleaveBuffer = function (array, strideInElements) { + if (dataLength == 0) { + dataLength = array.length / strideInElements; + } else if (array.length / strideInElements != dataLength) { + canInterleave = false; + } + interleavedArrays.push(array); + interleavedArrayStrides.push(strideInElements); + interleavedValues += strideInElements; + return (interleavedValues - strideInElements) * 4; + }; + + if (arrays.positions) { + if (canInterleave) { + core.interleavedPositionOffset = prepareInterleaveBuffer(arrays.positions, 3); + } + core.vertexBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, arrays.positions, arrays.positions.length, 3, usage); + } + + if (arrays.normals) { + if (canInterleave) { + core.interleavedNormalOffset = prepareInterleaveBuffer(arrays.normals, 3); + } + core.normalBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, arrays.normals, arrays.normals.length, 3, usage); + } + + if (arrays.uv) { + if (canInterleave) { + core.interleavedUVOffset = prepareInterleaveBuffer(arrays.uv, 2); + } + core.uvBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, arrays.uv, arrays.uv.length, 2, usage); + } + + if (arrays.uv2) { + if (canInterleave) { + core.interleavedUV2Offset = prepareInterleaveBuffer(arrays.uv2, 2); + } + core.uvBuf2 = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, arrays.uv2, arrays.uv2.length, 2, usage); + } + + if (arrays.colors) { + if (canInterleave) { + core.interleavedColorOffset = prepareInterleaveBuffer(arrays.colors, 4); + } + core.colorBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, arrays.colors, arrays.colors.length, 4, usage); + } + + if (arrays.indices) { + core.indexBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, arrays.indices, arrays.indices.length, 1, usage); + } + + if (interleavedValues > 0 && canInterleave) { + // We'll place the vertex attribute data interleaved in this array. + // This will enable us to use less bindBuffer calls and make the data + // efficient to address on the GPU. + var interleaved = []; + + var arrayCount = interleavedArrays.length; + for (var i = 0; i < dataLength; ++i) { + for (var j = 0; j < arrayCount; ++j) { + var stride = interleavedArrayStrides[j]; + for (var k = 0; k < stride; ++k) { + interleaved.push(interleavedArrays[j][i * stride + k]); + } + } + } + core.interleavedStride = interleavedValues * 4; // in bytes + core.interleavedBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, new Float32Array(interleaved), interleaved.length, interleavedValues, usage); + core.interleavedBuf.dirty = false; + } + + } catch (e) { // Allocation failure - delete whatever buffers got allocated + destroyBuffers(core); + throw SceneJS_error.fatalError( + SceneJS.errors.ERROR, + "Failed to allocate geometry: " + e); + } + }; + + SceneJS.Geometry.prototype._updateArray = function (array, items, offset) { + + var arrayLen = array.length; + var itemsLen = items.length; + + if (itemsLen + offset > arrayLen) { + itemsLen -= (itemsLen + offset) - arrayLen; + } + + for (var i = offset, j = 0; j < itemsLen; i++, j++) { + array[i] = items[j]; + } + + }; + + /** Builds normal vectors from positions and indices + * @private + */ + SceneJS.Geometry.prototype._buildNormals = function (data) { + + var positions = data.positions; + var indices = data.indices; + var nvecs = new Array(positions.length / 3); + var j0; + var j1; + var j2; + var v1; + var v2; + var v3; + + for (var i = 0, len = indices.length - 3; i < len; i += 3) { + j0 = indices[i + 0]; + j1 = indices[i + 1]; + j2 = indices[i + 2]; + + v1 = [positions[j0 * 3 + 0], positions[j0 * 3 + 1], positions[j0 * 3 + 2]]; + v2 = [positions[j1 * 3 + 0], positions[j1 * 3 + 1], positions[j1 * 3 + 2]]; + v3 = [positions[j2 * 3 + 0], positions[j2 * 3 + 1], positions[j2 * 3 + 2]]; + + v2 = SceneJS_math_subVec4(v2, v1, [0, 0, 0, 0]); + v3 = SceneJS_math_subVec4(v3, v1, [0, 0, 0, 0]); + + var n = SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(v2, v3, [0, 0, 0, 0]), [0, 0, 0, 0]); + + if (!nvecs[j0]) nvecs[j0] = []; + if (!nvecs[j1]) nvecs[j1] = []; + if (!nvecs[j2]) nvecs[j2] = []; + + nvecs[j0].push(n); + nvecs[j1].push(n); + nvecs[j2].push(n); + } + + var normals = new Array(positions.length); + + // now go through and average out everything + for (var i = 0, len = nvecs.length; i < len; i++) { + var count = nvecs[i].length; + var x = 0; + var y = 0; + var z = 0; + for (var j = 0; j < count; j++) { + x += nvecs[i][j][0]; + y += nvecs[i][j][1]; + z += nvecs[i][j][2]; + } + normals[i * 3 + 0] = (x / count); + normals[i * 3 + 1] = (y / count); + normals[i * 3 + 2] = (z / count); + } + + data.normals = normals; + }; + + + /** + * Builds vertex tangent vectors from positions, UVs and indices + * + * Based on code by @rollokb, in his fork of webgl-obj-loader: + * https://github.com/rollokb/webgl-obj-loader + * + * @private + **/ + SceneJS.Geometry.prototype._buildTangents = function (arrays) { + + var positions = arrays.positions; + var indices = arrays.indices; + var uv = arrays.uv; + + var tangents = []; + + // The vertex arrays needs to be calculated + // before the calculation of the tangents + + for (var location = 0; location < indices.length; location += 3) { + + // Recontructing each vertex and UV coordinate into the respective vectors + + var index = indices[location]; + + var v0 = [positions[index * 3], positions[(index * 3) + 1], positions[(index * 3) + 2]]; + var uv0 = [uv[index * 2], uv[(index * 2) + 1]]; + + index = indices[location + 1]; + + var v1 = [positions[index * 3], positions[(index * 3) + 1], positions[(index * 3) + 2]]; + var uv1 = [uv[index * 2], uv[(index * 2) + 1]]; + + index = indices[location + 2]; + + var v2 = [positions[index * 3], positions[(index * 3) + 1], positions[(index * 3) + 2]]; + var uv2 = [uv[index * 2], uv[(index * 2) + 1]]; + + var deltaPos1 = SceneJS_math_subVec3(v1, v0, []); + var deltaPos2 = SceneJS_math_subVec3(v2, v0, []); + + var deltaUV1 = SceneJS_math_subVec2(uv1, uv0, []); + var deltaUV2 = SceneJS_math_subVec2(uv2, uv0, []); + + var r = 1 / ((deltaUV1[0] * deltaUV2[1]) - (deltaUV1[1] * deltaUV2[0])); + + var tangent = SceneJS_math_mulVec3Scalar( + SceneJS_math_subVec3( + SceneJS_math_mulVec3Scalar(deltaPos1, deltaUV2[1], []), + SceneJS_math_mulVec3Scalar(deltaPos2, deltaUV1[1], []), + [] + ), + r, + [] + ); + + // Average the value of the vectors outs + for (var v = 0; v < 3; v++) { + var addTo = indices[location + v]; + if (typeof tangents[addTo] != "undefined") { + tangents[addTo] = SceneJS_math_addVec3(tangents[addTo], tangent, []); + } else { + tangents[addTo] = tangent; + } + } + } + + // Deconstruct the vectors back into 1D arrays for WebGL + + var tangents2 = []; + + for (var i = 0; i < tangents.length; i++) { + tangents2 = tangents2.concat(tangents[i]); + } + + return tangents2; + }; + + SceneJS.Geometry.prototype.setSource = function (sourceConfigs) { + this._sourceConfigs = sourceConfigs; + var source = this._source; + if (source && source.configure) { + source.configure(sourceConfigs); + } + }; + + SceneJS.Geometry.prototype.getSource = function () { + return this._sourceConfigs || {}; + }; + + SceneJS.Geometry.prototype.setPositions = function (data) { + if (data.positions && this._core.vertexBuf) { + this._boundary = null; + var core = this._core; + core.vertexBuf.bind(); + core.vertexBuf.setData(new Float32Array(data.positions), data.positionsOffset || 0); + core.arrays.positions.set(data.positions, data.positionsOffset || 0); + this._engine.display.imageDirty = true; + if (core.interleavedBuf) { + core.interleavedBuf.dirty = true; + } + } + }; + + SceneJS.Geometry.prototype.getPositions = function () { + return this._core.arrays ? this._core.arrays.positions : null; + }; + + SceneJS.Geometry.prototype.setNormals = function (data) { + if (data.normals && this._core.normalBuf) { + var core = this._core; + core.normalBuf.bind(); + core.normalBuf.setData(new Float32Array(data.normals), data.normalsOffset || 0); + core.arrays.normals.set(data.normals, data.normalsOffset || 0); + this._engine.display.imageDirty = true; + if (core.interleavedBuf) { + core.interleavedBuf.dirty = true; + } + } + }; + + SceneJS.Geometry.prototype.getNormals = function () { + return this._core.arrays ? this._core.arrays.normals : null; + }; + + SceneJS.Geometry.prototype.setColors = function (data) { + if (data.colors && this._core.colorBuf) { + var core = this._core; + core.colorBuf.bind(); + core.colorBuf.setData(new Float32Array(data.colors), data.colorsOffset || 0); + core.arrays.colors.set(data.colors, data.colorsOffset || 0); + this._engine.display.imageDirty = true; + if (core.interleavedBuf) { + core.interleavedBuf.dirty = true; + } + } + }; + + SceneJS.Geometry.prototype.getColors = function () { + return this._core.arrays ? this._core.arrays.colors : null; + }; + + SceneJS.Geometry.prototype.getIndices = function () { + return this._core.arrays ? this._core.arrays.indices : null; + }; + + SceneJS.Geometry.prototype.setUV = function (data) { + if (data.uv && this._core.uvBuf) { + var core = this._core; + core.uvBuf.bind(); + core.uvBuf.setData(new Float32Array(data.uv), data.uvOffset || 0); + core.arrays.uv.set(data.uv, data.uvOffset || 0); + this._engine.display.imageDirty = true; + if (core.interleavedBuf) { + core.interleavedBuf.dirty = true; + } + } + }; + + SceneJS.Geometry.prototype.getUV = function () { + return this._core.arrays ? this._core.arrays.uv : null; + }; + + SceneJS.Geometry.prototype.setUV2 = function (data) { + if (data.uv2 && this._core.uv2Buf) { + var core = this._core; + core.uv2Buf.bind(); + core.uv2Buf.setData(new Float32Array(data.uv2), data.uv2Offset || 0); + core.arrays.uv2.set(data.uv2, data.uv2Offset || 0); + this._engine.display.imageDirty = true; + if (core.interleavedBuf) { + core.interleavedBuf.dirty = true; + } + } + }; + + SceneJS.Geometry.prototype.getUV2 = function () { + return this._core.arrays ? this._core.arrays.uv2 : null; + }; + + SceneJS.Geometry.prototype.getPrimitive = function () { + return this.primitive; + }; + + /** Returns the Model-space boundary of this geometry + * + * @returns {*} + */ + SceneJS.Geometry.prototype.getBoundary = function () { + if (this._boundary) { + return this._boundary; + } + + var arrays = this._core.arrays; + + if (!arrays) { + return null; + } + + var positions = arrays.positions; + + if (!positions) { + return null; + } + + this._boundary = { + xmin: SceneJS_math_MAX_DOUBLE, + ymin: SceneJS_math_MAX_DOUBLE, + zmin: SceneJS_math_MAX_DOUBLE, + xmax: SceneJS_math_MIN_DOUBLE, + ymax: SceneJS_math_MIN_DOUBLE, + zmax: SceneJS_math_MIN_DOUBLE + }; + + var x, y, z; + + for (var i = 0, len = positions.length - 2; i < len; i += 3) { + + x = positions[i]; + y = positions[i + 1]; + z = positions[i + 2]; + + if (x < this._boundary.xmin) { + this._boundary.xmin = x; + } + if (y < this._boundary.ymin) { + this._boundary.ymin = y; + } + if (z < this._boundary.zmin) { + this._boundary.zmin = z; + } + if (x > this._boundary.xmax) { + this._boundary.xmax = x; + } + if (y > this._boundary.ymax) { + this._boundary.ymax = y; + } + if (z > this._boundary.zmax) { + this._boundary.zmax = z; + } + } + + return this._boundary; + }; + + SceneJS.Geometry.prototype._compile = function (ctx) { + + if (this._core._loading) { // TODO: Breaks with asynch loaded cores - this node needs to recompile when target core is loaded + this._compileNodes(ctx); + return; + } + + var core = this._core; + + if (!core.vertexBuf) { + + /* SceneJS.Geometry has no vertex buffer - it must be therefore be indexing a vertex/uv buffers defined + * by a higher Geometry, as part of a composite geometry: + * + * It must therefore inherit the vertex buffer, along with UV coord buffers. + * + * We'll leave it to the render state graph traversal to ensure that the + * vertex and UV buffers are not needlessly rebound for this geometry. + */ + core = this._inheritVBOs(core); + } + + if (core.indexBuf) { // Can only render when we have indices + + core.hash = ([ // Safe to build geometry hash here - geometry is immutable + core.normalBuf ? "t" : "f", + core.arrays && core.arrays.tangents ? "t" : "f", + core.uvBuf ? "t" : "f", + core.uvBuf2 ? "t" : "f", + core.colorBuf ? "t" : "f", + core.primitive + ]).join(""); + + core.stateId = this._core.stateId; + core.type = "geometry"; + + this._engine.display.geometry = coreStack[stackLen++] = core; + + SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING, { // Pull in state updates from scenes nodes + display: this._engine.display + }); + + this._engine.display.buildObject(this.id); // Use node ID since we may inherit from many cores + + } else { + coreStack[stackLen++] = this._core; + } + + this._compileNodes(ctx); + + stackLen--; + }; + + SceneJS.Geometry.prototype._inheritVBOs = function (core) { + + var core2 = { + primitive: core.primitive, + boundary: core.boundary, + normalBuf: core.normalBuf, + uvBuf: core.uvBuf, + uvBuf2: core.uvBuf2, + colorBuf: core.colorBuf, + interleavedBuf: core.interleavedBuf, + indexBuf: core.indexBuf, + interleavedStride: core.interleavedStride, + interleavedPositionOffset: core.interleavedPositionOffset, + interleavedNormalOffset: core.interleavedNormalOffset, + interleavedUVOffset: core.interleavedUVOffset, + interleavedUV2Offset: core.interleavedUV2Offset, + interleavedColorOffset: core.interleavedColorOffset + }; + + for (var i = stackLen - 1; i >= 0; i--) { + if (coreStack[i].vertexBuf) { + core2.vertexBuf = coreStack[i].vertexBuf; + core2.boundary = coreStack[i].boundary; + core2.normalBuf = coreStack[i].normalBuf; + core2.uvBuf = coreStack[i].uvBuf; // Vertex and UVs are a package + core2.uvBuf2 = coreStack[i].uvBuf2; + core2.colorBuf = coreStack[i].colorBuf; + core2.interleavedBuf = coreStack[i].interleavedBuf; + core2.interleavedStride = coreStack[i].interleavedStride; + core2.interleavedPositionOffset = coreStack[i].interleavedPositionOffset; + core2.interleavedNormalOffset = coreStack[i].interleavedNormalOffset; + core2.interleavedUVOffset = coreStack[i].interleavedUVOffset; + core2.interleavedUV2Offset = coreStack[i].interleavedUV2Offset; + core2.interleavedColorOffset = coreStack[i].interleavedColorOffset; + return core2; + } + } + + return core2; + }; + + SceneJS.Geometry.prototype._destroy = function () { + + this._engine.display.removeObject(this.id); + + /* Destroy core if no other references + */ + if (this._core.useCount == 1) { + + this._destroyNodeCore(); + + if (this._source && this._source.destroy) { + this._source.destroy(); + } + } + }; + + SceneJS.Geometry.prototype._destroyNodeCore = function () { + + if (document.getElementById(this._engine.canvas.canvasId)) { // Context won't exist if canvas has disappeared + destroyBuffers(this._core); + } + }; + +})(); +;(function() { + + /** + * The default state core singleton for {@link SceneJS.Stage} nodes + */ + var defaultCore = { + type: "stage", + stateId: SceneJS._baseStateId++, + priority: 0, + pickable: true, + enabled: true + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function(params) { + params.engine.display.stage = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which assigns the {@link SceneJS.Geometry}s within its subgraph to a prioritised render bin + * @extends SceneJS.Node + */ + SceneJS.Stage = SceneJS_NodeFactory.createNodeType("stage"); + + SceneJS.Stage.prototype._init = function(params) { + if (this._core.useCount == 1) { // This node defines the resource + this._core.priority = params.priority || 0; + this._core.enabled = params.enabled !== false; + this._core.pickable = !!params.pickable; + } + }; + + SceneJS.Stage.prototype.setPriority = function(priority) { + priority = priority || 0; + if (this._core.priority != priority) { + this._core.priority = priority; + this._engine.display.stateOrderDirty = true; + } + }; + + SceneJS.Stage.prototype.getPriority = function() { + return this._core.priority; + }; + + SceneJS.Stage.prototype.setEnabled = function(enabled) { + enabled = !!enabled; + if (this._core.enabled != enabled) { + this._core.enabled = enabled; + this._engine.display.drawListDirty = true; + } + }; + + SceneJS.Stage.prototype.getEnabled = function() { + return this._core.enabled; + }; + + SceneJS.Stage.prototype.getEnabled = function() { + return this._core.enabled; + }; + + SceneJS.Stage.prototype._compile = function(ctx) { + this._engine.display.stage = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.stage = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})(); + +;(function () { + + /** + * The default state core singleton for {@link SceneJS.Layer} nodes + */ + var defaultCore = { + type: "layer", + stateId: SceneJS._baseStateId++, + priority: 0, + enabled: true + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.layer = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which assigns the {@link SceneJS.Geometry}s within its subgraph to a prioritised render bin + * @extends SceneJS.Node + */ + SceneJS.Layer = SceneJS_NodeFactory.createNodeType("layer"); + + SceneJS.Layer.prototype._init = function (params) { + if (this._core.useCount == 1) { // This node defines the resource + this._core.priority = params.priority || 0; + this._core.enabled = params.enabled !== false; + } + }; + + SceneJS.Layer.prototype.setPriority = function (priority) { + priority = priority || 0; + if (this._core.priority != priority) { + this._core.priority = priority; + this._engine.display.stateOrderDirty = true; + } + }; + + SceneJS.Layer.prototype.getPriority = function () { + return this._core.priority; + }; + + SceneJS.Layer.prototype.setEnabled = function (enabled) { + enabled = !!enabled; + if (this._core.enabled != enabled) { + this._core.enabled = enabled; + this._engine.display.drawListDirty = true; + } + }; + + SceneJS.Layer.prototype.getEnabled = function () { + return this._core.enabled; + }; + + SceneJS.Layer.prototype.getEnabled = function () { + return this._core.enabled; + }; + + SceneJS.Layer.prototype.setClearDepth = function (clearDepth) { + clearDepth = clearDepth || 0; + if (this._core.clearDepth != clearDepth) { + this._core.clearDepth = clearDepth; + this._engine.display.drawListDirty = true; + } + }; + + SceneJS.Layer.prototype.getClearDepth = function () { + return this._core.clearDepth; + }; + + SceneJS.Layer.prototype._compile = function(ctx) { + this._engine.display.layer = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.layer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})(); + +;/** + * @class Scene graph node which assigns nodes in its subgraph to a library + * @extends SceneJS.Node + */ +SceneJS.Library = SceneJS_NodeFactory.createNodeType("library"); +SceneJS.Library.prototype._compile = function(ctx) { // Bypass child nodes +}; + +;(function () { + + /** + * The default state core singleton for {@link SceneJS.Lights} nodes + */ + var defaultCore = { + type: "lights", + stateId: SceneJS._baseStateId++, + hash: null, + empty: false, + lights: [ + { + mode: "ambient", + color: [0.7, 0.7, 0.8 ], + diffuse: true, + specular: false + }, + { + mode: "dir", + color: [1.0, 1.0, 1.0 ], + diffuse: true, + specular: true, + dir: [-0.5, -0.5, -1.0 ], + space: "view" + }, + { + mode: "dir", + color: [1.0, 1.0, 1.0 ], + diffuse: false, + specular: true, + dir: [1.0, -0.9, -0.7 ], + space: "view" + } + ] + }; + + makeHash(defaultCore); + + function makeHash(core) { + if (core.lights && core.lights.length > 0) { + var lights = core.lights; + var parts = []; + var light; + for (var i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + parts.push(light.mode); + if (light.specular) { + parts.push("s"); + } + if (light.diffuse) { + parts.push("d"); + } + parts.push((light.space == "world") ? "w" : "v"); + } + core.hash = parts.join(""); + + } else { + core.hash = ""; + } + } + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.lights = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines light sources to illuminate the {@link SceneJS.Geometry}s within its subgraph + * @extends SceneJS.Node + */ + SceneJS.Lights = SceneJS_NodeFactory.createNodeType("lights"); + + SceneJS.Lights.prototype._init = function (params) { + + if (this._core.useCount == 1) { // This node defines the resource + + var lights = params.lights; + + if (!lights) { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "lights node attribute missing : 'lights'"); + } + + this._core.lights = this._core.lights || []; + + for (var i = 0, len = lights.length; i < len; i++) { + this._initLight(i, lights[i]); + } + } + }; + + SceneJS.Lights.prototype._initLight = function (index, cfg) { + + var light = []; + this._core.lights[index] = light; + + var mode = cfg.mode || "dir"; + if (mode != "dir" && mode != "point" && mode != "ambient") { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Light mode not supported - should be 'dir' or 'point' or 'ambient'"); + } + + var pos = cfg.pos; + var dir = cfg.dir; + + var color = cfg.color; + light.color = [ + color.r != undefined ? color.r : 1.0, + color.g != undefined ? color.g : 1.0, + color.b != undefined ? color.b : 1.0 + ]; + + // Ambient lights hardwired to contribute to diffuse lighting + light.mode = mode; + light.diffuse = (mode == "ambient") ? true : ((cfg.diffuse != undefined) ? cfg.diffuse : true); + light.specular = (mode == "ambient") ? false : ((cfg.specular != undefined) ? cfg.specular : true); + light.pos = cfg.pos ? [ pos.x || 0, pos.y || 0, pos.z || 0 ] : [0, 0, 0]; + light.dir = cfg.dir ? [dir.x || 0, dir.y || 0, dir.z || 0] : [0, 0, 1]; + light.attenuation = [ + cfg.constantAttenuation != undefined ? cfg.constantAttenuation : 0.0, + cfg.linearAttenuation || 0.0, + cfg.quadraticAttenuation || 0.0 + ]; + + var space = cfg.space; + + if (!space) { + + space = "world"; + + } else if (space != "view" && space != "world") { + + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "lights node invalid value for property 'space': '" + space + "' - should be 'view' or 'world'"); + } + + light.space = space; + + this._core.hash = null; + }; + + + SceneJS.Lights.prototype.setLights = function (lights) { + var indexNum; + for (var index in lights) { + if (lights.hasOwnProperty(index)) { + if (index != undefined || index != null) { + indexNum = parseInt(index); + if (indexNum < 0 || indexNum >= this._core.lights.length) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Invalid argument to set 'lights': index out of range (" + this._core.lights.length + " lights defined)"); + } + this._setLight(indexNum, lights[index] || {}); + } + } + } + this._engine.branchDirty(this); // Schedule recompilation of this subgraph + }; + + SceneJS.Lights.prototype._setLight = function (index, cfg) { + + var light = this._core.lights[index]; + + // Impact of light update + var imageDirty = false; // Redraw display list? + var branchDirty = false; // Recompile scene branch? + + if (cfg.mode && cfg.mode != light.mode) { + var mode = cfg.mode; + if (mode != "dir" && mode != "point" && mode != "ambient") { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Light mode not supported - should be 'dir' or 'point' or 'ambient'"); + } + light.mode = mode; + light.diffuse = (mode == "ambient") ? true : ((cfg.diffuse != undefined) ? cfg.diffuse : true); + light.specular = (mode == "ambient") ? false : ((cfg.specular != undefined) ? cfg.specular : true); + branchDirty = true; + } + + if (cfg.color) { + var color = cfg.color; + light.color = [ + color.r != undefined ? color.r : 1.0, + color.g != undefined ? color.g : 1.0, + color.b != undefined ? color.b : 1.0 + ]; + imageDirty = true; + } + + var pos = cfg.pos; + if (pos) { + light.pos = [ pos.x || 0, pos.y || 0, pos.z || 0 ]; + imageDirty = true; + } + + var dir = cfg.dir; + if (dir) { + light.dir = [dir.x || 0, dir.y || 0, dir.z || 0]; + imageDirty = true; + } + + if (cfg.constantAttenuation != undefined) { + light.attenuation[0] = cfg.constantAttenuation; + imageDirty = true; + } + if (cfg.linearAttenuation != undefined) { + light.attenuation[1] = cfg.linearAttenuation; + imageDirty = true; + } + if (cfg.quadraticAttenuation != undefined) { + light.attenuation[2] = cfg.quadraticAttenuation; + imageDirty = true; + } + + if (cfg.space && cfg.space != light.space) { + var space = cfg.space; + if (space != "view" && space != "world") { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "lights node invalid value for property 'space': '" + space + "' - should be 'view' or 'world'"); + } + light.space = space; + this._core.hash = null; + branchDirty = true; + } + + if (cfg.specular != undefined && cfg.specular != light.specular) { + light.specular = cfg.specular; + branchDirty = true; + } + if (cfg.diffuse != undefined && cfg.diffuse != light.diffuse) { + light.diffuse = cfg.diffuse; + branchDirty = true; + } + + if (branchDirty) { + this._engine.branchDirty(this); // Schedule recompilation of this subgraph + } else if (imageDirty) { + this._engine.display.imageDirty = true; + } + + this._core.hash = null; + }; + + SceneJS.Lights.prototype._compile = function (ctx) { + + if (!this._core.hash) { + makeHash(this._core); + } + + this._engine.display.lights = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.lights = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})();;(function () { + + var defaultMatrix = SceneJS_math_lookAtMat4c(0, 0, 10, 0, 0, 0, 0, 1, 0); + var defaultMat = new Float32Array(defaultMatrix); + var normalMat = SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(defaultMat, SceneJS_math_mat4())); + var defaultNormalMat = new Float32Array(normalMat); + + /** + * The default state core singleton for {@link SceneJS.Lookat} nodes + */ + var defaultCore = { + type:"lookAt", + stateId:SceneJS._baseStateId++, + matrix:defaultMatrix, + mat:defaultMat, + normalMatrix:normalMat, + normalMat:defaultNormalMat, + lookAt:SceneJS_math_LOOKAT_ARRAYS + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.viewTransform = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines the viewing transform for the {@link SceneJS.Geometry}s within its subgraph + * @extends SceneJS.Node + */ + SceneJS.Lookat = SceneJS_NodeFactory.createNodeType("lookAt"); + + SceneJS.Lookat.prototype._init = function (params) { + + this._mat = null; + + this._xf = { + type:"lookat" + }; + + if (this._core.useCount == 1) { // This node is the resource definer + + this._core.eyeX = 0; + this._core.eyeY = 0; + this._core.eyeZ = 10.0; + + this._core.lookX = 0; + this._core.lookY = 0; + this._core.lookZ = 0; + + this._core.upX = 0; + this._core.upY = 1; + this._core.upZ = 0; + + if (!params.eye && !params.look && !params.up) { + this.setEye({x:0, y:0, z:10.0 }); + this.setLook({x:0, y:0, z:0 }); + this.setUp({x:0, y:1.0, z:0 }); + } else { + this.setEye(params.eye); + this.setLook(params.look); + this.setUp(params.up); + } + + var core = this._core; + + var self = this; + + this._core.rebuild = function () { + + core.matrix = SceneJS_math_lookAtMat4c( + core.eyeX, core.eyeY, core.eyeZ, + core.lookX, core.lookY, core.lookZ, + core.upX, core.upY, core.upZ); + + core.lookAt = { + eye:[core.eyeX, core.eyeY, core.eyeZ ], + look:[core.lookX, core.lookY, core.lookZ ], + up:[core.upX, core.upY, core.upZ ] + }; + + if (!core.mat) { // Lazy-create arrays + core.mat = new Float32Array(core.matrix); + core.normalMat = new Float32Array( + SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(core.matrix, SceneJS_math_mat4()))); + + } else { // Insert into arrays + core.mat.set(core.matrix); + core.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(core.matrix, SceneJS_math_mat4()))); + } + + self.publish("matrix", core.matrix); + + core.dirty = false; + }; + + this._core.dirty = true; + + // Rebuild on every scene tick + // https://github.com/xeolabs/scenejs/issues/277 + this._tick = this.getScene().on("tick", function () { + if (self._core.dirty) { + self._core.rebuild(); + } + }); + } + }; + + /** + * Returns the default view transformation matrix + * @return {Float32Array} + */ + SceneJS.Lookat.getDefaultMatrix = function () { + return defaultMat; + }; + + SceneJS.Lookat.prototype.setEye = function (eye) { + + eye = eye || {}; + + if (eye.x != undefined && eye.x != null) { + this._core.eyeX = eye.x; + } + + if (eye.y != undefined && eye.y != null) { + this._core.eyeY = eye.y; + } + + if (eye.z != undefined && eye.z != null) { + this._core.eyeZ = eye.z; + } + + this._core.dirty = true; + this._engine.display.imageDirty = true; + + return this; + }; + + SceneJS.Lookat.prototype.incEye = function (eye) { + eye = eye || {}; + this._core.eyeX += (eye.x != undefined && eye.x != null) ? eye.x : 0; + this._core.eyeY += (eye.y != undefined && eye.y != null) ? eye.y : 0; + this._core.eyeZ += (eye.z != undefined && eye.z != null) ? eye.z : 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setEyeX = function (x) { + this._core.eyeX = x || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setEyeY = function (y) { + this._core.eyeY = y || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setEyeZ = function (z) { + this._core.eyeZ = z || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incEyeX = function (x) { + this._core.eyeX += x; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incEyeY = function (y) { + this._core.eyeY += y; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incEyeZ = function (z) { + this._core.eyeZ += z; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.getEye = function () { + return { + x:this._core.eyeX, + y:this._core.eyeY, + z:this._core.eyeZ + }; + }; + + SceneJS.Lookat.prototype.setLook = function (look) { + look = look || {}; + + if (look.x != undefined && look.x != null) { + this._core.lookX = look.x; + } + + if (look.y != undefined && look.y != null) { + this._core.lookY = look.y; + } + + if (look.z != undefined && look.z != null) { + this._core.lookZ = look.z; + } + + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incLook = function (look) { + look = look || {}; + this._core.lookX += (look.x != undefined && look.x != null) ? look.x : 0; + this._core.lookY += (look.y != undefined && look.y != null) ? look.y : 0; + this._core.lookZ += (look.z != undefined && look.z != null) ? look.z : 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setLookX = function (x) { + this._core.lookX = x || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setLookY = function (y) { + this._core.lookY = y || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setLookZ = function (z) { + this._core.lookZ = z || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incLookX = function (x) { + this._core.lookX += x; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incLookY = function (y) { + this._core.lookY += y; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incLookZ = function (z) { + this._core.lookZ += z; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.getLook = function () { + return { + x:this._core.lookX, + y:this._core.lookY, + z:this._core.lookZ + }; + }; + + SceneJS.Lookat.prototype.setUp = function (up) { + up = up || {}; + + if (up.x != undefined && up.x != null) { + this._core.upX = up.x; + } + + if (up.y != undefined && up.y != null) { + this._core.upY = up.y; + } + + if (up.z != undefined && up.z != null) { + this._core.upZ = up.z; + } + + this._core.dirty = true; + this._engine.display.imageDirty = true; + + return this; + }; + + SceneJS.Lookat.prototype.incUp = function (up) { + up = up || {}; + this._core.upX += (up.x != undefined && up.x != null) ? up.x : 0; + this._core.upY += (up.y != undefined && up.y != null) ? up.y : 0; + this._core.upZ += (up.z != undefined && up.z != null) ? up.z : 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setUpX = function (x) { + this._core.upX = x || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setUpY = function (y) { + this._core.upY = y || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.setUpZ = function (z) { + this._core.upZ = z || 0; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incUpX = function (x) { + this._core.upX += x; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incUpY = function (y) { + this._core.upY += y; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.incUpZ = function (z) { + this._core.upZ += z; + this._core.dirty = true; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Lookat.prototype.getUp = function () { + return { + x:this._core.upX, + y:this._core.upY, + z:this._core.upZ + }; + }; + + /** + * Returns a copy of the matrix as a 1D array of 16 elements + * @returns {Number[16]} + */ + SceneJS.Lookat.prototype.getMatrix = function () { + + if (this._core.dirty) { + this._core.rebuild(); + } + + return this._core.matrix.slice(0); + }; + + SceneJS.Lookat.prototype.getAttributes = function () { + return { + look:{ + x:this._core.lookX, + y:this._core.lookY, + z:this._core.lookZ + }, + eye:{ + x:this._core.eyeX, + y:this._core.eyeY, + z:this._core.eyeZ + }, + up:{ + x:this._core.upX, + y:this._core.upY, + z:this._core.upZ + } + }; + }; + + SceneJS.Lookat.prototype._compile = function (ctx) { + this._engine.display.viewTransform = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.viewTransform = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + SceneJS.Lookat.prototype._destroy = function () { + // Stop publishing matrix on each tick + this.getScene().off(this._tick); + }; + +})();;/* + + TODO: material system from virtualworldframework: + + "color": + "ambient": + "specColor": + "shininess": + "reflect": + "specular": + "emit": + "alpha": + "binaryAlpha": + */ +new (function () { + + /** + * The default state core singleton for {@link SceneJS.Material} nodes + */ + var defaultCore = { + type:"material", + stateId:SceneJS._baseStateId++, + baseColor:[ 1.0, 1.0, 1.0 ], + specularColor:[ 1.0, 1.0, 1.0 ], + specular:1.0, + shine:70.0, + alpha:1.0, + emit:0.0 + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.material = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines surface material properties for the {@link SceneJS.Geometry}s within its subgraph + * @extends SceneJS.Node + */ + SceneJS.Material = SceneJS_NodeFactory.createNodeType("material"); + + SceneJS.Material.prototype._init = function (params) { + if (this._core.useCount == 1) { + this.setBaseColor(params.color || params.baseColor); + this.setSpecularColor(params.specularColor); + this.setSpecular(params.specular); + this.setShine(params.shine); + this.setEmit(params.emit); + this.setAlpha(params.alpha); + } + }; + + /** + * @deprecated + * @param color + * @return {*} + */ + SceneJS.Material.prototype.setBaseColor = function (color) { + var defaultBaseColor = defaultCore.baseColor; + this._core.baseColor = color ? [ + color.r != undefined && color.r != null ? color.r : defaultBaseColor[0], + color.g != undefined && color.g != null ? color.g : defaultBaseColor[1], + color.b != undefined && color.b != null ? color.b : defaultBaseColor[2] + ] : defaultCore.baseColor; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Material.prototype.setColor = SceneJS.Material.prototype.setBaseColor; + + /** + * @deprecated + * @return {Object} + */ + SceneJS.Material.prototype.getBaseColor = function () { + return { + r:this._core.baseColor[0], + g:this._core.baseColor[1], + b:this._core.baseColor[2] + }; + }; + + SceneJS.Material.prototype.getColor = SceneJS.Material.prototype.getBaseColor; + + SceneJS.Material.prototype.setSpecularColor = function (color) { + var defaultSpecularColor = defaultCore.specularColor; + this._core.specularColor = color ? [ + color.r != undefined && color.r != null ? color.r : defaultSpecularColor[0], + color.g != undefined && color.g != null ? color.g : defaultSpecularColor[1], + color.b != undefined && color.b != null ? color.b : defaultSpecularColor[2] + ] : defaultCore.specularColor; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Material.prototype.getSpecularColor = function () { + return { + r:this._core.specularColor[0], + g:this._core.specularColor[1], + b:this._core.specularColor[2] + }; + }; + + SceneJS.Material.prototype.setSpecular = function (specular) { + this._core.specular = (specular != undefined && specular != null) ? specular : defaultCore.specular; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Material.prototype.getSpecular = function () { + return this._core.specular; + }; + + SceneJS.Material.prototype.setShine = function (shine) { + this._core.shine = (shine != undefined && shine != null) ? shine : defaultCore.shine; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Material.prototype.getShine = function () { + return this._core.shine; + }; + + SceneJS.Material.prototype.setEmit = function (emit) { + this._core.emit = (emit != undefined && emit != null) ? emit : defaultCore.emit; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Material.prototype.getEmit = function () { + return this._core.emit; + }; + + SceneJS.Material.prototype.setAlpha = function (alpha) { + this._core.alpha = (alpha != undefined && alpha != null) ? alpha : defaultCore.alpha; + this._engine.display.imageDirty = true; + return this; + }; + + SceneJS.Material.prototype.getAlpha = function () { + return this._core.alpha; + }; + + SceneJS.Material.prototype._compile = function (ctx) { + this._engine.display.material = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.material = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})();;new (function () { + + /** + * The default state core singleton for {@link SceneJS.MorphGeometry} nodes + */ + var defaultCore = { + type:"morphGeometry", + stateId:SceneJS._baseStateId++, + hash:"", + // empty: true, + morph:null + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.morphGeometry = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines morphing behaviour for the {@link SceneJS.Geometry}s within its subgraph + * @extends SceneJS.Node + */ + SceneJS.MorphGeometry = SceneJS_NodeFactory.createNodeType("morphGeometry"); + + SceneJS.MorphGeometry.prototype._init = function (params) { + + if (this._core.useCount == 1) { // This node defines the resource + + this._sourceConfigs = params.source; + this._source = null; + + if (params.source) { + + /*--------------------------------------------------------------------------------------------------- + * Build node core (possibly asynchronously) using a factory object + *--------------------------------------------------------------------------------------------------*/ + + if (!params.source.type) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "morphGeometry config expected: source.type"); + } + + var self = this; + + SceneJS.Plugins.getPlugin( + "morphGeometry", + this._sourceConfigs.type, + function (sourceService) { + + if (!sourceService) { + throw SceneJS_error.fatalError( + SceneJS.errors.PLUGIN_INVALID, + "morphGeometry: no support for source type '" + self._sourceConfigs.type + "' - need to include plugin for self source type, " + + "or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '" + self._sourceConfigs.type + "', )."); + } + + if (!sourceService.getSource) { + throw SceneJS_error.fatalError( + SceneJS.errors.PLUGIN_INVALID, + "morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)"); + } + + self._source = sourceService.getSource(); + + if (!self._source.subscribe) { + throw SceneJS_error.fatalError( + SceneJS.errors.PLUGIN_INVALID, + "morphGeometry: 'subscribe' method not found on source provided by plugin type '" + params.source.type + "'"); + } + + var created = false; + + self._source.subscribe(// Get notification when factory creates the morph + function (data) { + + if (!created) { + self._buildNodeCore(data); + + self._core._loading = false; + self._fireEvent("loaded"); + + self._engine.branchDirty(self); // TODO + + created = true; + + } else { + + if (data.targets) { + + var dataTargets = data.targets; + var dataTarget; + var index; + var morphTargets = self._core.targets; + var morphTarget; + + for (var i = 0, len = dataTargets.length; i < len; i++) { + dataTarget = dataTargets[i]; + index = dataTarget.targetIndex; + morphTarget = morphTargets[index]; + + if (dataTarget.positions && morphTarget.vertexBuf) { + morphTarget.vertexBuf.bind(); + morphTarget.vertexBuf.setData(dataTarget.positions, 0); + } + } + } + + // TODO: factory can update factor? + // self.setFactor(params.factor); + + self._display.imageDirty = true; + } + }); + + self._core._loading = true; + + self._fireEvent("loading"); + + self._source.configure(self._sourceConfigs); + }); + + } else if (params.create instanceof Function) { + + /*--------------------------------------------------------------------------------------------------- + * Build node core from JSON arrays and primitive name returned by factory function + *--------------------------------------------------------------------------------------------------*/ + + this._buildNodeCore(params.create()); + + } else { + + /*--------------------------------------------------------------------------------------------------- + * Build node core from JSON arrays and primitive name given in node properties + *--------------------------------------------------------------------------------------------------*/ + + this._buildNodeCore(params); + } + + this._core.webglRestored = function () { + //self._buildNodeCore(self._engine.canvas.gl, self._core); + }; + + this.setFactor(params.factor); + } + + // TODO: factor shared on cores? + this._core.factor = params.factor || 0; + this._core.clamp = !!params.clamp; + }; + + SceneJS.MorphGeometry.prototype._buildNodeCore = function (data) { + + var targetsData = data.targets || []; + if (targetsData.length < 2) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "morphGeometry node should have at least two targets"); + } + + var keysData = data.keys || []; + if (keysData.length != targetsData.length) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "morphGeometry node mismatch in number of keys and targets"); + } + + var core = this._core; + var gl = this._engine.canvas.gl; + var usage = gl.STATIC_DRAW; //var usage = (!arrays.fixed) ? gl.STREAM_DRAW : gl.STATIC_DRAW; + + core.keys = keysData; + core.targets = []; + core.key1 = 0; + core.key2 = 1; + + /* First target's arrays are defaults for where not given on previous and subsequent targets. + * When target does have array, subsequent targets without array inherit it. + */ + + var positions; + var normals; + var uv; + var uv2; + + var targetData; + + for (var i = 0, len = targetsData.length; i < len; i++) { + targetData = targetsData[i]; + if (!positions && targetData.positions) { + positions = targetData.positions; + } + if (!normals && targetData.normals) { + normals = targetData.normals; + } + if (!uv && targetData.uv) { + uv = targetData.uv; + } + if (!uv2 && targetData.uv2) { + uv2 = targetData.uv2; + } + } + + try { + var target; + var arry; + + for (var i = 0, len = targetsData.length; i < len; i++) { + targetData = targetsData[i]; + target = {}; + + arry = targetData.positions || positions; + if (arry) { + target.positions = (typeof arry == "Float32Array") ? arry : new Float32Array(arry); + target.vertexBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, target.positions, arry.length, 3, usage); + positions = arry; + } + + arry = targetData.normals || normals; + if (arry) { + target.normals = (typeof arry == "Float32Array") ? arry : new Float32Array(arry); + target.normalBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, target.normals, arry.length, 3, usage); + normals = arry; + } + + arry = targetData.uv || uv; + if (arry) { + target.uv = (typeof arry == "Float32Array") ? arry : new Float32Array(arry); + target.uvBuf = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, target.uv, arry.length, 2, usage); + uv = arry; + } + + arry = targetData.uv2 || uv2; + if (arry) { + target.uv2 = (typeof arry == "Float32Array") ? arry : new Float32Array(arry); + target.uvBuf2 = new SceneJS._webgl.ArrayBuffer(gl, gl.ARRAY_BUFFER, target.uv2, arry.length, 2, usage); + uv2 = arry; + } + + core.targets.push(target); // We'll iterate this to destroy targets when we recover from error + } + + } catch (e) { + + /* Allocation failure - deallocate target VBOs + */ + for (var i = 0, len = core.targets.length; i < len; i++) { + + target = core.targets[i]; + + if (target.vertexBuf) { + target.vertexBuf.destroy(); + } + if (target.normalBuf) { + target.normalBuf.destroy(); + } + if (target.uvBuf) { + target.uvBuf.destroy(); + } + if (target.uvBuf2) { + target.uvBuf2.destroy(); + } + } + + throw SceneJS_error.fatalError( + SceneJS.errors.ERROR, + "Failed to allocate VBO(s) for morphGeometry: " + e); + } + }; + + SceneJS.MorphGeometry.prototype.setSource = function (sourceConfigs) { + this._sourceConfigs = sourceConfigs; + var source = this._source; + if (source) { + source.configure(sourceConfigs); + } + }; + + SceneJS.MorphGeometry.prototype.getSource = function () { + return this._sourceConfigs; + }; + + SceneJS.MorphGeometry.prototype.setFactor = function (factor) { + factor = factor || 0.0; + + var core = this._core; + + var keys = core.keys; + var key1 = core.key1; + var key2 = core.key2; + + var oldFactor = core.factor; + + if (factor < keys[0]) { + key1 = 0; + key2 = 1; + + } else if (factor > keys[keys.length - 1]) { + key1 = keys.length - 2; + key2 = key1 + 1; + + } else { + while (keys[key1] > factor) { + key1--; + key2--; + } + while (keys[key2] < factor) { + key1++; + key2++; + } + } + + var frameUpdate = key1 != core.key1; + + /* Normalise factor to range [0.0..1.0] for the target frame + */ + core.factor = (factor - keys[key1]) / (keys[key2] - keys[key1]); + + this._factor = factor; + + var morphUpdate = frameUpdate || oldFactor != core.factor; + + core.key1 = key1; + core.key2 = key2; + + if (morphUpdate) { + var currentFrame = this.getCurrentFrame(); + this.publish("update", currentFrame); + if (frameUpdate) { + this.publish("frameUpdate", currentFrame); + } + } + + this._engine.display.imageDirty = true; + }; + + SceneJS.MorphGeometry.prototype.getFactor = function () { + return this._factor; + }; + + SceneJS.MorphGeometry.prototype.getKeys = function () { + return this._core.keys; + }; + + SceneJS.MorphGeometry.prototype.getTargets = function () { + return this._core.targets; + }; + + SceneJS.MorphGeometry.prototype.getCurrentFrame = function () { + var core = this._core; + var key1 = core.key1; + var key2 = core.key2; + return { + key1: key1, + key2: key2, + factor: core.factor, + target1: core.targets[key1], + target2: core.targets[key2] + } + }; + + SceneJS.MorphGeometry.prototype._compile = function (ctx) { + + if (!this._core.hash) { + this._makeHash(); + } + + this._engine.display.morphGeometry = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.morphGeometry = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + SceneJS.MorphGeometry.prototype._makeHash = function () { + var core = this._core; + if (core.targets.length > 0) { + var target0 = core.targets[0]; // All targets have same arrays + var t = "t"; + var f = "f"; + core.hash = ([ + target0.vertexBuf ? t : f, + target0.normalBuf ? t : f, + target0.uvBuf ? t : f, + target0.uvBuf2 ? t : f + ]).join(""); + } else { + core.hash = ""; + } + }; + + SceneJS.MorphGeometry.prototype._destroy = function () { + if (this._core.useCount == 1) { // Destroy core if no other references + if (document.getElementById(this._engine.canvas.canvasId)) { // Context won't exist if canvas has disappeared + var core = this._core; + var target; + for (var i = 0, len = core.targets.length; i < len; i++) { + target = core.targets[i]; + if (target.vertexBuf) { + target.vertexBuf.destroy(); + } + if (target.normalBuf) { + target.normalBuf.destroy(); + } + if (target.uvBuf) { + target.uvBuf.destroy(); + } + if (target.uvBuf2) { + target.uvBuf2.destroy(); + } + } + } + if (this._source && this._source.destroy) { + this._source.destroy(); + } + } + }; + +})();;(function () { + + /** + * The default state core singleton for {@link SceneJS.Name} nodes + */ + var defaultCore = { + type:"name", + stateId:SceneJS._baseStateId++, + name:null + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.name = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which assigns a pick name to the {@link SceneJS.Geometry} nodes in its subgraph. + * @extends SceneJS.Node + */ + SceneJS.Name = SceneJS_NodeFactory.createNodeType("name"); + + SceneJS.Name.prototype._init = function (params) { + this.setName(params.name); + this._core.nodeId = this.id; + }; + + SceneJS.Name.prototype.setName = function (name) { + this._core.name = name || "unnamed"; + this._engine.branchDirty(this); // Need to recompile name path + }; + + SceneJS.Name.prototype.getName = function () { + return this._core.name; + }; + + SceneJS.Name.prototype._compile = function (ctx) { + + this._engine.display.name = coreStack[stackLen++] = this._core; + + // (Re)build name path + var path = []; + var name; + for (var i = 0; i < stackLen; i++) { + name = coreStack[i].name; + if (name) { + path.push(name); + } + } + this._core.path = path.join("."); + + this._compileNodes(ctx); + this._engine.display.name = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; +})();;new (function () { + + /** + * The default state core singleton for {@link SceneJS.Renderer} nodes + */ + var defaultCore = { + type: "renderer", + stateId: SceneJS._baseStateId++, + props: null + }; + + var canvas; // Currently active canvas + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + + canvas = params.engine.canvas; + +// // TODO: Below is a HACK +// +// defaultCore.props = createProps({ // Dont set props - just define for restoring to on props pop +// clear: { +// depth : true, +// color : true +// }, +// // clearColor: {r: 0, g : 0, b : 0 }, +// clearDepth: 1.0, +// enableDepthTest:true, +// enableCullFace: false, +// frontFace: "ccw", +// cullFace: "back", +// depthFunc: "less", +// depthRange: { +// zNear: 0, +// zFar: 1 +// }, +// enableScissorTest: false, +// viewport:{ +// x : 1, +// y : 1, +// width: canvas.canvas.width, +// height: canvas.canvas.height +// }, +// enableClip: undefined, +// enableBlend: false, +// blendFunc: { +// sfactor: "srcAlpha", +// dfactor: "one" +// } +// }); + + stackLen = 0; + + params.engine.display.renderer = coreStack[stackLen++] = defaultCore; + }); + + function createProps(props) { + + var restore; + if (stackLen > 0) { // can't restore when no previous props set + restore = {}; + for (var name in props) { + if (props.hasOwnProperty(name)) { + if (!(props[name] == undefined)) { + restore[name] = getSuperProperty(name); + } + } + } + } + + processProps(props.props); + + return { + + props: props, + + setProps: function (gl) { + setProperties(gl, props); + }, + + restoreProps: function (gl) { + if (restore) { + restoreProperties(gl, restore); + } + } + }; + } + + var getSuperProperty = function (name) { + var props; + var prop; + for (var i = stackLen - 1; i >= 0; i--) { + props = coreStack[i].props; + if (props) { + prop = props[name]; + if (prop != undefined && prop != null) { + return props[name]; + } + } + } + return null; // Cause default to be set + }; + + function processProps(props) { + var prop; + for (var name in props) { + if (props.hasOwnProperty(name)) { + prop = props[name]; + if (prop != undefined && prop != null) { + if (glModeSetters[name]) { + props[name] = glModeSetters[name](null, prop); + } else if (glStateSetters[name]) { + props[name] = glStateSetters[name](null, prop); + } + } + } + } + } + + var setProperties = function (gl, props) { + + for (var key in props) { // Set order-insensitive properties (modes) + if (props.hasOwnProperty(key)) { + var setter = glModeSetters[key]; + if (setter) { + setter(gl, props[key]); + } + } + } + + if (props.viewport) { // Set order-sensitive properties (states) + glStateSetters.viewport(gl, props.viewport); + } + + if (props.scissor) { + glStateSetters.clear(gl, props.scissor); + } + + if (props.clear) { + glStateSetters.clear(gl, props.clear); + } + }; + + /** + * Restores previous renderer properties, except for clear - that's the reason we + * have a seperate set and restore semantic - we don't want to keep clearing the buffer. + */ + var restoreProperties = function (gl, props) { + + var value; + + for (var key in props) { // Set order-insensitive properties (modes) + if (props.hasOwnProperty(key)) { + value = props[key]; + if (value != undefined && value != null) { + var setter = glModeSetters[key]; + if (setter) { + setter(gl, value); + } + } + } + } + + if (props.viewport) { // Set order-sensitive properties (states) + glStateSetters.viewport(gl, props.viewport); + } + + if (props.scissor) { + glStateSetters.clear(gl, props.scissor); + } + }; + + + /** + * Maps renderer node properties to WebGL gl enums + * @private + */ + var glEnum = function (gl, name) { + if (!name) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Null SceneJS.State node config: \"" + name + "\""); + } + var result = SceneJS._webgl.enumMap[name]; + if (!result) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Unrecognised SceneJS.State node config value: \"" + name + "\""); + } + var value = gl[result]; + if (!value) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "This browser's WebGL does not support renderer node config value: \"" + name + "\""); + } + return value; + }; + + + /** + * Order-insensitive functions that set WebGL modes ie. not actually causing an + * immediate change. + * + * These map to renderer properties and are called in whatever order their + * property is found on the renderer config. + * + * Each of these wrap a state-setter function on the WebGL gl. Each function + * also uses the glEnum map to convert its renderer node property argument to the + * WebGL enum constant required by its wrapped function. + * + * When called with undefined/null gl, will condition and return the value given + * ie. set it to default if value is undefined. When called with a gl, will + * set the value on the gl using the wrapped function. + * + * @private + */ + var glModeSetters = { + + enableBlend: function (gl, flag) { + if (!gl) { + if (flag == null || flag == undefined) { + flag = false; + } + return flag; + } + if (flag) { + gl.enable(gl.BLEND); + } else { + gl.disable(gl.BLEND); + } + }, + + blendColor: function (gl, color) { + if (!gl) { + color = color || {}; + return { + r: color.r || 0, + g: color.g || 0, + b: color.b || 0, + a: (color.a == undefined || color.a == null) ? 1 : color.a + }; + } + gl.blendColor(color.r, color.g, color.b, color.a); + }, + + blendEquation: function (gl, eqn) { + if (!gl) { + return eqn || "funcAdd"; + } + gl.blendEquation(gl, glEnum(gl, eqn)); + }, + + /** Sets the RGB blend equation and the alpha blend equation separately + */ + blendEquationSeparate: function (gl, eqn) { + if (!gl) { + eqn = eqn || {}; + return { + rgb: eqn.rgb || "funcAdd", + alpha: eqn.alpha || "funcAdd" + }; + } + gl.blendEquation(glEnum(gl, eqn.rgb), glEnum(gl, eqn.alpha)); + }, + + blendFunc: function (gl, funcs) { + if (!gl) { + funcs = funcs || {}; + return { + sfactor: funcs.sfactor || "srcAlpha", + dfactor: funcs.dfactor || "oneMinusSrcAlpha" + }; + } + gl.blendFunc(glEnum(gl, funcs.sfactor || "srcAlpha"), glEnum(gl, funcs.dfactor || "oneMinusSrcAlpha")); + }, + + blendFuncSeparate: function (gl, func) { + if (!gl) { + func = func || {}; + return { + srcRGB: func.srcRGB || "zero", + dstRGB: func.dstRGB || "zero", + srcAlpha: func.srcAlpha || "zero", + dstAlpha: func.dstAlpha || "zero" + }; + } + gl.blendFuncSeparate( + glEnum(gl, func.srcRGB || "zero"), + glEnum(gl, func.dstRGB || "zero"), + glEnum(gl, func.srcAlpha || "zero"), + glEnum(gl, func.dstAlpha || "zero")); + }, + + clearColor: function (gl, color) { + if (!gl) { + color = color || {}; + return { + r: color.r || 0, + g: color.g || 0, + b: color.b || 0, + a: (color.a == undefined || color.a == null) ? 1 : color.a + }; + } + gl.clearColor(color.r, color.g, color.b, color.a); + }, + + clearDepth: function (gl, depth) { + if (!gl) { + return (depth == null || depth == undefined) ? 1 : depth; + } + gl.clearDepth(depth); + }, + + clearStencil: function (gl, clearValue) { + if (!gl) { + return clearValue || 0; + } + gl.clearStencil(clearValue); + }, + + colorMask: function (gl, color) { + if (!gl) { + color = color || {}; + return { + r: color.r || 0, + g: color.g || 0, + b: color.b || 0, + a: (color.a == undefined || color.a == null) ? 1 : color.a + }; + + } + gl.colorMask(color.r, color.g, color.b, color.a); + }, + + enableCullFace: function (gl, flag) { + if (!gl) { + return flag; + } + if (flag) { + gl.enable(gl.CULL_FACE); + } else { + gl.disable(gl.CULL_FACE); + } + }, + + cullFace: function (gl, mode) { + if (!gl) { + return mode || "back"; + } + gl.cullFace(glEnum(gl, mode)); + }, + + enableDepthTest: function (gl, flag) { + if (!gl) { + if (flag == null || flag == undefined) { + flag = true; + } + return flag; + } + if (flag) { + gl.enable(gl.DEPTH_TEST); + } else { + gl.disable(gl.DEPTH_TEST); + } + }, + + depthFunc: function (gl, func) { + if (!gl) { + return func || "less"; + } + gl.depthFunc(glEnum(gl, func)); + }, + + enableDepthMask: function (gl, flag) { + if (!gl) { + if (flag == null || flag == undefined) { + flag = true; + } + return flag; + } + gl.depthMask(flag); + }, + + depthRange: function (gl, range) { + if (!gl) { + range = range || {}; + return { + zNear: (range.zNear == undefined || range.zNear == null) ? 0 : range.zNear, + zFar: (range.zFar == undefined || range.zFar == null) ? 1 : range.zFar + }; + } + gl.depthRange(range.zNear, range.zFar); + }, + + frontFace: function (gl, mode) { + if (!gl) { + return mode || "ccw"; + } + gl.frontFace(glEnum(gl, mode)); + }, + + lineWidth: function (gl, width) { + if (!gl) { + return width || 1; + } + gl.lineWidth(width); + }, + + enableScissorTest: function (gl, flag) { + if (!gl) { + return flag; + } + if (flag) { + gl.enable(gl.SCISSOR_TEST); + } else { + flag = false; + gl.disable(gl.SCISSOR_TEST); + } + } + }; + + /** + * Order-sensitive functions that immediately effect WebGL state change. + * + * These map to renderer properties and are called in a particular order since they + * affect one another. + * + * Each of these wrap a state-setter function on the WebGL gl. Each function + * also uses the glEnum map to convert its renderer node property argument to the + * WebGL enum constant required by its wrapped function. + * + * @private + */ + var glStateSetters = { + + /** Set viewport on the given gl + */ + viewport: function (gl, v) { + if (!gl) { + v = v || {}; + return { + x: v.x || 1, + y: v.y || 1, + width: v.width || canvas.canvas.width, + height: v.height || canvas.canvas.height + }; + } + gl.viewport(v.x, v.y, v.width, v.height); + }, + + /** Sets scissor region on the given gl + */ + scissor: function (gl, s) { + if (!gl) { + s = s || {}; + return { + x: s.x || 0, + y: s.y || 0, + width: s.width || 1.0, + height: s.height || 1.0 + }; + } + gl.scissor(s.x, s.y, s.width, s.height); + }, + + /** Clears buffers on the given gl as specified in mask + */ + clear: function (gl, mask) { + if (!gl) { + mask = mask || {}; + return mask; + } + var m; + if (mask.color) { + m = gl.COLOR_BUFFER_BIT; + } + if (mask.depth) { + m = m | gl.DEPTH_BUFFER_BIT; + } + if (mask.stencil) { + m = m | gl.STENCIL_BUFFER_BIT; + } + if (m) { + // gl.clear(m); + } + } + }; + + SceneJS.Renderer = SceneJS_NodeFactory.createNodeType("renderer"); + + SceneJS.Renderer.prototype._init = function (params) { + if (this._core.useCount == 1) { // This node defines the resource + for (var key in params) { + if (params.hasOwnProperty(key)) { + this._core[key] = params[key]; + } + } + this._core.dirty = true; + } + }; + + SceneJS.Renderer.prototype.setViewport = function (viewport) { + this._core.viewport = viewport ? { + x: viewport.x || 1, + y: viewport.y || 1, + width: viewport.width || 1000, + height: viewport.height || 1000 + } : undefined; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getViewport = function () { + return this._core.viewport ? { + x: this._core.viewport.x, + y: this._core.viewport.y, + width: this._core.viewport.width, + height: this._core.viewport.height + } : undefined; + }; + + SceneJS.Renderer.prototype.setScissor = function (scissor) { + this._core.scissor = scissor ? { + x: scissor.x || 1, + y: scissor.y || 1, + width: scissor.width || 1000, + height: scissor.height || 1000 + } : undefined; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getScissor = function () { + return this._core.scissor ? { + x: this._core.scissor.x, + y: this._core.scissor.y, + width: this._core.scissor.width, + height: this._core.scissor.height + } : undefined; + }; + + SceneJS.Renderer.prototype.setClear = function (clear) { + this._core.clear = clear ? { + r: clear.r || 0, + g: clear.g || 0, + b: clear.b || 0 + } : undefined; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getClear = function () { + return this._core.clear ? { + r: this._core.clear.r, + g: this._core.clear.g, + b: this._core.clear.b + } : null; + }; + + SceneJS.Renderer.prototype.setEnableBlend = function (enableBlend) { + this._core.enableBlend = enableBlend; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getEnableBlend = function () { + return this._core.enableBlend; + }; + + SceneJS.Renderer.prototype.setBlendColor = function (color) { + this._core.blendColor = color ? { + r: color.r || 0, + g: color.g || 0, + b: color.b || 0, + a: (color.a == undefined || color.a == null) ? 1 : color.a + } : undefined; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getBlendColor = function () { + return this._core.blendColor ? { + r: this._core.blendColor.r, + g: this._core.blendColor.g, + b: this._core.blendColor.b, + a: this._core.blendColor.a + } : undefined; + }; + + SceneJS.Renderer.prototype.setBlendEquation = function (eqn) { + this._core.blendEquation = eqn; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getBlendEquation = function () { + return this._core.blendEquation; + }; + + SceneJS.Renderer.prototype.setBlendEquationSeparate = function (eqn) { + this._core.blendEquationSeparate = eqn ? { + rgb: eqn.rgb || "funcAdd", + alpha: eqn.alpha || "funcAdd" + } : undefined; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getBlendEquationSeparate = function () { + return this._core.blendEquationSeparate ? { + rgb: this._core.rgb, + alpha: this._core.alpha + } : undefined; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.setBlendFunc = function (funcs) { + this._core.blendFunc = funcs ? { + sfactor: funcs.sfactor || "srcAlpha", + dfactor: funcs.dfactor || "one" + } : undefined; + this._core.dirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.Renderer.prototype.getBlendFunc = function () { + return this._core.blendFunc ? { + sfactor: this._core.sfactor, + dfactor: this._core.dfactor + } : undefined; + }; + + SceneJS.Renderer.prototype.setBlendFuncSeparate = function (eqn) { + this._core.blendFuncSeparate = eqn ? { + srcRGB: eqn.srcRGB || "zero", + dstRGB: eqn.dstRGB || "zero", + srcAlpha: eqn.srcAlpha || "zero", + dstAlpha: eqn.dstAlpha || "zero" + } : undefined; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getBlendFuncSeparate = function () { + return this._core.blendFuncSeparate ? { + srcRGB: this._core.blendFuncSeparate.srcRGB, + dstRGB: this._core.blendFuncSeparate.dstRGB, + srcAlpha: this._core.blendFuncSeparate.srcAlpha, + dstAlpha: this._core.blendFuncSeparate.dstAlpha + } : undefined; + }; + + SceneJS.Renderer.prototype.setEnableCullFace = function (enableCullFace) { + this._core.enableCullFace = enableCullFace; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getEnableCullFace = function () { + return this._core.enableCullFace; + }; + + + SceneJS.Renderer.prototype.setCullFace = function (cullFace) { + this._core.cullFace = cullFace; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getCullFace = function () { + return this._core.cullFace; + }; + + SceneJS.Renderer.prototype.setEnableDepthTest = function (enableDepthTest) { + this._core.enableDepthTest = enableDepthTest; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getEnableDepthTest = function () { + return this._core.enableDepthTest; + }; + + SceneJS.Renderer.prototype.setDepthFunc = function (depthFunc) { + this._core.depthFunc = depthFunc; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getDepthFunc = function () { + return this._core.depthFunc; + }; + + SceneJS.Renderer.prototype.setEnableDepthMask = function (enableDepthMask) { + this._core.enableDepthMask = enableDepthMask; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getEnableDepthMask = function () { + return this._core.enableDepthMask; + }; + + SceneJS.Renderer.prototype.setClearDepth = function (clearDepth) { + this._core.clearDepth = clearDepth; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getClearDepth = function () { + return this._core.clearDepth; + }; + + SceneJS.Renderer.prototype.setDepthRange = function (range) { + this._core.depthRange = range ? { + zNear: (range.zNear == undefined || range.zNear == null) ? 0 : range.zNear, + zFar: (range.zFar == undefined || range.zFar == null) ? 1 : range.zFar + } : undefined; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getDepthRange = function () { + return this._core.depthRange ? { + zNear: this._core.depthRange.zNear, + zFar: this._core.depthRange.zFar + } : undefined; + }; + + SceneJS.Renderer.prototype.setFrontFace = function (frontFace) { + this._core.frontFace = frontFace; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getFrontFace = function () { + return this._core.frontFace; + }; + + SceneJS.Renderer.prototype.setLineWidth = function (lineWidth) { + this._core.lineWidth = lineWidth; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getLineWidth = function () { + return this._core.lineWidth; + }; + + SceneJS.Renderer.prototype.setEnableScissorTest = function (enableScissorTest) { + this._core.enableScissorTest = enableScissorTest; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getEnableScissorTest = function () { + return this._core.enableScissorTest; + }; + + SceneJS.Renderer.prototype.setClearStencil = function (clearStencil) { + this._core.clearStencil = clearStencil; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getClearStencil = function () { + return this._core.clearStencil; + }; + + SceneJS.Renderer.prototype.setColorMask = function (color) { + this._core.colorMask = color ? { + r: color.r || 0, + g: color.g || 0, + b: color.b || 0, + a: (color.a == undefined || color.a == null) ? 1 : color.a + } : undefined; + this._core.dirty = true; + }; + + SceneJS.Renderer.prototype.getColorMask = function () { + return this._core.colorMask ? { + r: this._core.colorMask.r, + g: this._core.colorMask.g, + b: this._core.colorMask.b, + a: this._core.colorMask.a + } : undefined; + }; + + SceneJS.Renderer.prototype._compile = function (ctx) { + if (this._core.dirty) { + this._core.props = createProps(this._core); + this._core.dirty = false; + } + this._engine.display.renderer = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.renderer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; +})();;(function () { + + var lookup = { + less:"LESS", + equal:"EQUAL", + lequal:"LEQUAL", + greater:"GREATER", + notequal:"NOTEQUAL", + gequal:"GEQUAL" + }; + + // The default state core singleton for {@link SceneJS.DepthBuf} nodes + var defaultCore = { + type:"depthBuffer", + stateId:SceneJS._baseStateId++, + enabled:true, + clearDepth:1, + depthFunc:null, // Lazy init depthFunc when we can get a context + _depthFuncName:"less" + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + if (defaultCore.depthFunc === null) { // Lazy-init depthFunc now we can get a context + defaultCore.depthFunc = params.engine.canvas.gl.LESS; + } + params.engine.display.depthBuffer = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which configures the depth buffer for its subgraph + * @extends SceneJS.Node + */ + SceneJS.DepthBuf = SceneJS_NodeFactory.createNodeType("depthBuffer"); + + SceneJS.DepthBuf.prototype._init = function (params) { + + if (params.enabled != undefined) { + this.setEnabled(params.enabled); + } else if (this._core.useCount == 1) { // This node defines the core + this.setEnabled(true); + } + + if (params.clearDepth != undefined) { + this.setClearDepth(params.clearDepth); + } else if (this._core.useCount == 1) { + this.setClearDepth(1); + } + + if (params.depthFunc != undefined) { + this.setDepthFunc(params.depthFunc); + } else if (this._core.useCount == 1) { + this.setDepthFunc("less"); + } + + if (params.clear != undefined) { + this.setClear(params.clear); + } else if (this._core.useCount == 1) { + this.setClear(true); + } + }; + + /** + * Enable or disable the depth buffer + * + * @param enabled Specifies whether depth buffer is enabled or not + * @return {*} + */ + SceneJS.DepthBuf.prototype.setEnabled = function (enabled) { + if (this._core.enabled != enabled) { + this._core.enabled = enabled; + this._engine.display.imageDirty = true; + } + return this; + }; + + /** + * Get whether or not the depth buffer is enabled + * + * @return Boolean + */ + SceneJS.DepthBuf.prototype.getEnabled = function () { + return this._core.enabled; + }; + + /** + * Sets whether or not to clear the depth buffer before each render + * + * @param clear + * @return {*} + */ + SceneJS.DepthBuf.prototype.setClear = function (clear) { + if (this._core.clear != clear) { + this._core.clear = clear; + this._engine.display.imageDirty = true; + } + return this; + }; + + /** + * Get whether or not the depth buffer is cleared before each render + * + * @return Boolean + */ + SceneJS.DepthBuf.prototype.getClear = function () { + return this._core.clear; + }; + + /** + * Specify the clear value for the depth buffer. + * Initial value is 1, and the given value will be clamped to [0..1]. + * @param clearDepth + * @return {*} + */ + SceneJS.DepthBuf.prototype.setClearDepth = function (clearDepth) { + if (this._core.clearDepth != clearDepth) { + this._core.clearDepth = clearDepth; + this._engine.display.imageDirty = true; + } + return this; + }; + + /** + * Get the clear value for the depth buffer + * + * @return Number + */ + SceneJS.DepthBuf.prototype.getClearDepth = function () { + return this._core.clearDepth; + }; + + /** + * Sets the depth comparison function. + * Supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal' + * @param {String} depthFunc The depth comparison function + * @return {*} + */ + SceneJS.DepthBuf.prototype.setDepthFunc = function (depthFunc) { + if (this._core._depthFuncName != depthFunc) { + var enumName = lookup[depthFunc]; + if (enumName == undefined) { + throw "unsupported value for 'clearFunc' attribute on depthBuffer node: '" + depthFunc + + "' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'"; + } + this._core.depthFunc = this._engine.canvas.gl[enumName]; + this._core._depthFuncName = depthFunc; + this._engine.display.imageDirty = true; + } + return this; + }; + + /** + * Returns the depth comparison function + * @return {*} + */ + SceneJS.DepthBuf.prototype.getDepthFunc = function () { + return this._core._depthFuncName; + }; + + SceneJS.DepthBuf.prototype._compile = function (ctx) { + this._engine.display.depthBuffer = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.depthBuffer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})();;(function () { + + // The default state core singleton for {@link SceneJS.ColorBuffer} nodes + var defaultCore = { + type: "colorBuffer", + stateId: SceneJS._baseStateId++, + blendEnabled: false, + colorMask: { r: true, g: true, b: true, a: true } + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.colorBuffer = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which configures the color buffer for its subgraph + * @extends SceneJS.Node + */ + SceneJS.ColorBuffer = SceneJS_NodeFactory.createNodeType("colorBuffer"); + + SceneJS.ColorBuffer.prototype._init = function (params) { + if (params.blendEnabled != undefined) { + this.setBlendEnabled(params.blendEnabled); + } else if (this._core.useCount == 1) { // This node defines the core + this.setBlendEnabled(false); + } + this.setColorMask(params); + }; + + /** + * Enable or disable blending + * + * @param blendEnabled Specifies whether depth buffer is blendEnabled or not + */ + SceneJS.ColorBuffer.prototype.setBlendEnabled = function (blendEnabled) { + if (this._core.blendEnabled != blendEnabled) { + this._core.blendEnabled = blendEnabled; + this._engine.display.imageDirty = true; + } + this._engine.display.imageDirty = true; + }; + + /** + * Get whether or not blending is enabled + * @return Boolean + */ + SceneJS.ColorBuffer.prototype.getBlendEnabled = function () { + return this._core.blendEnabled; + }; + + /** + * Enable and disable writing of buffer's color components. + * Components default to true where not given. + * @param mask The mask + */ + SceneJS.ColorBuffer.prototype.setColorMask = function (mask) { + this._core.colorMask = { + r: mask.r != undefined && mask.r != null ? mask.r : true, + g: mask.g != undefined && mask.g != null ? mask.g : true, + b: mask.b != undefined && mask.b != null ? mask.b : true, + a: mask.a != undefined && mask.a != null ? mask.a : true + }; + this._engine.display.imageDirty = true; + }; + + /** + * Gets the color mask + * @return {{}} + */ + SceneJS.ColorBuffer.prototype.getColorMask = function () { + return this._core.colorMask; + }; + + SceneJS.ColorBuffer.prototype._compile = function (ctx) { + this._engine.display.colorBuffer = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.colorBuffer = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + this._engine.display.imageDirty = true; + }; + +})();;(function () { + + // The default state core singleton for {@link SceneJS.View} nodes + var defaultCore = { + type:"view", + stateId:SceneJS._baseStateId++, + scissorTestEnabled:false + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.view = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which configures view parameters such as depth range, scissor test and viewport + * @extends SceneJS.Node + * void depthRange(floatzNear, floatzFar) + zNear: Clamped to the range 0 to 1 Must be <= zFar + zFar: Clamped to the range 0 to 1. + void scissor(int x, int y, long width, long height) + void viewport(int x, int y, long width, long height) + */ + SceneJS.View = SceneJS_NodeFactory.createNodeType("view"); + + SceneJS.View.prototype._init = function (params) { + + if (params.scissorTestEnabled != undefined) { + this.setScissorTestEnabled(params.scissorTestEnabled); + } else if (this._core.useCount == 1) { // This node defines the core + this.setScissorTestEnabled(false); + } + }; + + /** + * Enable or disables scissor test. + * + * When enabled, the scissor test will discards fragments that are outside the scissor box. + * + * Scissor test is initially disabled. + * + * @param scissorTestEnabled Specifies whether scissor test is enabled or not + * @return {*} + */ + SceneJS.View.prototype.setScissorTestEnabled = function (scissorTestEnabled) { + if (this._core.scissorTestEnabled != scissorTestEnabled) { + this._core.scissorTestEnabled = scissorTestEnabled; + this._engine.display.imageDirty = true; + } + return this; + }; + + /** + * Get whether or not scissor test is enabled. + * Initial value will be false. + * + * @return Boolean + */ + SceneJS.View.prototype.getScissorTestEnabled = function () { + return this._core.scissorTestEnabled; + }; + + SceneJS.View.prototype._compile = function (ctx) { + this._engine.display.view = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.view = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})();;/** + * @class The root node of a scenegraph + * @extends SceneJS.Node + * + */ + +SceneJS.Scene = SceneJS_NodeFactory.createNodeType("scene"); + +SceneJS.Scene.prototype._init = function (params) { + + if (params.tagMask) { + this.setTagMask(params.tagMask); + } + + this._tagSelector = null; + + /** + * Set false when canvas is to be transparent. + * @type {boolean} + */ + this.transparent = (params.transparent === true); +}; + + +/** + * Simulate a lost WebGL context for testing purposes. + * Only works if the simulateWebGLLost was given as an option to {@link SceneJS.createScene}. + */ +SceneJS.Scene.prototype.loseWebGLContext = function () { + this._engine.loseWebGLContext(); +}; + + +/** + * Returns the HTML canvas for this scene + * @return {HTMLCanvas} The canvas + */ +SceneJS.Scene.prototype.getCanvas = function () { + return this._engine.canvas.canvas; +}; + +/** + * Returns the WebGL context for this scene + */ +SceneJS.Scene.prototype.getGL = function () { + return this._engine.canvas.gl; +}; + +/** Returns the Z-buffer depth in bits of the webgl context that this scene is to bound to. + */ +SceneJS.Scene.prototype.getZBufferDepth = function () { + var gl = this._engine.canvas.gl; + return gl.getParameter(gl.DEPTH_BITS); +}; + +/** + * Set canvas size multiplier for supersample anti-aliasing + */ +SceneJS.Scene.prototype.setSSAAMultiplier = function (ssaaMultiplier) { + return this._engine.canvas.setSSAAMultiplier(ssaaMultiplier); +}; + +/** + * Sets a regular expression to select which of the scene subgraphs that are rooted by {@link SceneJS.Tag} nodes are included in scene renders + * @param {String} [tagMask] Regular expression string to match on the tag attributes of {@link SceneJS.Tag} nodes. Nothing is selected when this is omitted. + * @see #getTagMask + * @see SceneJS.Tag + */ +SceneJS.Scene.prototype.setTagMask = function (tagMask) { + tagMask = tagMask || "XXXXXXXXXXXXXXXXXXXXXXXXXX"; // HACK to select nothing by default + if (!this._tagSelector) { + this._tagSelector = {}; + } + this._tagSelector.mask = tagMask; + this._tagSelector.regex = tagMask ? new RegExp(tagMask) : null; + this._engine.display.selectTags(this._tagSelector); +}; + +/** + * Gets the regular expression which will select which of the scene subgraphs that are rooted by {@link SceneJS.Tag} nodes are included in scene renders + * @see #setTagMask + * @see SceneJS.Tag + * @returns {String} Regular expression string that will be matched on the tag attributes of {@link SceneJS.Tag} nodes + */ +SceneJS.Scene.prototype.getTagMask = function () { + return this._tagSelector ? this._tagSelector.mask : null; +}; + +/** + * Sets the number of times this scene is drawn on each render. + *

This is useful for when we need to do things like render for left and right eyes. + * @param {Number} numPasses The number of times the scene is drawn on each frame. + * @see #getTagMask + * @see SceneJS.Tag + */ +SceneJS.Scene.prototype.setNumPasses = function (numPasses) { + this._engine.setNumPasses(numPasses); +}; + +/** + * Render a single frame if new frame pending, or force a new frame + * Returns true if frame rendered + */ +SceneJS.Scene.prototype.renderFrame = function (params) { + return this._engine.renderFrame(params); +}; + +/** + * Signals that a new frame will be needed + * @param params + */ +SceneJS.Scene.prototype.needFrame = function () { + this._engine.display.imageDirty = true; +}; + +/** + * Starts the render loop for this scene + */ +SceneJS.Scene.prototype.start = function (params) { + this._engine.start(params); +}; + +/** + * Set refresh rate for the scene + */ +SceneJS.Scene.prototype.setFPS = function (fps) { + this._engine.fps = fps; +}; + +/** + * Pauses/unpauses current render loop that was started with {@link #start}. After this, {@link #isRunning} will return false. + * @param {Boolean} doPause Indicates whether to pause or unpause the render loop + */ +SceneJS.Scene.prototype.pause = function (doPause) { + this._engine.pause(doPause); +}; + +/** + * Returns true if the scene's render loop is currently running. + * @returns {Boolean} True when scene render loop is running + */ +SceneJS.Scene.prototype.isRunning = function () { + return this._engine.running; +}; + +/** + * Picks whatever geometry will be rendered at the given canvas coordinates. + */ +SceneJS.Scene.prototype.pick = function (canvasX, canvasY, options) { + var result = this._engine.pick(canvasX, canvasY, options); + this.renderFrame({force: true }); // HACK: canvas blanks after picking + if (result) { + this.publish("pick", result); + return result; + } else { + this.publish("nopick"); + } +}; + + +/** + * Reads colors of pixels from the last rendered frame. + * + *

Call this method like this:

+ * + *
+ * #readPixels([
+ *      { x: 100, y: 22,  r: 0, g: 0, b: 0 },
+ *      { x: 120, y: 82,  r: 0, g: 0, b: 0 },
+ *      { x: 12,  y: 345, r: 0, g: 0, b: 0 }
+ * ], 3);
+ * 
+ * + * Then the r,g,b components of the entries will be set to the colors at those pixels. + */ +SceneJS.Scene.prototype.readPixels = function (entries, size) { + return this._engine.readPixels(entries, size); +}; + +/** + * Scene node's destroy handler, called by {@link SceneJS_node#destroy} + * @private + */ +SceneJS.Scene.prototype._destroy = function () { + if (!this.destroyed) { + delete SceneJS._engines[this.id]; // HACK: circular dependency + SceneJS._engineIds.removeItem(this.id); // HACK: circular dependency + this.destroyed = true; + } +}; + +/** + * Returns true if scene active, ie. not destroyed. A destroyed scene becomes active again + * when you render it. + */ +SceneJS.Scene.prototype.isActive = function () { + return !this._engine.destroyed; +}; + +/** + * Stops current render loop that was started with {@link #start}. After this, {@link #isRunning} will return false. + */ +SceneJS.Scene.prototype.stop = function () { + this._engine.stop(); +}; + +/** Determines if node exists in this scene + * @deprecated + */ +SceneJS.Scene.prototype.containsNode = function (nodeId) { + return !!this._engine.findNode(nodeId); +}; + +/** + * Finds nodes in this scene that have nodes IDs matching the given regular expression + * + * @param {String} nodeIdRegex Regular expression to match on node IDs + * @return {[SceneJS.Node]} Array of nodes whose IDs match the given regex + */ +SceneJS.Scene.prototype.findNodes = function (nodeIdRegex) { + return this._engine.findNodes(nodeIdRegex); +}; + +/** + * Finds the node with the given ID in this scene + * @deprecated + * @param {String} nodeId Node ID + * @param {Function} callback Callback through which we'll get the node asynchronously if it's being instantiated on-demand from a node type plugin + * @return {SceneJS.Node} The node if found, else null + */ +SceneJS.Scene.prototype.findNode = function (nodeId, callback) { + return this.getNode(nodeId, callback); +}; + +/** + * @function Finds the node with the given ID in this scene + * @param {String} nodeId Node ID + * @param {Function} callback Callback through which we'll get the node asynchronously if it's being instantiated on-demand from a node type plugin + * @return {SceneJS.Node} The node if found, else null + */ +SceneJS.Scene.prototype.getNode = function (nodeId, callback) { + var node = this._engine.findNode(nodeId); + if (node) { + if (callback) { + callback(node); + } + return node; + } else { + if (!callback) { + return null; + } + // Subscribe to instantiation of node from plugin + this.once("nodes/" + nodeId, callback); + } +}; + +/** + * Tests whether a node core of the given ID exists for the given node type + * @param {String} type Node type + * @param {String} coreId + * @returns Boolean + */ +SceneJS.Scene.prototype.hasCore = function (type, coreId) { + return this._engine.hasCore(type, coreId); +}; + +/** + * Returns the current status of this scene. + * + * When the scene has been destroyed, the returned status will be a map like this: + * + * { + * destroyed: true + * } + * + * Otherwise, the status will be: + * + * { + * numTasks: Total number of asset loads (eg. texture, geometry stream etc.) currently in progress for this scene + * } + * + */ +SceneJS.Scene.prototype.getStatus = function () { + var sceneStatus = SceneJS_sceneStatusModule.sceneStatus[this.id]; + if (!sceneStatus) { + return { + destroyed: true + }; + } + return SceneJS._shallowClone(sceneStatus); +}; +;new (function() { + + /** + * The default state core singleton for {@link SceneJS.Shader} nodes + */ + var defaultCore = { + type: "shader", + stateId: SceneJS._baseStateId++, + hash: "", + empty: true, + shader : {} + }; + + var idStack = []; + var shaderVertexCodeStack = []; + var shaderVertexHooksStack = []; + var shaderFragmentCodeStack = []; + var shaderFragmentHooksStack = []; + var shaderParamsStack = []; + + var stackLen = 0; + + var dirty = true; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function(params) { + + params.engine.display.shader = defaultCore; + + stackLen = 0; + + dirty = true; + }); + + SceneJS_events.addListener( + SceneJS_events.OBJECT_COMPILING, + function(params) { + if (dirty) { + + if (stackLen > 0) { + + var core = { + type: "shader", + stateId: idStack[stackLen - 1], + hash: idStack.slice(0, stackLen).join("."), + + shaders: { + fragment: { + code: shaderFragmentCodeStack.slice(0, stackLen).join(""), + hooks: combineMapStack(shaderFragmentHooksStack) + }, + vertex: { + code: shaderVertexCodeStack.slice(0, stackLen).join(""), + hooks: combineMapStack(shaderVertexHooksStack) + } + }, + + paramsStack: shaderParamsStack.slice(0, stackLen) + }; + + params.display.shader = core; + + } else { + + params.display.shader = defaultCore; + } + + dirty = false; + } + }); + + function combineMapStack(maps) { + var map1; + var map2 = {}; + var name; + for (var i = 0; i < stackLen; i++) { + map1 = maps[i]; + for (name in map1) { + if (map1.hasOwnProperty(name)) { + map2[name] = map1[name]; + } + } + } + return map2; + } + + function pushHooks(hooks, hookStacks) { + var stack; + for (var key in hooks) { + if (hooks.hasOwnProperty(key)) { + stack = hookStacks[key]; + if (!stack) { + stack = hookStacks[key] = []; + } + stack.push(hooks[key]); + } + } + } + + SceneJS.Shader = SceneJS_NodeFactory.createNodeType("shader"); + + SceneJS.Shader.prototype._init = function(params) { + if (this._core.useCount == 1) { // This node is the resource definer + this._setShaders(params.shaders); + this.setParams(params.params); + } + }; + + SceneJS.Shader.prototype._setShaders = function(shaders) { + shaders = shaders || []; + this._core.shaders = {}; + var shader; + + for (var i = 0, len = shaders.length; i < len; i++) { + shader = shaders[i]; + + if (!shader.stage) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "shader 'stage' attribute expected"); + } + + var code; + if (shader.code) { + if (SceneJS._isArray(shader.code)) { + code = shader.code.join(""); + } else { + code = shader.code; + } + } + + this._core.shaders[shader.stage] = { + code: code, + hooks: shader.hooks + }; + } + }; + + SceneJS.Shader.prototype.setParams = function(params) { + params = params || {}; + var coreParams = this._core.params; + if (!coreParams) { + coreParams = this._core.params = {}; + } + for (var name in params) { + if (params.hasOwnProperty(name)) { + coreParams[name] = params[name]; + } + } + this._engine.display.imageDirty = true; + }; + + SceneJS.Shader.prototype.getParams = function() { + var coreParams = this._core.params; + if (!coreParams) { + return {}; + } + var params = {}; + for (var name in coreParams) { + if (coreParams.hasOwnProperty(name)) { + params[name] = coreParams[name]; + } + } + return params; + }; + + SceneJS.Shader.prototype._compile = function(ctx) { + + idStack[stackLen] = this._core.coreId; // Draw list node tied to core, not node + + var shaders = this._core.shaders; + + var fragment = shaders.fragment || {}; + var vertex = shaders.vertex || {}; + + shaderFragmentCodeStack[stackLen] = fragment.code || ""; + shaderFragmentHooksStack[stackLen] = fragment.hooks || {}; + + shaderVertexCodeStack[stackLen] = vertex.code || ""; + shaderVertexHooksStack[stackLen] = vertex.hooks || {}; + + shaderParamsStack[stackLen] = this._core.params || {}; + + stackLen++; + dirty = true; + + this._compileNodes(ctx); + + stackLen--; + dirty = true; + }; + +})();;new (function() { + + /** + * The default state core singleton for {@link SceneJS.ShaderParams} nodes + */ + var defaultCore = { + type: "shaderParams", + stateId: SceneJS._baseStateId++, + empty: true + }; + + var idStack = []; + var shaderParamsStack = []; + var stackLen = 0; + var dirty; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function(params) { + + params.engine.display.shaderParams = defaultCore; + + stackLen = 0; + dirty = true; + }); + + SceneJS_events.addListener( + SceneJS_events.OBJECT_COMPILING, + function(params) { + if (dirty) { + + if (stackLen > 0) { + var core = { + type: "shaderParams", + stateId: idStack[stackLen - 1], + paramsStack: shaderParamsStack.slice(0, stackLen) + }; + params.display.shaderParams = core; + + } else { + params.display.shaderParams = defaultCore; + } + + dirty = false; + } + }); + + SceneJS.ShaderParams = SceneJS_NodeFactory.createNodeType("shaderParams"); + + SceneJS.ShaderParams.prototype._init = function(params) { + if (this._core.useCount == 1) { // This node is the resource definer + this.setParams(params.params); + } + }; + + SceneJS.ShaderParams.prototype.setParams = function(params) { + params = params || {}; + var core = this._core; + if (!core.params) { + core.params = {}; + } + for (var name in params) { + if (params.hasOwnProperty(name)) { + core.params[name] = params[name]; + } + } + this._engine.display.imageDirty = true; + }; + + SceneJS.ShaderParams.prototype.getParams = function() { + var coreParams = this._core.params; + if (!coreParams) { + return {}; + } + var params = {}; + for (var name in coreParams) { + if (coreParams.hasOwnProperty(name)) { + params[name] = coreParams[name]; + } + } + return params; + }; + + SceneJS.ShaderParams.prototype._compile = function(ctx) { + + idStack[stackLen] = this._core.coreId; // Tie draw list state to core, not to scene node + shaderParamsStack[stackLen] = this._core.params; + stackLen++; + dirty = true; + + this._compileNodes(ctx); + + stackLen--; + dirty = true; + }; + +})();;(function () { + + // The default state core singleton for {@link SceneJS.Line} nodes + var defaultCore = { + type:"style", + stateId:SceneJS._baseStateId++, + lineWidth:1.0 + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.style = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which configures style parameters such as line width for subnodes + * @extends SceneJS.Node + */ + SceneJS.Style = SceneJS_NodeFactory.createNodeType("style"); + + SceneJS.Style.prototype._init = function (params) { + if (params.lineWidth != undefined) { + this.setLineWidth(params.lineWidth); + } + }; + + /** + * Sets the line width + * + * Line width is initially 1. + * + * @param lineWidth The line width + * @return {*} + */ + SceneJS.Style.prototype.setLineWidth = function (lineWidth) { + if (this._core.lineWidth != lineWidth) { + this._core.lineWidth = lineWidth; + this._engine.display.imageDirty = true; + } + return this; + }; + + /** + * Gets the line width + * Initial value will be 1. + * + * @return Boolean + */ + SceneJS.Style.prototype.getLineWidth = function () { + return this._core.lineWidth; + }; + + SceneJS.Style.prototype._compile = function (ctx) { + this._engine.display.style = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.style = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + +})();;(function() { + + /** + * The default state core singleton for {@link SceneJS.Tag} nodes + */ + var defaultCore = { + type: "tag", + stateId: SceneJS._baseStateId++, + tag : null + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function(params) { + params.engine.display.tag = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which assigns a symbolic tag name to the {@link SceneJS.Geometry} nodes in its subgraph. + * The subgraph can then be included or excluded from scene rendering using {@link SceneJS.Scene#setTagMask}. + * @extends SceneJS.Node + */ + SceneJS.Tag = SceneJS_NodeFactory.createNodeType("tag"); + + SceneJS.Tag.prototype._init = function(params) { + if (this._core.useCount == 1) { // This node defines the resource + if (!params.tag) { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "tag node attribute missing : 'tag'"); + } + this.setTag(params.tag); + } + }; + + SceneJS.Tag.prototype.setTag = function(tag) { + + var core = this._core; + + core.tag = tag; + core.pattern = null; // To be recomputed + core.matched = false; // To be rematched + + this._engine.display.drawListDirty = true; + }; + + SceneJS.Tag.prototype.getTag = function() { + return this._core.tag; + }; + + SceneJS.Tag.prototype._compile = function(ctx) { + this._engine.display.tag = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.tag = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; +})();;/** + * @class Scene graph node which defines textures to apply to the objects in its subgraph + *

This is the deprecated node type from SceneJS v3.2, which has been replaced by the "texture" node in ./texture.js

+ * @extends SceneJS.Node + */ +new (function () { + + // The default state core singleton for {@link SceneJS.Texture} nodes + var defaultCore = { + type:"texture", + stateId:SceneJS._baseStateId++, + empty:true, + hash:"" + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.texture = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which defines one or more textures to apply to the {@link SceneJS.Geometry} nodes in its subgraph + * @extends SceneJS.Node + */ + SceneJS.Texture = SceneJS_NodeFactory.createNodeType("_texture"); + + SceneJS.Texture.prototype._init = function (params) { + + if (this._core.useCount == 1) { // This node is the resource definer + + this._core.layers = []; + this._core.params = {}; + + // By default, wait for texture to load before building subgraph + var waitForLoad = params.waitForLoad == undefined ? true : params.waitForLoad; + + if (!params.layers) { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layers missing"); + } + + if (!SceneJS._isArray(params.layers)) { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layers should be an array"); + } + + var layerParams; + var gl = this._engine.canvas.gl; + + for (var i = 0; i < params.layers.length; i++) { + + layerParams = params.layers[i]; + + if (!layerParams.source && !layerParams.uri && !layerParams.src && !layerParams.colorTarget && !layerParams.video) { + + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layer " + i + " has no uri, src, source, colorTarget, video or canvasId specified"); + } + + if (layerParams.applyFrom) { + if (layerParams.applyFrom != "uv" && + layerParams.applyFrom != "uv2" && + layerParams.applyFrom != "normal" && + layerParams.applyFrom != "geometry") { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layer " + i + " applyFrom value is unsupported - " + + "should be either 'uv', 'uv2', 'normal' or 'geometry'"); + } + } + + if (layerParams.applyTo) { + if (layerParams.applyTo != "baseColor" && // Colour map (deprecated) + layerParams.applyTo != "color" && // Colour map + layerParams.applyTo != "specular" && // Specular map + layerParams.applyTo != "emit" && // Emission map + layerParams.applyTo != "alpha" && // Alpha map + layerParams.applyTo != "normals" && // Normal map + layerParams.applyTo != "shine") { // Shininess map + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layer " + i + " applyTo value is unsupported - " + + "should be either 'color', 'baseColor', 'specular' or 'normals'"); + } + } + + if (layerParams.blendMode) { + if (layerParams.blendMode != "add" && layerParams.blendMode != "multiply" && layerParams.blendMode != "mix") { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layer " + i + " blendMode value is unsupported - " + + "should be either 'add', 'multiply' or 'mix'"); + } + } + + if (layerParams.applyTo == "color") { + layerParams.applyTo = "baseColor"; + } + + var layer = SceneJS._apply(layerParams, { + waitForLoad:waitForLoad, + texture:null, + applyFrom:layerParams.applyFrom || "uv", + applyTo:layerParams.applyTo || "baseColor", + blendMode:layerParams.blendMode || "multiply", + blendFactor:(layerParams.blendFactor != undefined && layerParams.blendFactor != null) ? layerParams.blendFactor : 1.0, + translate:{ x:0, y:0}, + scale:{ x:1, y:1 }, + rotate:{ z:0.0 } + }); + + this._core.layers.push(layer); + + this._setLayerTransform(layerParams, layer); + + if (layer.colorTarget) { // Create from a colorTarget node preceeding this texture in the scene graph + var targetNode = this._engine.findNode(layer.colorTarget); + if (targetNode && targetNode.type == "colorTarget") { + layer.texture = targetNode._core.colorTarget.getTexture(); // TODO: what happens when the colorTarget is destroyed? + } + } else { // Create from texture node's layer configs + this._loadLayerTexture(gl, layer); + } + } + + var self = this; + + // WebGL restored handler - rebuilds the texture layers + this._core.webglRestored = function () { + + var layers = self._core.layers; + var gl = self._engine.canvas.gl; + + for (var i = 0, len = layers.length; i < len; i++) { + self._loadLayerTexture(gl, layers[i]); + } + }; + } + }; + + SceneJS.Texture.prototype._loadLayerTexture = function (gl, layer) { + + var self = this; + + var sourceConfigs = layer.source; + + if (sourceConfigs) { + + if (!sourceConfigs.type) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "texture layer config expected: source.type"); + } + + SceneJS.Plugins.getPlugin( + "texture", + sourceConfigs.type, + function (plugin) { + + if (!plugin.getSource) { + throw SceneJS_error.fatalError( + SceneJS.errors.PLUGIN_INVALID, + "texture: 'getSource' method missing on plugin for texture source type '" + sourceConfigs.type + "'."); + } + + var source = plugin.getSource({ gl:gl }); + + if (!source.subscribe) { + throw SceneJS_error.fatalError( + SceneJS.errors.PLUGIN_INVALID, + "texture: 'subscribe' method missing on plugin for texture source type '" + sourceConfigs.type + "'"); + } + + var taskId = SceneJS_sceneStatusModule.taskStarted(self, "Loading texture"); + + source.subscribe(// Get notification whenever source updates the texture + (function () { + var loaded = false; + return function (texture) { + if (!loaded) { // Texture first initialised - create layer + loaded = true; + self._setLayerTexture(gl, layer, texture); + SceneJS_sceneStatusModule.taskFinished(taskId); + } else { // Texture updated - layer already has the handle to it, so just signal a redraw + self._engine.display.imageDirty = true; + } + }; + })()); + + if (source.configure) { + source.configure(sourceConfigs); // Configure the source, which may cause it to update the texture + } + + layer._source = source; + }); + + } else { + + /* Load from URL + */ + + var src = layer.uri || layer.src; + + var taskId = SceneJS_sceneStatusModule.taskStarted(this, "Loading texture"); + + var image = new Image(); + + image.onload = function () { + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + + var maxTextureSize = SceneJS_configsModule.configs.maxTextureSize; + if (maxTextureSize) { + image = SceneJS._webgl.clampImageSize(image, maxTextureSize); + } + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, self._ensureImageSizePowerOfTwo(image)); + self._setLayerTexture(gl, layer, texture); + SceneJS_sceneStatusModule.taskFinished(taskId); + self._engine.display.imageDirty = true; + }; + + image.onerror = function () { + SceneJS_sceneStatusModule.taskFailed(taskId); + }; + + if (src.indexOf("data") == 0) { // Image data + image.src = src; + } else { // Image file + image.crossOrigin = "Anonymous"; + image.src = src; + } + } + }; + + SceneJS.Texture.prototype._ensureImageSizePowerOfTwo = function (image) { + + if (!this._isPowerOfTwo(image.width) || !this._isPowerOfTwo(image.height)) { + + var canvas = document.createElement("canvas"); + canvas.width = this._nextHighestPowerOfTwo(image.width); + canvas.height = this._nextHighestPowerOfTwo(image.height); + + var ctx = canvas.getContext("2d"); + + ctx.drawImage(image, + 0, 0, image.width, image.height, + 0, 0, canvas.width, canvas.height); + + image = canvas; + image.crossOrigin = ""; + } + return image; + }; + + SceneJS.Texture.prototype._isPowerOfTwo = function (x) { + return (x & (x - 1)) == 0; + }; + + SceneJS.Texture.prototype._nextHighestPowerOfTwo = function (x) { + --x; + for (var i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; + }; + + SceneJS.Texture.prototype._setLayerTexture = function (gl, layer, texture) { + + layer.texture = new SceneJS._webgl.Texture2D(gl, { + texture:texture, // WebGL texture object + minFilter:this._getGLOption("minFilter", gl, layer, gl.LINEAR_MIPMAP_NEAREST), + magFilter:this._getGLOption("magFilter", gl, layer, gl.LINEAR), + wrapS:this._getGLOption("wrapS", gl, layer, gl.REPEAT), + wrapT:this._getGLOption("wrapT", gl, layer, gl.REPEAT), + isDepth:this._getOption(layer.isDepth, false), + depthMode:this._getGLOption("depthMode", gl, layer, gl.LUMINANCE), + depthCompareMode:this._getGLOption("depthCompareMode", gl, layer, gl.COMPARE_R_TO_TEXTURE), + depthCompareFunc:this._getGLOption("depthCompareFunc", gl, layer, gl.LEQUAL), + flipY:this._getOption(layer.flipY, true), + width:this._getOption(layer.width, 1), + height:this._getOption(layer.height, 1), + internalFormat:this._getGLOption("internalFormat", gl, layer, gl.LEQUAL), + sourceFormat:this._getGLOption("sourceType", gl, layer, gl.ALPHA), + sourceType:this._getGLOption("sourceType", gl, layer, gl.UNSIGNED_BYTE), + update:null + }); + + if (this.destroyed) { // Node was destroyed while loading + layer.texture.destroy(); + } + + this._engine.display.imageDirty = true; + }; + + SceneJS.Texture.prototype._getGLOption = function (name, gl, layer, defaultVal) { + var value = layer[name]; + if (value == undefined) { + return defaultVal; + } + var glName = SceneJS._webgl.enumMap[value]; + if (glName == undefined) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Unrecognised value for texture node property '" + name + "' value: '" + value + "'"); + } + var glValue = gl[glName]; + // if (!glValue) { + // throw new SceneJS.errors.WebGLUnsupportedNodeConfigException( + // "This browser's WebGL does not support value of SceneJS.texture node property '" + name + "' value: '" + value + "'"); + // } + return glValue; + }; + + SceneJS.Texture.prototype._getOption = function (value, defaultVal) { + return (value == undefined) ? defaultVal : value; + }; + + /** + * Set some writeable properties on a layer + */ + SceneJS.Texture.prototype.setLayer = function (cfg) { + + if (cfg.index == undefined || cfg.index == null) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Invalid texture set layer argument: index null or undefined"); + } + + if (cfg.index < 0 || cfg.index >= this._core.layers.length) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Invalid texture set layer argument: index out of range (" + this._core.layers.length + " layers defined)"); + } + + this._setLayer(parseInt(cfg.index), cfg); + + this._engine.display.imageDirty = true; + }; + + /** + * Set some writeable properties on multiple layers + */ + SceneJS.Texture.prototype.setLayers = function (layers) { + var indexNum; + for (var index in layers) { + if (layers.hasOwnProperty(index)) { + if (index != undefined || index != null) { + indexNum = parseInt(index); + if (indexNum < 0 || indexNum >= this._core.layers.length) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Invalid texture set layer argument: index out of range (" + this._core.layers.length + " layers defined)"); + } + this._setLayer(indexNum, layers[index] || {}); + } + } + } + this._engine.display.imageDirty = true; + }; + + SceneJS.Texture.prototype._setLayer = function (index, cfg) { + + cfg = cfg || {}; + + var layer = this._core.layers[index]; + + if (cfg.blendFactor != undefined && cfg.blendFactor != null) { + layer.blendFactor = cfg.blendFactor; + } + + if (cfg.source) { + var source = layer._source; + if (source && source.configure) { + source.configure(cfg.source); + } + } + + if (cfg.translate || cfg.rotate || cfg.scale) { + this._setLayerTransform(cfg, layer); + } + }; + + SceneJS.Texture.prototype._setLayerTransform = function (cfg, layer) { + + var matrix; + var t; + + if (cfg.translate) { + var translate = cfg.translate; + if (translate.x != undefined) { + layer.translate.x = translate.x; + } + if (translate.y != undefined) { + layer.translate.y = translate.y; + } + matrix = SceneJS_math_translationMat4v([ translate.x || 0, translate.y || 0, 0]); + } + + if (cfg.scale) { + var scale = cfg.scale; + if (scale.x != undefined) { + layer.scale.x = scale.x; + } + if (scale.y != undefined) { + layer.scale.y = scale.y; + } + t = SceneJS_math_scalingMat4v([ scale.x || 1, scale.y || 1, 1]); + matrix = matrix ? SceneJS_math_mulMat4(matrix, t) : t; + } + + if (cfg.rotate) { + var rotate = cfg.rotate; + if (rotate.z != undefined) { + layer.rotate.z = rotate.z || 0; + } + t = SceneJS_math_rotationMat4v(rotate.z * 0.0174532925, [0, 0, 1]); + matrix = matrix ? SceneJS_math_mulMat4(matrix, t) : t; + } + + if (matrix) { + layer.matrix = matrix; + if (!layer.matrixAsArray) { + layer.matrixAsArray = new Float32Array(layer.matrix); + } else { + layer.matrixAsArray.set(layer.matrix); + } + + layer.matrixAsArray = new Float32Array(layer.matrix); // TODO - reinsert into array + } + }; + + SceneJS.Texture.prototype._compile = function (ctx) { + if (!this._core.hash) { + this._makeHash(); + } + this._engine.display.texture = coreStack[stackLen++] = this._core; + this._compileNodes(ctx); + this._engine.display.texture = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + SceneJS.Texture.prototype._makeHash = function () { + var core = this._core; + var hash; + if (core.layers && core.layers.length > 0) { + var layers = core.layers; + var hashParts = []; + var texLayer; + for (var i = 0, len = layers.length; i < len; i++) { + texLayer = layers[i]; + hashParts.push("/"); + hashParts.push(texLayer.applyFrom); + hashParts.push("/"); + hashParts.push(texLayer.applyTo); + hashParts.push("/"); + hashParts.push(texLayer.blendMode); + if (texLayer.matrix) { + hashParts.push("/anim"); + } + } + hash = hashParts.join(""); + } else { + hash = ""; + } + if (core.hash != hash) { + core.hash = hash; + } + }; + + SceneJS.Texture.prototype._destroy = function () { + if (this._core.useCount == 1) { // Last resource user + var layers = this._core.layers; + var layer; + var source; + for (var i = 0, len = layers.length; i < len; i++) { + layer = layers[i]; + if (layer.texture) { + layer.texture.destroy(); + } + source = layer._source; + if (source && source.destroy) { + source.destroy(); + } + } + } + }; + +})();;/** + * @class Scene graph node which defines textures to apply to the objects in its subgraph + * @extends SceneJS.Node + */ +new (function () { + + // The default state core singleton for {@link SceneJS.Texture} nodes + var defaultCore = { + type: "texture", + stateId: SceneJS._baseStateId++, + empty: true, + hash: "" + }; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.texture = defaultCore; + stackLen = 0; + }); + + var coreStack = []; + var stackLen = 0; + + /** + * @class Scene graph node which defines one or more textures to apply to the {@link SceneJS.Geometry} nodes in its subgraph + * @extends SceneJS.Node + */ + SceneJS.TextureMap = SceneJS_NodeFactory.createNodeType("texture"); + + SceneJS.TextureMap.prototype._init = function (params) { + + var self = this; + + if (this._core.useCount == 1) { // This node is the resource definer + + if (params.applyFrom) { + if (params.applyFrom != "uv" && + params.applyFrom != "uv2" && + params.applyFrom != "normal" && + params.applyFrom != "geometry") { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture applyFrom value is unsupported - " + + "should be either 'uv', 'uv2', 'normal' or 'geometry'"); + } + } + + if (params.applyTo) { + if (params.applyTo != "baseColor" && // Colour map (deprecated) + params.applyTo != "color" && // Colour map + params.applyTo != "specular" && // Specular map + params.applyTo != "emit" && // Emission map + params.applyTo != "alpha" && // Alpha map + params.applyTo != "normals" && // Normal map + params.applyTo != "shine") { // Shininess map + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture applyTo value is unsupported - " + + "should be either 'color', 'baseColor', 'specular' or 'normals'"); + } + } + + if (params.blendMode) { + if (params.blendMode != "add" && params.blendMode != "multiply") { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "texture layer blendMode value is unsupported - " + + "should be either 'add' or 'multiply'"); + } + } + + if (params.applyTo == "color") { + params.applyTo = "baseColor"; + } + + SceneJS._apply({ + waitForLoad: params.waitForLoad == undefined ? true : params.waitForLoad, + texture: null, + applyFrom: !!params.applyFrom ? params.applyFrom : "uv", + applyTo: !!params.applyTo ? params.applyTo : "baseColor", + blendMode: !!params.blendMode ? params.blendMode : "multiply", + blendFactor: (params.blendFactor != undefined && params.blendFactor != null) ? params.blendFactor : 1.0, + translate: params.translate ? SceneJS._apply(params.translate, { x: 0, y: 0}) : {x: 0, y: 0}, + scale: params.scale ? SceneJS._apply(params.scale, { x: 1, y: 1}) : {x: 1, y: 1}, + rotate: params.rotate || 0, + matrix: null, + _matrixDirty: true, + buildMatrix: buildMatrix + }, + this._core); + + buildMatrix.call(this._core); + + if (params.src) { // Load from URL + this._core.src = params.src; + this._loadTexture(params.src); + + } else if (params.image) { // Create from image + this._core.image = params.image; + this._initTexture(params.image); + + } else if (params.target) { // Render to this texture + this.getScene().getNode(params.target, + function (target) { + self.setTarget(target); + }); + } + + this._core.webglRestored = function () { + if (self._core.image) { + self._initTexture(self._core.image); + + } else if (self._core.src) { + self._loadTexture(self._core.src); + + } else if (self._core.target) { +// self.getScene().getNode(params.target, +// function (target) { +// self.setTarget(self._core.target); +// }); + } + }; + } + }; + + function buildMatrix() { + var matrix; + var t; + if (this.translate.x != 0 || this.translate.y != 0) { + matrix = SceneJS_math_translationMat4v([ this.translate.x || 0, this.translate.y || 0, 0]); + } + if (this.scale.x != 1 || this.scale.y != 1) { + t = SceneJS_math_scalingMat4v([ this.scale.x || 1, this.scale.y || 1, 1]); + matrix = matrix ? SceneJS_math_mulMat4(matrix, t) : t; + } + if (this.rotate != 0) { + t = SceneJS_math_rotationMat4v(this.rotate * 0.0174532925, [0, 0, 1]); + matrix = matrix ? SceneJS_math_mulMat4(matrix, t) : t; + } + if (matrix) { + this.matrix = matrix; + if (!this.matrixAsArray) { + this.matrixAsArray = new Float32Array(this.matrix); + } else { + this.matrixAsArray.set(this.matrix); + } + } + this._matrixDirty = false; + } + + SceneJS.TextureMap.prototype._loadTexture = function (src) { + var self = this; + var taskId = SceneJS_sceneStatusModule.taskStarted(this, "Loading texture"); + var image = new Image(); + image.onload = function () { + self._initTexture(image); + SceneJS_sceneStatusModule.taskFinished(taskId); + self._engine.display.imageDirty = true; + }; + image.onerror = function () { + SceneJS_sceneStatusModule.taskFailed(taskId); + }; + if (src.indexOf("data") == 0) { // Image data + image.src = src; + } else { // Image file + image.crossOrigin = "Anonymous"; + image.src = src; + } + }; + + SceneJS.TextureMap.prototype._initTexture = function (image) { + + var gl = this._engine.canvas.gl; + + var texture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, texture); + + var maxTextureSize = SceneJS_configsModule.configs.maxTextureSize; + if (maxTextureSize) { + image = SceneJS._webgl.clampImageSize(image, maxTextureSize); + } + + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, SceneJS._webgl.ensureImageSizePowerOfTwo(image)); + + this._core.image = image; + + this._core.texture = new SceneJS._webgl.Texture2D(gl, { + texture: texture, // WebGL texture object + minFilter: this._getGLOption("minFilter", gl.LINEAR_MIPMAP_NEAREST), + magFilter: this._getGLOption("magFilter", gl.LINEAR), + wrapS: this._getGLOption("wrapS", gl.REPEAT), + wrapT: this._getGLOption("wrapT", gl.REPEAT), + isDepth: this._getOption(this._core.isDepth, false), + depthMode: this._getGLOption("depthMode", gl.LUMINANCE), + depthCompareMode: this._getGLOption("depthCompareMode", gl.COMPARE_R_TO_TEXTURE), + depthCompareFunc: this._getGLOption("depthCompareFunc", gl.LEQUAL), + flipY: this._getOption(this._core.flipY, true), + width: this._getOption(this._core.width, 1), + height: this._getOption(this._core.height, 1), + internalFormat: this._getGLOption("internalFormat", gl.ALPHA), + sourceFormat: this._getGLOption("sourceFormat", gl.ALPHA), + sourceType: this._getGLOption("sourceType", gl.UNSIGNED_BYTE), + update: null + }); + + if (this.destroyed) { // Node was destroyed while loading + this._core.texture.destroy(); + } + + this._engine.display.imageDirty = true; + }; + + SceneJS.TextureMap.prototype._getGLOption = function (name, defaultVal) { + var gl = this._engine.canvas.gl; + var value = this._core[name]; + if (value == undefined) { + return defaultVal; + } + var glName = SceneJS._webgl.enumMap[value]; + if (glName == undefined) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "Unrecognised value for texture node property '" + name + "' value: '" + value + "'"); + } + return gl[glName]; + }; + + SceneJS.TextureMap.prototype._getOption = function (value, defaultVal) { + return (value == undefined) ? defaultVal : value; + }; + + SceneJS.TextureMap.prototype.setSrc = function (src) { + this._core.image = null; + this._core.src = src; + this._core.target = null; + this._loadTexture(src); + }; + + SceneJS.TextureMap.prototype.setImage = function (image) { + this._core.image = image; + this._core.src = null; + this._core.target = null; + this._initTexture(image); + }; + + SceneJS.TextureMap.prototype.setTarget = function (target) { + if (target.type != "colorTarget" && target.type != "depthTarget") { + console.log("Target node type not compatible: " + target.type); + return; + } + delete this._core.src; + this._core.target = target; + this._core.src = null; + this._core.image = null; + this._core.texture = target._core.renderBuf.getTexture(); // TODO: what happens when the target is destroyed? + this._core.texture.bufType = target._core.bufType; + this._engine.display.imageDirty = true; + }; + + /** + * Sets the texture's blend factor with respect to other active textures. + * @param {number} blendFactor The blend factor, in range [0..1] + */ + SceneJS.TextureMap.prototype.setBlendFactor = function (blendFactor) { + this._core.blendFactor = blendFactor; + this._engine.display.imageDirty = true; + }; + + SceneJS.TextureMap.prototype.getBlendFactor = function () { + return this._core.blendFactor; + }; + + SceneJS.TextureMap.prototype.setTranslate = function (t) { + if (!this._core.translate) { + this._core.translate = {x: 0, y: 0}; + } + this._core.translate.x = t.x; + this._core.translate.y = t.y; + this._core._matrixDirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.TextureMap.prototype.getTranslate = function () { + return this._core.translate; + }; + + SceneJS.TextureMap.prototype.setScale = function (s) { + if (!this._core.scale) { + this._core.scale = {x: 0, y: 0}; + } + this._core.scale.x = s.x; + this._core.scale.y = s.y; + this._core._matrixDirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.TextureMap.prototype.getScale = function () { + return this._core.scale; + }; + + SceneJS.TextureMap.prototype.setRotate = function (angle) { + this._core.rotate = angle; + this._core._matrixDirty = true; + this._engine.display.imageDirty = true; + }; + + SceneJS.TextureMap.prototype.getRotate = function () { + return this._core.rotate; + }; + + SceneJS.TextureMap.prototype.getMatrix = function () { + if (this._core._matrixDirty) { + this._core.buildMatrix.call(this.core)() + } + return this.core.matrix; + }; + + SceneJS.TextureMap.prototype._compile = function (ctx) { + if (!this.__core) { + this.__core = this._engine._coreFactory.getCore("texture"); + } + var parentCore = this._engine.display.texture; + if (!this._core.empty) { + this.__core.layers = (parentCore && parentCore.layers) ? parentCore.layers.concat([this._core]) : [this._core]; + } + this._makeHash(this.__core); + coreStack[stackLen++] = this.__core; + this._engine.display.texture = this.__core; + this._compileNodes(ctx); + this._engine.display.texture = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + SceneJS.TextureMap.prototype._makeHash = function (core) { + var hash; + if (core.layers && core.layers.length > 0) { + var layers = core.layers; + var hashParts = []; + var texLayer; + for (var i = 0, len = layers.length; i < len; i++) { + texLayer = layers[i]; + hashParts.push("/"); + hashParts.push(texLayer.applyFrom); + hashParts.push("/"); + hashParts.push(texLayer.applyTo); + hashParts.push("/"); + hashParts.push(texLayer.blendMode); + if (texLayer.matrix) { + hashParts.push("/anim"); + } + } + hash = hashParts.join(""); + } else { + hash = ""; + } + if (core.hash != hash) { + core.hash = hash; + } + }; + + SceneJS.TextureMap.prototype._destroy = function () { + if (this._core.useCount == 1) { // Last core user + if (this._core.texture && !this._core.target) { // Don't wipe out target texture + this._core.texture.destroy(); + this._core.texture = null; + } + } + if (this._core) { + this._engine._coreFactory.putCore(this._core); + } + }; + +})();;(function () { + + // The default state core singleton for {@link SceneJS.ColorBuf} nodes + var defaultCore = { + type: "cubemap", + stateId: SceneJS._baseStateId++, + empty: true, + texture: null, + hash: "" + }; + + var coreStack = []; + var stackLen = 0; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function (params) { + params.engine.display.cubemap = defaultCore; + stackLen = 0; + }); + + /** + * @class Scene graph node which configures the color buffer for its subgraph + * @extends SceneJS.Node + */ + SceneJS.Reflect = SceneJS_NodeFactory.createNodeType("reflect"); + + SceneJS.Reflect.prototype._init = function (params) { + if (this._core.useCount == 1) { // This node is first to reference the state core, so sets it up + this._core.hash = "y"; + + if (params.blendMode) { + if (params.blendMode != "add" && params.blendMode != "multiply") { + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "reflection blendMode value is unsupported - " + + "should be either 'add' or 'multiply'"); + } + } + + this._core.blendMode = params.blendMode || "multiply"; + this._core.intensity = (params.intensity != undefined && params.intensity != null) ? params.intensity : 1.0; + this._core.applyTo = "reflect"; + + var self = this; + + var gl = this._engine.canvas.gl; + var texture = gl.createTexture(); + + var faces = [ + gl.TEXTURE_CUBE_MAP_POSITIVE_X, + gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ]; + + var images = []; + var taskId = SceneJS_sceneStatusModule.taskStarted(this, "Loading reflection texture"); + var loadFailed = false; + + for (var i = 0; i < faces.length; i++) { + + var image = new Image(); + + image.onload = (function() { + + var _image = image; + + return function () { + + if (loadFailed) { + return; + } + + images.push(_image); + + if (images.length == faces.length) { + + gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + + for (var j = 0, lenj = images.length; j < lenj; j++) { + gl.texImage2D(faces[j], 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, + SceneJS._webgl.ensureImageSizePowerOfTwo(images[j])); + } + + self._core.texture = new SceneJS._webgl.Texture2D(gl, { + texture: texture, + target: gl.TEXTURE_CUBE_MAP, + minFilter: gl.LINEAR, + magFilter: gl.LINEAR, + wrapS: gl.CLAMP_TO_EDGE, + wrapT: gl.CLAMP_TO_EDGE + }); + + SceneJS_sceneStatusModule.taskFinished(taskId); + + self._engine.display.imageDirty = true; + } + }; + })(); + + image.onerror = function () { + loadFailed = true; + SceneJS_sceneStatusModule.taskFailed(taskId); + }; + + image.src = params.src[i]; + } + } + }; + + SceneJS.Reflect.prototype._compile = function (ctx) { + if (!this.__core) { + this.__core = this._engine._coreFactory.getCore("cubemap"); + } + var parentCore = this._engine.display.cubemap; + if (!this._core.empty) { + this.__core.layers = (parentCore && parentCore.layers) ? parentCore.layers.concat([this._core]) : [this._core]; + } + this._makeHash(this.__core); + coreStack[stackLen++] = this.__core; + this._engine.display.cubemap = this.__core; + this._compileNodes(ctx); + this._engine.display.cubemap = (--stackLen > 0) ? coreStack[stackLen - 1] : defaultCore; + }; + + SceneJS.Reflect.prototype._makeHash = function (core) { + var hash; + if (core.layers && core.layers.length > 0) { + var layers = core.layers; + var hashParts = []; + var texLayer; + for (var i = 0, len = layers.length; i < len; i++) { + texLayer = layers[i]; + hashParts.push("/"); + hashParts.push(texLayer.applyTo); + hashParts.push("/"); + hashParts.push(texLayer.blendMode); + } + hash = hashParts.join(""); + } else { + hash = ""; + } + if (core.hash != hash) { + core.hash = hash; + } + }; + + SceneJS.Reflect.prototype._destroy = function () { + if (this._core.useCount == 1) { // Last resource user + if (this._core.texture) { + this._core.texture.destroy(); + this._core.texture = null; + } + } + if (this._core) { + this._engine._coreFactory.putCore(this._core); + } + } + +})();;/** + * @class Scene graph node which defines the modelling transform to apply to the objects in its subgraph + * @extends SceneJS.Node + */ +SceneJS.XForm = SceneJS_NodeFactory.createNodeType("xform"); + +SceneJS.XForm.prototype._init = function (params) { + + if (this._core.useCount == 1) { // This node is the resource definer + + SceneJS_modelXFormStack.buildCore(this._core); + + this.setElements(params.elements); + } +}; + +/** + * Get Model matrix + * @return {*} + */ +SceneJS.XForm.prototype.getModelMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return this._core.matrix; +}; + +/** + * Get World matrix. That's the multiplication of this node's Model matrix by the World matrix of the the next + * tranform (scale, XForm, translate etc) node on the path to the scene root. + * @return {*} + */ +SceneJS.XForm.prototype.getWorldMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return Array.apply( [], this._core.mat); +}; + + +SceneJS.XForm.prototype.setElements = function (elements) { + + elements = elements || SceneJS_math_identityMat4(); + + if (elements.length != 16) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.XForm elements should number 16"); + } + + var core = this._core; + + if (!core.matrix) { + core.matrix = elements; + + } else { + + for (var i = 0; i < 16; i++) { + core.matrix[i] = elements[i]; + } + } + +// core.mat.set(core.matrix); +// core.normalMat.set( +// SceneJS_math_transposeMat4( +// SceneJS_math_inverseMat4(core.matrix, SceneJS_math_mat4()))); + + + core.setDirty(); + + this._engine.display.imageDirty = true; + + return this; +}; + +SceneJS.XForm.prototype._compile = function (ctx) { + SceneJS_modelXFormStack.push(this._core); + this._compileNodes(ctx); + SceneJS_modelXFormStack.pop(); +}; +; +/** + * @class Scene graph node which defines a modelling transform matrix to apply to the objects in its subgraph + * @extends SceneJS.Node + */ +SceneJS.Matrix = SceneJS_NodeFactory.createNodeType("matrix"); + +SceneJS.Matrix.prototype._init = function(params) { + + if (this._core.useCount == 1) { // This node is the resource definer + + SceneJS_modelXFormStack.buildCore(this._core); + + this.setElements(params.elements); + } +}; + +/** + * Get Model matrix + * @return {*} + */ +SceneJS.Matrix.prototype.getModelMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return this._core.matrix; +}; + +/** + * Get World matrix. That's the multiplication of this node's Model matrix by the World matrix of the the next + * tranform (scale, matrix, translate etc) node on the path to the scene root. + * @return {*} + */ +SceneJS.Matrix.prototype.getWorldMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return Array.apply( [], this._core.mat); +}; + +/** + * Sets the matrix elements + * @type {Function} + */ +SceneJS.Matrix.prototype.setMatrix = function(elements) { + + elements = elements || SceneJS_math_identityMat4(); + + if (elements.length != 16) { + throw SceneJS_error.fatalError( + SceneJS.errors.ILLEGAL_NODE_CONFIG, + "SceneJS.Matrix elements should number 16"); + } + + var core = this._core; + + if (!core.matrix) { + core.matrix = elements; + + } else { + + for (var i = 0; i < 16; i++) { + core.matrix[i] = elements[i]; + } + } + + core.setDirty(); + + this._engine.display.imageDirty = true; + + return this; +}; + +/** + * Sets the matrix elements + * @deprecated + * @type {Function} + */ +SceneJS.Matrix.prototype.setElements = SceneJS.Matrix.prototype.setMatrix; + +SceneJS.Matrix.prototype._compile = function(ctx) { + SceneJS_modelXFormStack.push(this._core); + this._compileNodes(ctx); + SceneJS_modelXFormStack.pop(); +}; +;/** + * @class Scene graph node which defines a rotation modelling transform to apply to the objects in its subgraph + * @extends SceneJS.Node + */ +SceneJS.Rotate = SceneJS_NodeFactory.createNodeType("rotate"); + +SceneJS.Rotate.prototype._init = function(params) { + + if (this._core.useCount == 1) { // This node is the resource definer + + SceneJS_modelXFormStack.buildCore(this._core); + + this.setMultOrder(params.multOrder); + + this.setAngle(params.angle); + + this.setXYZ({ + x: params.x, + y: params.y, + z: params.z + }); + + var core = this._core; + + this._core.buildMatrix = function() { + core.matrix = SceneJS_math_rotationMat4v(core.angle * Math.PI / 180.0, [core.x, core.y, core.z]); + }; + } +}; + +/** + * Get Model matrix + * @return {*} + */ +SceneJS.Rotate.prototype.getModelMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return this._core.matrix; +}; + +/** + * Get World matrix. That's the multiplication of this node's Model matrix by the World matrix of the the next + * tranform (scale, rotate, translate etc) node on the path to the scene root. + * @return {*} + */ +SceneJS.Rotate.prototype.getWorldMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return Array.apply( [], this._core.mat); +}; + +/** + * Sets the multiplication order of this node's transform matrix with respect to the parent modeling transform + * in the scene graph. + * + * @param {String} multOrder Mulplication order - "post" and "pre" + */ +SceneJS.Rotate.prototype.setMultOrder = function(multOrder) { + + multOrder = multOrder || "post"; + + if (multOrder != "post" && multOrder != "pre") { + + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "Illegal multOrder for rotate node - '" + multOrder + "' should be 'pre' or 'post'"); + } + + this._core.multOrder = multOrder; + + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype.setAngle = function(angle) { + this._core.angle = angle || 0; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype.getAngle = function() { + return this._core.angle; +}; + +SceneJS.Rotate.prototype.setXYZ = function(xyz) { + + xyz = xyz || {}; + + this._core.x = xyz.x || 0; + this._core.y = xyz.y || 0; + this._core.z = xyz.z || 0; + + this._core.setDirty(); + + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype.getXYZ = function() { + return { + x: this._core.x, + y: this._core.y, + z: this._core.z + }; +}; + +SceneJS.Rotate.prototype.setX = function(x) { + this._core.x = x; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype.getX = function() { + return this._core.x; +}; + +SceneJS.Rotate.prototype.setY = function(y) { + this._core.y = y; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype.getY = function() { + return this._core.y; +}; + +SceneJS.Rotate.prototype.setZ = function(z) { + this._core.z = z; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype.getZ = function() { + return this._core.z; +}; + +SceneJS.Rotate.prototype.incAngle = function(angle) { + this._core.angle += angle; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Rotate.prototype._compile = function(ctx) { + SceneJS_modelXFormStack.push(this._core); + this._compileNodes(ctx); + SceneJS_modelXFormStack.pop(); +}; +;/** + * @class Scene graph node which defines a translation modelling transform to apply to the objects in its subgraph + * @extends SceneJS.Node + */ +SceneJS.Translate = SceneJS_NodeFactory.createNodeType("translate"); + +SceneJS.Translate.prototype._init = function(params) { + + if (this._core.useCount == 1) { // This node is the resource definer + + SceneJS_modelXFormStack.buildCore(this._core); + + this.setMultOrder(params.multOrder); + + this.setXYZ({ + x: params.x, + y: params.y, + z: params.z + }); + + var core = this._core; + + this._core.buildMatrix = function() { + core.matrix = SceneJS_math_translationMat4v([core.x, core.y, core.z], core.matrix); + }; + } +}; + +/** + * Get Model matrix + * @return {*} + */ +SceneJS.Translate.prototype.getModelMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return this._core.matrix; +}; + +/** + * Get World matrix. That's the multiplication of this node's Model matrix by the World matrix of the the next + * tranform (scale, translate, translate etc) node on the path to the scene root. + * @return {*} + */ +SceneJS.Translate.prototype.getWorldMatrix = function() { + if (this._core.dirty) { + this._core.build(); + } + return Array.apply( [], this._core.mat); +}; + + +/** + * Sets the multiplication order of this node's transform matrix with respect to the parent modeling transform + * in the scene graph. + * + * @param {String} multOrder Mulplication order - "post" and "pre" + */ +SceneJS.Translate.prototype.setMultOrder = function(multOrder) { + + multOrder = multOrder || "post"; + + if (multOrder != "post" && multOrder != "pre") { + + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "Illegal multOrder for translate node - '" + multOrder + "' should be 'pre' or 'post'"); + } + + this._core.multOrder = multOrder; + + this._core.setDirty(); + + this._engine.display.imageDirty = true; +}; + +SceneJS.Translate.prototype.setXYZ = function(xyz) { + + xyz = xyz || {}; + + this._core.x = xyz.x || 0; + this._core.y = xyz.y || 0; + this._core.z = xyz.z || 0; + + this._core.setDirty(); + + this._engine.display.imageDirty = true; + + return this; +}; + +SceneJS.Translate.prototype.getXYZ = function() { + return { + x: this._core.x, + y: this._core.y, + z: this._core.z + }; +}; + +SceneJS.Translate.prototype.setX = function(x) { + this._core.x = x; + this._core.setDirty(); + this._engine.display.imageDirty = true; + return this; +}; + +SceneJS.Translate.prototype.setY = function(y) { + this._core.y = y; + this._core.setDirty(); + this._engine.display.imageDirty = true; + return this; +}; + +SceneJS.Translate.prototype.setZ = function(z) { + this._core.z = z; + this._core.setDirty(); + this._engine.display.imageDirty = true; + return this; +}; + +SceneJS.Translate.prototype.incX = function(x) { + this._core.x += x; + this._core.setDirty(); + this._engine.display.imageDirty = true; + return this; +}; + +SceneJS.Translate.prototype.incY = function(y) { + this._core.y += y; + this._core.setDirty(); + this._engine.display.imageDirty = true; + return this; +}; + +SceneJS.Translate.prototype.incZ = function(z) { + this._core.z += z; + this._core.setDirty(); + this._engine.display.imageDirty = true; + return this; +}; + +SceneJS.Translate.prototype.getX = function() { + return this._core.x; +}; + +SceneJS.Translate.prototype.getY = function() { + return this._core.y; +}; + +SceneJS.Translate.prototype.getZ = function() { + return this._core.z; +}; + +SceneJS.Translate.prototype._compile = function(ctx) { + SceneJS_modelXFormStack.push(this._core); + this._compileNodes(ctx); + SceneJS_modelXFormStack.pop(); +}; +;/** + * @class Scene graph node which defines a rotation modelling transform to apply to the objects in its subgraph + * @extends SceneJS.Node + */ +SceneJS.Scale = SceneJS_NodeFactory.createNodeType("scale"); + +SceneJS.Scale.prototype._init = function (params) { + + if (this._core.useCount == 1) { // This node is the resource definer + + SceneJS_modelXFormStack.buildCore(this._core); + + this.setMultOrder(params.multOrder); + + this.setXYZ({ + x:params.x, + y:params.y, + z:params.z + }); + + var core = this._core; + + this._core.buildMatrix = function () { + core.matrix = SceneJS_math_scalingMat4v([core.x, core.y, core.z]); + }; + } +}; + +/** + * Get Model matrix + * @return {*} + */ +SceneJS.Scale.prototype.getModelMatrix = function () { + if (this._core.dirty) { + this._core.build(); + } + return this._core.matrix; +}; + +/** + * Get World matrix. That's the multiplication of this node's Model matrix by the World matrix of the the next + * tranform (scale, scale, translate etc) node on the path to the scene root. + * @return {*} + */ +SceneJS.Scale.prototype.getWorldMatrix = function () { + if (this._core.dirty) { + this._core.build(); + } + return Array.apply([], this._core.mat); +}; + +/** + * Sets the multiplication order of this node's transform matrix with respect to the parent modeling transform + * in the scene graph. + * + * @param {String} multOrder Mulplication order - "post" and "pre" + */ +SceneJS.Scale.prototype.setMultOrder = function (multOrder) { + + multOrder = multOrder || "post"; + + if (multOrder != "post" && multOrder != "pre") { + + throw SceneJS_error.fatalError( + SceneJS.errors.NODE_CONFIG_EXPECTED, + "Illegal multOrder for scale node - '" + multOrder + "' should be 'pre' or 'post'"); + } + + this._core.multOrder = multOrder; + + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype.setXYZ = function (xyz) { + + xyz = xyz || {}; + + this._core.x = xyz.x == undefined ? 1 : xyz.x; + this._core.y = xyz.y == undefined ? 1 : xyz.y; + this._core.z = xyz.z == undefined ? 1 : xyz.z; + + this._core.setDirty(); + + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype.getXYZ = function () { + return { + x:this._core.x, + y:this._core.y, + z:this._core.z + }; +}; + +SceneJS.Scale.prototype.setX = function (x) { + this._core.x = x; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype.setY = function (y) { + this._core.y = y; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype.setZ = function (z) { + this._core.z = z; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype.getX = function () { + return this._core.x; +}; + +SceneJS.Scale.prototype.getY = function () { + return this._core.y; +}; + +SceneJS.Scale.prototype.getZ = function () { + return this._core.z; +}; + +SceneJS.Scale.prototype.incX = function (x) { + this._core.x += x; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype.incY = function (y) { + this._core.y += y; + this._core.matrixDirty = true; +}; + +SceneJS.Scale.prototype.incZ = function (z) { + this._core.z += z; + this._core.setDirty(); + this._engine.display.imageDirty = true; +}; + +SceneJS.Scale.prototype._compile = function (ctx) { + SceneJS_modelXFormStack.push(this._core); + this._compileNodes(ctx); + SceneJS_modelXFormStack.pop(); +}; +;/** + * Provides a model transform stack in front of the renderer. + * Nodes peek push and pop to the stack, while the renderer peeks at + * the transform on the top of the stack whenever it builds a renderer node. + * + */ +var SceneJS_modelXFormStack = new (function () { + + var defaultMatrix = SceneJS_math_identityMat4(); + var defaultMat = new Float32Array(defaultMatrix); + + var defaultNormalMatrix = SceneJS_math_transposeMat4( + SceneJS_math_inverseMat4( + SceneJS_math_identityMat4(), + SceneJS_math_mat4())); + var defaultNormalMat = new Float32Array(defaultNormalMatrix); + + var defaultCore = { + type:"xform", + stateId:SceneJS._baseStateId++, + + matrix:defaultMatrix, + mat:defaultMat, + + normalMatrix:defaultNormalMatrix, + normalMat:defaultNormalMat, + + parent:null, // Parent transform core + cores:[], // Child transform cores + numCores:0, // Number of child transform cores + dirty:false, // Does this subtree need matrices rebuilt + matrixDirty:false + }; + + var transformStack = []; + var stackLen = 0; + + this.top = defaultCore; + + var dirty; + + var self = this; + + SceneJS_events.addListener( + SceneJS_events.SCENE_COMPILING, + function () { + stackLen = 0; + self.top = defaultCore; + dirty = true; + }); + + SceneJS_events.addListener( + SceneJS_events.OBJECT_COMPILING, + function (params) { + + if (dirty) { + + if (stackLen > 0) { + + params.display.modelTransform = transformStack[stackLen - 1]; + + } else { + + params.display.modelTransform = defaultCore; + } + + dirty = false; + } + }); + + /** + * Creates a fresh transformation core + * @param core + */ + this.buildCore = function (core) { + + /* + * Transform tree node properties + */ + core.parent = null; // Parent transform core + core.cores = []; // Child transform cores + core.numCores = 0; // Number of child transform cores + core.matrixDirty = false; + + core.matrix = SceneJS_math_identityMat4(); + + core.mat = new Float32Array(core.matrix); + core.normalMat = new Float32Array( + SceneJS_math_transposeMat4( + SceneJS_math_inverseMat4(core.matrix, SceneJS_math_mat4()))); + + core.dirty = false; // Does this subtree need matrices rebuilt + + core.setDirty = function () { + + core.matrixDirty = true; + + if (core.dirty) { + // return; + } + + setDirty(core); + }; + + /** + * Recursively flag this subtree of transforms cores as dirty, + * ie. needing their matrices rebuilt. + */ + function setDirty(core) { + + core.dirty = true; + core.matrixDirty = true; + + for (var i = 0, len = core.numCores; i < len; i++) { + setDirty(core.cores[i]); + } + } + + /** + * Pre-multiply matrices at cores on path up to root into matrix at this core + */ + core.build = function () { + + if (core.matrixDirty) { + if (core.buildMatrix) { // Matrix might be explicit property on some transform node types + core.buildMatrix(); + } + core.matrixDirty = false; + } + + var parent = core.parent; + + var matrix; + + if (parent) { + + matrix = core.matrix.slice(0); + + while (parent) { + + if (parent.matrixDirty) { + + if (parent.buildMatrix) { // Matrix might be explicit property on some transform node types + parent.buildMatrix(); + } + parent.mat.set(parent.matrix); + parent.normalMat.set( + SceneJS_math_transposeMat4( + SceneJS_math_inverseMat4(parent.matrix, SceneJS_math_mat4()))); + + parent.matrixDirty = false; + } + + SceneJS_math_mulMat4(parent.matrix, matrix, matrix); + + if (!parent.dirty) { + // break; + } + + // parent.dirty = false; + + parent = parent.parent; + } + + } else { + + matrix = core.matrix; + } + + // if (!core.mat) { + // + // core.mat = new Float32Array(matrix); + // + // core.normalMat = new Float32Array( + // SceneJS_math_transposeMat4( + // SceneJS_math_inverseMat4(matrix, SceneJS_math_mat4()))); + // } else { + + core.mat.set(matrix); + + core.normalMat.set( + SceneJS_math_transposeMat4( + SceneJS_math_inverseMat4(matrix, SceneJS_math_mat4()))); + //} + + core.dirty = false; + }; + }; + + this.push = function (core) { + + transformStack[stackLen++] = core; + + core.parent = this.top; + core.dirty = true; + + if (this.top) { + this.top.cores[this.top.numCores++] = core; + } + + core.numCores = 0; + + this.top = core; + + dirty = true; + }; + + this.pop = function () { + + this.top = (--stackLen > 0) ? transformStack[stackLen - 1] : defaultCore; + + + dirty = true; + }; + +})(); +;/** + * Container for custom node types + */ +SceneJS.Types = new (function () { + + /** + * Installs a node type + * @param typeName + * @param methods + */ + this.addType = function (typeName, methods) { + SceneJS_NodeFactory.createNodeType(typeName, methods, + // Augments the basic node type with our custom type's methods + function (type) { + var method; + for (var methodName in methods) { + if (methods.hasOwnProperty(methodName)) { + method = methods[methodName]; + switch (methodName) { + case "init": // Deprecated + case "construct": + (function () { + var _method = methods[methodName]; + type.prototype._init = function (params) { + _method.call(this, params); + }; + + // Mark node type as a plugin + type.prototype._fromPlugin = true; + })(); + break; + case "destroy": // Deprecated + case "destruct": + type.prototype._destroy = method; + break; + default: + type.prototype[methodName] = method; + } + } + } + }); + }; + + /** + * Tests if given node type is installed + * @param typeName + * @param methods + */ + this.hasType = function (typeName) { + return !!SceneJS_NodeFactory.nodeTypes[typeName]; + }; +})(); + +;/** + * @class Display compiled from a {@link SceneJS.Scene}, providing methods to render and pick. + * @private + * + *

A Display is a container of {@link SceneJS_Object}s which are created (or updated) by a depth-first + * compilation traversal of a {@link SceneJS.Scene}. + * + *

Rendering Pipeline

+ * + *

Conceptually, a Display implements a pipeline with the following stages:

+ * + *
    + *
  1. Create or update {@link SceneJS_Object}s during scene compilation
  2. + *
  3. Organise the {@link SceneJS_Object} into an object list
  4. + *
  5. Determine the GL state sort order for the object list
  6. + *
  7. State sort the object list
  8. + *
  9. Create a draw list containing {@link SceneJS_Chunk}s belonging to the {@link SceneJS_Object}s in the object list
  10. + *
  11. Render the draw list to draw the image
  12. + *
+ * + *

An update to the scene causes the pipeline to be re-executed from one of these stages, and SceneJS is designed + * so that the pipeline is always re-executed from the latest stage possible to avoid redoing work.

+ * + *

For example:

+ * + *
    + *
  • when an object is created or updated, we need to (re)do stages 2, 3, 4, 5 and 6
  • + *
  • when an object is made invisible, we need to redo stages 5 and 6
  • + *
  • when an object is assigned to a different scene render layer (works like a render bin), we need to redo + * stages 3, 4, 5, and 6
  • + *
  • when the colour of an object changes, or maybe when the viewpoint changes, we simplt redo stage 6
  • + *
+ * + *

Object Creation

+ *

The object soup (stage 1) is constructed by a depth-first traversal of the scene graph, which we think of as + * "compiling" the scene graph into the Display. As traversal visits each scene node, the node's state core is + * set on the Display (such as {@link #flags}, {@link #layer}, {@link #renderer} etc), which we think of as the + * cores that are active at that instant during compilation. Each of the scene's leaf nodes is always + * a {@link SceneJS.Geometry}, and when traversal visits one of those it calls {@link #buildObject} to create an + * object in the soup. For each of the currently active cores, the object is given a {@link SceneJS_Chunk} + * containing the WebGL calls for rendering it.

+ * + *

The object also gets a shader (implemented by {@link SceneJS_Program}), taylored to render those state cores.

+ * + *

Limited re-compilation may also be done on portions of a scene that have been added or sufficiently modified. When + * traversal visits a {@link SceneJS.Geometry} for which an object already exists in the display, {@link #buildObject} + * may update the {@link SceneJS_Chunk}s on the object as required for any changes in the core soup since the + * last time the object was built. If differences among the cores require it, then {@link #buildObject} may also replace + * the object's {@link SceneJS_Program} in order to render the new core soup configuration.

+ * + *

So in summary, to each {@link SceneJS_Object} it builds, {@link #buildObject} creates a list of + * {@link SceneJS_Chunk}s to render the set of node state cores that are currently set on the {@link SceneJS_Display}. + * When {@link #buildObject} is re-building an existing object, it may replace one or more {@link SceneJS_Chunk}s + * for state cores that have changed from the last time the object was built or re-built.

+ + *

Object Destruction

+ *

Destruction of a scene graph branch simply involves a call to {@link #removeObject} for each {@link SceneJS.Geometry} + * in the branch.

+ * + *

Draw List

+ *

The draw list is actually comprised of two lists of state chunks: a "pick" list to render a pick buffer + * for colour-indexed GPU picking, along with a "draw" list for normal image rendering. The chunks in these lists + * are held in the state-sorted order of their objects in #_objectList, with runs of duplicate states removed.

+ * + *

After a scene update, we set a flag on the display to indicate the stage we will need to redo from. The pipeline is + * then lazy-redone on the next call to #render or #pick.

+ */ +var SceneJS_Display = function (cfg) { + + // Display is bound to the lifetime of an HTML5 canvas + this._canvas = cfg.canvas; + + // Factory which creates and recycles {@link SceneJS_Program} instances + this._programFactory = new SceneJS_ProgramFactory({ + canvas: cfg.canvas + }); + + // Factory which creates and recycles {@link SceneJS.Chunk} instances + this._chunkFactory = new SceneJS_ChunkFactory(); + + /** + * True when the background is to be transparent + * @type {boolean} + */ + this.transparent = cfg.transparent === true; + + /** + * Node state core for the last {@link SceneJS.Enable} visited during scene graph compilation traversal + * @type Object + */ + this.enable = null; + + /** + * Node state core for the last {@link SceneJS.Flags} visited during scene graph compilation traversal + * @type Object + */ + this.flags = null; + + /** + * Node state core for the last {@link SceneJS.Layer} visited during scene graph compilation traversal + * @type Object + */ + this.layer = null; + + /** + * Node state core for the last {@link SceneJS.Stage} visited during scene graph compilation traversal + * @type Object + */ + this.stage = null; + + /** + * Node state core for the last {@link SceneJS.Renderer} visited during scene graph compilation traversal + * @type Object + */ + this.renderer = null; + + /** + * Node state core for the last {@link SceneJS.DepthBuf} visited during scene graph compilation traversal + * @type Object + */ + this.depthBuffer = null; + + /** + * Node state core for the last {@link SceneJS.ColorBuf} visited during scene graph compilation traversal + * @type Object + */ + this.colorBuffer = null; + + /** + * Node state core for the last {@link SceneJS.View} visited during scene graph compilation traversal + * @type Object + */ + this.view = null; + + /** + * Node state core for the last {@link SceneJS.Lights} visited during scene graph compilation traversal + * @type Object + */ + this.lights = null; + + /** + * Node state core for the last {@link SceneJS.Material} visited during scene graph compilation traversal + * @type Object + */ + this.material = null; + + /** + * Node state core for the last {@link SceneJS.Texture} visited during scene graph compilation traversal + * @type Object + */ + this.texture = null; + + /** + * Node state core for the last {@link SceneJS.Reflect} visited during scene graph compilation traversal + * @type Object + */ + this.cubemap = null; + + /** + * Node state core for the last {@link SceneJS.XForm} visited during scene graph compilation traversal + * @type Object + */ + this.modelTransform = null; + + /** + * Node state core for the last {@link SceneJS.LookAt} visited during scene graph compilation traversal + * @type Object + */ + this.viewTransform = null; + + /** + * Node state core for the last {@link SceneJS.Camera} visited during scene graph compilation traversal + * @type Object + */ + this.projTransform = null; + + /** + * Node state core for the last {@link SceneJS.ColorTarget} visited during scene graph compilation traversal + * @type Object + */ + this.renderTarget = null; + + /** + * Node state core for the last {@link SceneJS.Clips} visited during scene graph compilation traversal + * @type Object + */ + this.clips = null; + + /** + * Node state core for the last {@link SceneJS.MorphGeometry} visited during scene graph compilation traversal + * @type Object + */ + this.morphGeometry = null; + + /** + * Node state core for the last {@link SceneJS.Name} visited during scene graph compilation traversal + * @type Object + */ + this.name = null; + + /** + * Node state core for the last {@link SceneJS.Tag} visited during scene graph compilation traversal + * @type Object + */ + this.tag = null; + + /** + * Node state core for the last render {@link SceneJS.Node} listener encountered during scene graph compilation traversal + * @type Object + */ + this.renderListeners = null; + + /** + * Node state core for the last {@link SceneJS.Shader} visited during scene graph compilation traversal + * @type Object + */ + this.shader = null; + + /** + * Node state core for the last {@link SceneJS.ShaderParams} visited during scene graph compilation traversal + * @type Object + */ + this.shaderParams = null; + + /** + * Node state core for the last {@link SceneJS.Style} visited during scene graph compilation traversal + * @type Object + */ + this.style = null; + + /** + * Node state core for the last {@link SceneJS.Geometry} visited during scene graph compilation traversal + * @type Object + */ + this.geometry = null; + + /* Factory which creates and recycles {@link SceneJS_Object} instances + */ + this._objectFactory = new SceneJS_ObjectFactory(); + + /** + * The objects in the display + */ + this._objects = {}; + + /** + * Ambient color, which must be given to gl.clearColor before draw list iteration + */ + this._ambientColor = [0, 0, 0, 1.0]; + + /** + * The object list, containing all elements of #_objects, kept in GL state-sorted order + */ + this._objectList = []; + this._objectListLen = 0; + + /* The "draw list", comprised collectively of three lists of state chunks belong to visible objects + * within #_objectList: a "pick" list to render a pick buffer for colour-indexed GPU picking, along with an + * "draw" list for normal image rendering. The chunks in these lists are held in the state-sorted order of + * their objects in #_objectList, with runs of duplicate states removed. + */ + this._drawList = []; // State chunk list to render all objects + this._drawListLen = 0; + + this._pickDrawList = []; // State chunk list to render scene to pick buffer + this._pickDrawListLen = 0; + + this._targetList = []; + this._targetListLen = 0; + + /* The frame context holds state shared across a single render of the draw list, along with any results of + * the render, such as pick hits + */ + this._frameCtx = { + pickNames: [], // Pick names of objects hit during pick render + canvas: this._canvas, // The canvas + VAO: null // Vertex array object extension + }; + + /* The frame context has this facade which is given to scene node "rendered" listeners + * to allow application code to access things like transform matrices from within those listeners. + */ + this._frameCtx.renderListenerCtx = new SceneJS.RenderContext(this._frameCtx); + + /*------------------------------------------------------------------------------------- + * Flags which schedule what the display is to do when #render is next called. + *------------------------------------------------------------------------------------*/ + + /** + * Flags the object list as needing to be rebuilt from existing objects on the next call to {@link #render} or {@link #pick}. + * Setting this will cause the rendering pipeline to be executed from stage #2 (see class comment), + * causing object list rebuild, state order determination, state sort, draw list construction and image render. + * @type Boolean + */ + this.objectListDirty = true; + + /** + * Flags the object list as needing state orders to be computed on the next call to {@link #render} or {@link #pick}. + * Setting this will cause the rendering pipeline to be executed from stage #3 (see class comment), + * causing state order determination, state sort, draw list construction and image render. + * @type Boolean + */ + this.stateOrderDirty = true; + + /** + * Flags the object list as needing to be state sorted on the next call to {@link #render} or {@link #pick}. + * Setting this will cause the rendering pipeline to be executed from stage #4 (see class comment), + * causing state sort, draw list construction and image render. + * @type Boolean + */ + this.stateSortDirty = true; + + /** + * Flags the draw list as needing to be rebuilt from the object list on the next call to {@link #render} or {@link #pick}. + * Setting this will cause the rendering pipeline to be executed from stage #5 (see class comment), + * causing draw list construction and image render. + * @type Boolean + */ + this.drawListDirty = true; + + /** + * Flags the image as needing to be redrawn from the draw list on the next call to {@link #render} or {@link #pick}. + * Setting this will cause the rendering pipeline to be executed from stage #6 (see class comment), + * causing the image render. + * @type Boolean + */ + this.imageDirty = true; + + /** + * Flags the neccessity for the image buffer to be re-rendered from the draw list. + * @type Boolean + */ + this.pickBufDirty = true; // Redraw pick buffer + this.rayPickBufDirty = true; // Redraw raypick buffer +}; + +/** + * Reallocates WebGL resources for objects within this display + */ +SceneJS_Display.prototype.webglRestored = function () { + this._programFactory.webglRestored();// Reallocate programs + this._chunkFactory.webglRestored(); // Recache shader var locations + var gl = this._canvas.gl; + if (this.pickBuf) { + this.pickBuf.webglRestored(gl); // Rebuild pick buffers + } + if (this.rayPickBuf) { + this.rayPickBuf.webglRestored(gl); + } + this.imageDirty = true; // Need redraw +}; + +/** + * Internally creates (or updates) a {@link SceneJS_Object} of the given ID from whatever node state cores are currently set + * on this {@link SceneJS_Display}. The object is created if it does not already exist in the display, otherwise it is + * updated with the current state cores, possibly replacing cores already referenced by the object. + * + * @param {String} objectId ID of object to create or update + */ +SceneJS_Display.prototype.buildObject = function (objectId) { + + var object = this._objects[objectId]; + + if (!object) { // Create object + object = this._objects[objectId] = this._objectFactory.getObject(objectId); + this.objectListDirty = true; + } + + object.stage = this.stage; + object.layer = this.layer; + object.renderTarget = this.renderTarget; + object.texture = this.texture; + object.cubemap = this.cubemap; + object.geometry = this.geometry; + object.enable = this.enable; + object.flags = this.flags; + object.tag = this.tag; + + //if (!object.hash) { + + var hash = ([ // Build current state hash + this.geometry.hash, + this.shader.hash, + this.clips.hash, + this.morphGeometry.hash, + this.texture.hash, + this.cubemap.hash, + this.lights.hash, + this.flags.hash + ]).join(";"); + + if (!object.program || hash != object.hash) { + // Get new program for object if no program or hash mismatch + if (object.program) { + this._programFactory.putProgram(object.program); + } + object.program = this._programFactory.getProgram(hash, this); + object.hash = hash; + } + //} + + // Build draw chunks for object + + this._setChunk(object, 0, "program"); // Must be first + this._setChunk(object, 1, "xform", this.modelTransform); + this._setChunk(object, 2, "lookAt", this.viewTransform); + this._setChunk(object, 3, "camera", this.projTransform); + this._setChunk(object, 4, "flags", this.flags); + this._setChunk(object, 5, "shader", this.shader); + this._setChunk(object, 6, "shaderParams", this.shaderParams); + this._setChunk(object, 7, "style", this.style); + this._setChunk(object, 8, "depthBuffer", this.depthBuffer); + this._setChunk(object, 9, "colorBuffer", this.colorBuffer); + this._setChunk(object, 10, "view", this.view); + this._setChunk(object, 11, "name", this.name); + this._setChunk(object, 12, "lights", this.lights); + this._setChunk(object, 13, "material", this.material); + this._setChunk(object, 14, "texture", this.texture); + this._setChunk(object, 15, "cubemap", this.cubemap); + this._setChunk(object, 16, "clips", this.clips); + this._setChunk(object, 17, "renderer", this.renderer); + this._setChunk(object, 18, "geometry", this.morphGeometry, this.geometry); + this._setChunk(object, 19, "listeners", this.renderListeners); // Must be after the above chunks + this._setChunk(object, 20, "draw", this.geometry); // Must be last +}; + +SceneJS_Display.prototype._setChunk = function (object, order, chunkType, core, core2) { + + var chunkId; + var chunkClass = this._chunkFactory.chunkTypes[chunkType]; + + if (core) { + + // Core supplied + if (core.empty) { // Only set default cores for state types that have them + var oldChunk = object.chunks[order]; + if (oldChunk) { + this._chunkFactory.putChunk(oldChunk); // Release previous chunk to pool + } + object.chunks[order] = null; + return; + } + + // Note that core.stateId can be either a number or a string, that's why we make + // chunkId a string here. + // TODO: Would it be better if all were numbers? + chunkId = chunkClass.prototype.programGlobal + ? '_' + core.stateId + : 'p' + object.program.id + '_' + core.stateId; + + if (core2) { + chunkId += '__' + core2.stateId; + } + + } else { + + // No core supplied, probably a program. + // Only one chunk of this type per program. + chunkId = 'p' + object.program.id; + } + + // This is needed so that chunkFactory can distinguish between draw and geometry + // chunks with the same core. + chunkId = order + '__' + chunkId; + + var oldChunk = object.chunks[order]; + + if (oldChunk) { + if (oldChunk.id == chunkId) { // Avoid needless chunk reattachment + return; + } + this._chunkFactory.putChunk(oldChunk); // Release previous chunk to pool + } + + object.chunks[order] = this._chunkFactory.getChunk(chunkId, chunkType, object.program, core, core2); // Attach new chunk + + // Ambient light is global across everything in display, and + // can never be disabled, so grab it now because we want to + // feed it to gl.clearColor before each display list render + if (chunkType == "lights") { + this._setAmbient(core); + } +}; + +SceneJS_Display.prototype._setAmbient = function (core) { + var lights = core.lights; + var light; + for (var i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + if (light.mode == "ambient") { + this._ambientColor[0] = light.color[0]; + this._ambientColor[1] = light.color[1]; + this._ambientColor[2] = light.color[2]; + } + } +}; + +/** + * Removes an object from this display + * + * @param {String} objectId ID of object to remove + */ +SceneJS_Display.prototype.removeObject = function (objectId) { + var object = this._objects[objectId]; + if (!object) { + return; + } + this._programFactory.putProgram(object.program); + object.program = null; + object.hash = null; + this._objectFactory.putObject(object); + delete this._objects[objectId]; + this.objectListDirty = true; +}; + +/** + * Set a tag selector to selectively activate objects that have matching SceneJS.Tag nodes + */ +SceneJS_Display.prototype.selectTags = function (tagSelector) { + this._tagSelector = tagSelector; + this.drawListDirty = true; +}; + +/** + * Render this display. What actually happens in the method depends on what flags are set. + * + */ +SceneJS_Display.prototype.render = function (params) { + + params = params || {}; + + if (this.objectListDirty) { + this._buildObjectList(); // Build object render bin + this.objectListDirty = false; + this.stateOrderDirty = true; // Now needs state ordering + } + + if (this.stateOrderDirty) { + this._makeStateSortKeys(); // Compute state sort order + this.stateOrderDirty = false; + this.stateSortDirty = true; // Now needs state sorting + } + + if (this.stateSortDirty) { + this._stateSort(); // State sort the object render bin + this.stateSortDirty = false; + this.drawListDirty = true; // Now needs new visible object bin + //this._logObjectList(); + } + + if (this.drawListDirty) { // Render visible list while building transparent list + this._buildDrawList(); + this.imageDirty = true; + //this._logDrawList(); + //this._logPickList(); + } + + if (this.imageDirty || params.force) { + this._doDrawList({ // Render, no pick + clear: (params.clear !== false) // Clear buffers by default + }); + this.imageDirty = false; + this.pickBufDirty = true; // Pick buff will now need rendering on next pick + } +}; + +SceneJS_Display.prototype._buildObjectList = function () { + this._objectListLen = 0; + for (var objectId in this._objects) { + if (this._objects.hasOwnProperty(objectId)) { + this._objectList[this._objectListLen++] = this._objects[objectId]; + } + } +}; + +SceneJS_Display.prototype._makeStateSortKeys = function () { + // console.log("--------------------------------------------------------------------------------------------------"); + // console.log("SceneJS_Display_makeSortKeys"); + var object; + for (var i = 0, len = this._objectListLen; i < len; i++) { + object = this._objectList[i]; + if (!object.program) { + // Non-visual object (eg. sound) + object.sortKey = -1; + } else { + object.sortKey = + ((object.stage.priority + 1) * 1000000000000) + + ((object.flags.transparent ? 2 : 1) * 1000000000) + + ((object.layer.priority + 1) * 1000000) + + ((object.program.id + 1) * 1000) + + object.texture.stateId; + } + } + // console.log("--------------------------------------------------------------------------------------------------"); +}; + +SceneJS_Display.prototype._stateSort = function () { + this._objectList.length = this._objectListLen; + this._objectList.sort(this._stateSortObjects); +}; + +SceneJS_Display.prototype._stateSortObjects = function (a, b) { + return a.sortKey - b.sortKey; +}; + +SceneJS_Display.prototype._logObjectList = function () { + console.log("--------------------------------------------------------------------------------------------------"); + console.log(this._objectListLen + " objects"); + for (var i = 0, len = this._objectListLen; i < len; i++) { + var object = this._objectList[i]; + console.log("SceneJS_Display : object[" + i + "] sortKey = " + object.sortKey); + } + console.log("--------------------------------------------------------------------------------------------------"); +}; + +SceneJS_Display.prototype._buildDrawList = function () { + + this._lastStateId = this._lastStateId || []; + this._lastPickStateId = this._lastPickStateId || []; + + for (var i = 0; i < 23; i++) { + this._lastStateId[i] = null; + this._lastPickStateId[i] = null; + } + + this._drawListLen = 0; + this._pickDrawListLen = 0; + + // For each render target, a list of objects to render to that target + var targetObjectLists = {}; + + // A list of all the render target object lists + var targetListList = []; + + // List of all targets + var targetList = []; + + var object; + var tagMask; + var tagRegex; + var tagCore; + var flags; + + if (this._tagSelector) { + tagMask = this._tagSelector.mask; + tagRegex = this._tagSelector.regex; + } + + this._objectDrawList = this._objectDrawList || []; + this._objectDrawListLen = 0; + + for (var i = 0, len = this._objectListLen; i < len; i++) { + + object = this._objectList[i]; + + // Cull invisible objects + if (object.enable.enabled === false) { + continue; + } + + flags = object.flags; + + // Cull invisible objects + if (flags.enabled === false) { + continue; + } + + // Cull objects in disabled layers + if (!object.layer.enabled) { + continue; + } + + // Cull objects with unmatched tags + if (tagMask) { + tagCore = object.tag; + if (tagCore.tag) { + if (tagCore.mask != tagMask) { // Scene tag mask was updated since last render + tagCore.mask = tagMask; + tagCore.matches = tagRegex.test(tagCore.tag); + } + if (!tagCore.matches) { + continue; + } + } + } + + // Put objects with render targets into a bin for each target + if (object.renderTarget.targets) { + var targets = object.renderTarget.targets; + var target; + var coreId; + var list; + for (var j = 0, lenj = targets.length; j < lenj; j++) { + target = targets[j]; + coreId = target.coreId; + list = targetObjectLists[coreId]; + if (!list) { + list = []; + targetObjectLists[coreId] = list; + targetListList.push(list); + targetList.push(this._chunkFactory.getChunk(target.stateId, "renderTarget", object.program, target)); + } + list.push(object); + } + } else { + + // + this._objectDrawList[this._objectDrawListLen++] = object; + } + } + + // Append chunks for objects within render targets first + + var list; + var target; + var object; + var pickable; + + for (var i = 0, len = targetListList.length; i < len; i++) { + + list = targetListList[i]; + target = targetList[i]; + + this._appendRenderTargetChunk(target); + + for (var j = 0, lenj = list.length; j < lenj; j++) { + object = list[j]; + pickable = object.stage && object.stage.pickable; // We'll only pick objects in pickable stages + this._appendObjectToDrawLists(object, pickable); + } + } + + if (object) { + + // Unbinds any render target bound previously + this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1, "renderTarget", object.program, {})); + } + + // Append chunks for objects not in render targets + for (var i = 0, len = this._objectDrawListLen; i < len; i++) { + object = this._objectDrawList[i]; + pickable = !object.stage || (object.stage && object.stage.pickable); // We'll only pick objects in pickable stages + this._appendObjectToDrawLists(object, pickable); + } + + this.drawListDirty = false; +}; + + +SceneJS_Display.prototype._appendRenderTargetChunk = function (chunk) { + this._drawList[this._drawListLen++] = chunk; +}; + +/** + * Appends an object to the draw and pick lists. + * @param object + * @param pickable + * @private + */ +SceneJS_Display.prototype._appendObjectToDrawLists = function (object, pickable) { + var chunks = object.chunks; + var picking = object.flags.picking; + var chunk; + for (var i = 0, len = chunks.length; i < len; i++) { + chunk = chunks[i]; + if (chunk) { + + // As we apply the state chunk lists we track the ID of most types of chunk in order + // to cull redundant re-applications of runs of the same chunk - except for those chunks with a + // 'unique' flag, because we don't want to cull runs of draw chunks because they contain the GL + // drawElements calls which render the objects. + + if (chunk.draw) { + if (chunk.unique || this._lastStateId[i] != chunk.id) { // Don't reapply repeated states + this._drawList[this._drawListLen++] = chunk; + this._lastStateId[i] = chunk.id; + } + } + + if (chunk.pick) { + if (pickable !== false) { // Don't pick objects in unpickable stages + if (picking) { // Don't pick unpickable objects + if (chunk.unique || this._lastPickStateId[i] != chunk.id) { // Don't reapply repeated states + this._pickDrawList[this._pickDrawListLen++] = chunk; + this._lastPickStateId[i] = chunk.id; + } + } + } + } + } + } +}; + +/** + * Logs the contents of the draw list to the console. + * @private + */ +SceneJS_Display.prototype._logDrawList = function () { + console.log("--------------------------------------------------------------------------------------------------"); + console.log(this._drawListLen + " draw list chunks"); + for (var i = 0, len = this._drawListLen; i < len; i++) { + var chunk = this._drawList[i]; + console.log("[chunk " + i + "] type = " + chunk.type); + switch (chunk.type) { + case "draw": + console.log("\n"); + break; + case "renderTarget": + console.log(" bufType = " + chunk.core.bufType); + break; + } + } + console.log("--------------------------------------------------------------------------------------------------"); +}; + +/** + * Logs the contents of the pick list to the console. + * @private + */ +SceneJS_Display.prototype._logPickList = function () { + console.log("--------------------------------------------------------------------------------------------------"); + console.log(this._pickDrawListLen + " pick list chunks"); + for (var i = 0, len = this._pickDrawListLen; i < len; i++) { + var chunk = this._pickDrawList[i]; + console.log("[chunk " + i + "] type = " + chunk.type); + switch (chunk.type) { + case "draw": + console.log("\n"); + break; + case "renderTarget": + console.log(" bufType = " + chunk.core.bufType); + break; + } + } + console.log("--------------------------------------------------------------------------------------------------"); +}; + +/** + * Performs a pick on the display graph and returns info on the result. + * @param {*} params + * @returns {*} + */ +SceneJS_Display.prototype.pick = function (params) { + + var canvas = this._canvas.canvas; + var ssaaMultiplier = this._canvas.ssaaMultiplier; + var hit = null; + var canvasX = params.canvasX * ssaaMultiplier; + var canvasY = params.canvasY * ssaaMultiplier; + var pickBuf = this.pickBuf; + + // Lazy-create pick buffer + if (!pickBuf) { + pickBuf = this.pickBuf = new SceneJS._webgl.RenderBuffer({ canvas: this._canvas }); + this.pickBufDirty = true; + } + + this.render(); // Do any pending visible render + + // Colour-index pick to find the picked object + + pickBuf.bind(); + + // Re-render the pick buffer if the display has updated + if (this.pickBufDirty) { + pickBuf.clear(); + this._doDrawList({ + pick: true, + clear: true + }); + this._canvas.gl.finish(); + this.pickBufDirty = false; // Pick buffer up to date + this.rayPickBufDirty = true; // Ray pick buffer now dirty + } + + // Read pixel color in pick buffer at given coordinates, + // convert to an index into the pick name list + + var pix = pickBuf.read(canvasX, canvasY); // Read pick buffer + var pickedObjectIndex = pix[0] + pix[1] * 256 + pix[2] * 65536; + var pickIndex = (pickedObjectIndex >= 1) ? pickedObjectIndex - 1 : -1; + pickBuf.unbind(); // Unbind pick buffer + + // Look up pick name from index + var pickName = this._frameCtx.pickNames[pickIndex]; // Map pixel to name + + if (pickName) { + + hit = { + name: pickName.name, + path: pickName.path, + nodeId: pickName.nodeId, + canvasPos: [canvasX, canvasY] + }; + + // Now do a ray-pick if requested + + if (params.rayPick) { + + // Lazy-create ray pick depth buffer + var rayPickBuf = this.rayPickBuf; + if (!rayPickBuf) { + rayPickBuf = this.rayPickBuf = new SceneJS._webgl.RenderBuffer({ canvas: this._canvas }); + this.rayPickBufDirty = true; + } + + // Render depth values to ray-pick depth buffer + + rayPickBuf.bind(); + + if (this.rayPickBufDirty) { + rayPickBuf.clear(); + this._doDrawList({ + pick: true, + rayPick: true, + clear: true + }); + this.rayPickBufDirty = false; + } + + // Read pixel from depth buffer, convert to normalised device Z coordinate, + // which will be in range of [0..1] with z=0 at front + pix = rayPickBuf.read(canvasX, canvasY); + + rayPickBuf.unbind(); + + var screenZ = this._unpackDepth(pix); + var w = canvas.width; + var h = canvas.height; + // Calculate clip space coordinates, which will be in range + // of x=[-1..1] and y=[-1..1], with y=(+1) at top + var x = (canvasX - w / 2) / (w / 2); // Calculate clip space coordinates + var y = -(canvasY - h / 2) / (h / 2); + var projMat = this._frameCtx.cameraMat; + var viewMat = this._frameCtx.viewMat; + var pvMat = SceneJS_math_mulMat4(projMat, viewMat, []); + var pvMatInverse = SceneJS_math_inverseMat4(pvMat, []); + var world1 = SceneJS_math_transformVector4(pvMatInverse, [x, y, -1, 1]); + world1 = SceneJS_math_mulVec4Scalar(world1, 1 / world1[3]); + var world2 = SceneJS_math_transformVector4(pvMatInverse, [x, y, 1, 1]); + world2 = SceneJS_math_mulVec4Scalar(world2, 1 / world2[3]); + var dir = SceneJS_math_subVec3(world2, world1, []); + var vWorld = SceneJS_math_addVec3(world1, SceneJS_math_mulVec4Scalar(dir, screenZ, []), []); + + // Got World-space intersect with surface of picked geometry + hit.worldPos = vWorld; + } + } + + return hit; +}; + +SceneJS_Display.prototype.readPixels = function (entries, size) { + + if (!this._readPixelBuf) { + this._readPixelBuf = new SceneJS._webgl.RenderBuffer({ canvas: this._canvas }); + } + + this._readPixelBuf.bind(); + + this._readPixelBuf.clear(); + + this.render({ force: true }); + + var entry; + var color; + + for (var i = 0; i < size; i++) { + + entry = entries[i] || (entries[i] = {}); + + color = this._readPixelBuf.read(entry.x, entry.y); + + entry.r = color[0]; + entry.g = color[1]; + entry.b = color[2]; + entry.a = color[3]; + } + + this._readPixelBuf.unbind(); +}; + +/** + * Unpacks a color-encoded depth + * @param {Array(Number)} depthZ Depth encoded as an RGBA color value + * @returns {Number} + * @private + */ +SceneJS_Display.prototype._unpackDepth = function (depthZ) { + var vec = [depthZ[0] / 256.0, depthZ[1] / 256.0, depthZ[2] / 256.0, depthZ[3] / 256.0]; + var bitShift = [1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0]; + return SceneJS_math_dotVector4(vec, bitShift); +}; + +/** Renders either the draw or pick list. + * + * @param {*} params + * @param {Boolean} params.clear Set true to clear the color, depth and stencil buffers first + * @param {Boolean} params.pick Set true to render for picking + * @param {Boolean} params.rayPick Set true to render for ray-picking + * @private + */ +SceneJS_Display.prototype._doDrawList = function (params) { + + var gl = this._canvas.gl; + + // Reset frame context + var frameCtx = this._frameCtx; + frameCtx.renderTarget = null; + frameCtx.targetIndex = 0; + frameCtx.renderBuf = null; + frameCtx.viewMat = null; + frameCtx.modelMat = null; + frameCtx.cameraMat = null; + frameCtx.renderer = null; + frameCtx.depthbufEnabled = null; + frameCtx.clearDepth = null; + frameCtx.depthFunc = gl.LESS; + frameCtx.scissorTestEnabled = false; + frameCtx.blendEnabled = false; + frameCtx.backfaces = true; + frameCtx.frontface = "ccw"; + frameCtx.pick = !!params.pick; + frameCtx.rayPick = !!params.rayPick; + frameCtx.pickIndex = 0; + frameCtx.textureUnit = 0; + frameCtx.lineWidth = 1; + frameCtx.transparent = false; + frameCtx.ambientColor = this._ambientColor; + frameCtx.aspect = this._canvas.canvas.width / this._canvas.canvas.height; + + // The extensions needs to be re-queried in case the context was lost and has been recreated. + if (this._canvas.UINT_INDEX_ENABLED) { + gl.getExtension("OES_element_index_uint"); + } + + var VAO = gl.getExtension("OES_vertex_array_object"); + frameCtx.VAO = (VAO) ? VAO : null; + + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + + if (this.transparent) { + gl.clearColor(0, 0, 0, 0); + } else { + gl.clearColor(this._ambientColor[0], this._ambientColor[1], this._ambientColor[2], 1.0); + } + + if (params.clear) { + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + } + + gl.frontFace(gl.CCW); + gl.disable(gl.CULL_FACE); + gl.disable(gl.BLEND); + + if (params.pick) { + // Render for pick + for (var i = 0, len = this._pickDrawListLen; i < len; i++) { + this._pickDrawList[i].pick(frameCtx); + } + } else { + // Render for draw + for (var i = 0, len = this._drawListLen; i < len; i++) { // Push opaque rendering chunks + this._drawList[i].draw(frameCtx); + } + } + + gl.flush(); + + if (frameCtx.renderBuf) { + frameCtx.renderBuf.unbind(); + } + + if (frameCtx.VAO) { + frameCtx.VAO.bindVertexArrayOES(null); + for (var i = 0; i < 10; i++) { + gl.disableVertexAttribArray(i); + } + } +// +// var numTextureUnits = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); +// for (var ii = 0; ii < numTextureUnits; ++ii) { +// gl.activeTexture(gl.TEXTURE0 + ii); +// gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); +// gl.bindTexture(gl.TEXTURE_2D, null); +// } +}; + +SceneJS_Display.prototype.destroy = function () { + this._programFactory.destroy(); +}; +;/** + * @class Manages creation, sharing and recycle of {@link SceneJS_ProgramSource} instances + * @private + */ +var SceneJS_ProgramSourceFactory = new (function () { + + this._sourceCache = {}; // Source codes are shared across all scenes + + + /** + * Get sourcecode for a program to render the given states + */ + this.getSource = function (hash, states) { + + var source = this._sourceCache[hash]; + if (source) { + source.useCount++; + return source; + } + + return this._sourceCache[hash] = new SceneJS_ProgramSource( + hash, + + this._composePickingVertexShader(states), // pickVertexSrc + this._composePickingFragmentShader(states), // pickFragmentSrc + this._composeRenderingVertexShader(states), // drawVertexSrc + this._composeRenderingFragmentShader(states) // drawfragmentSrc + ); + }; + + /** + * Releases program source code + */ + this.putSource = function (hash) { + var source = this._sourceCache[hash]; + if (source) { + if (--source.useCount == 0) { + this._sourceCache[source.hash] = null; + } + } + }; + + this._composePickingVertexShader = function (states) { + var morphing = !!states.morphGeometry.targets; + var src = [ + + "precision mediump float;", + + "attribute vec3 SCENEJS_aVertex;", + "uniform mat4 SCENEJS_uMMatrix;", + "uniform mat4 SCENEJS_uVMatrix;", + "uniform mat4 SCENEJS_uVNMatrix;", + "uniform mat4 SCENEJS_uPMatrix;" + ]; + + src.push("varying vec4 SCENEJS_vWorldVertex;"); + src.push("varying vec4 SCENEJS_vViewVertex;"); + + if (morphing) { + src.push("uniform float SCENEJS_uMorphFactor;"); // LERP factor for morph + if (states.morphGeometry.targets[0].vertexBuf) { // target2 has these arrays also + src.push("attribute vec3 SCENEJS_aMorphVertex;"); + } + } + + src.push("void main(void) {"); + + src.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "); + if (morphing) { + if (states.morphGeometry.targets[0].vertexBuf) { + src.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "); + } + } + src.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "); + + src.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"); + + src.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"); + src.push("}"); + return src; + }; + + /** + * Composes a fragment shader script for rendering mode in current scene state + * @private + */ + this._composePickingFragmentShader = function (states) { + + var clipping = states.clips.clips.length > 0; + + var src = [ + "precision mediump float;" + ]; + + src.push("varying vec4 SCENEJS_vWorldVertex;"); + src.push("varying vec4 SCENEJS_vViewVertex;"); // View-space vertex + + src.push("uniform bool SCENEJS_uRayPickMode;"); // Z-pick mode when true else colour-pick + src.push("uniform vec3 SCENEJS_uPickColor;"); // Used in colour-pick mode + src.push("uniform float SCENEJS_uZNear;"); // Used in Z-pick mode + src.push("uniform float SCENEJS_uZFar;"); // Used in Z-pick mode + src.push("uniform bool SCENEJS_uClipping;"); + + if (clipping) { + + // World-space clipping planes + for (var i = 0; i < states.clips.clips.length; i++) { + src.push("uniform float SCENEJS_uClipMode" + i + ";"); + src.push("uniform vec4 SCENEJS_uClipNormalAndDist" + i + ";"); + } + } + + // Pack depth function for ray-pick + src.push("vec4 packDepth(const in float depth) {"); + src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); + src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); + src.push(" vec4 res = fract(depth * bitShift);"); + src.push(" res -= res.xxyz * bitMask;"); + src.push(" return res;"); + src.push("}"); + + src.push("void main(void) {"); + + if (clipping) { + src.push("if (SCENEJS_uClipping) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < states.clips.clips.length; i++) { + src.push(" if (SCENEJS_uClipMode" + i + " != 0.0) {"); + src.push(" dist += clamp(dot(SCENEJS_vWorldVertex.xyz, SCENEJS_uClipNormalAndDist" + i + ".xyz) - SCENEJS_uClipNormalAndDist" + i + ".w, 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); + } + + src.push(" if (SCENEJS_uRayPickMode) {"); + src.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"); + src.push(" gl_FragColor = packDepth(zNormalizedDepth); "); + src.push(" } else {"); + src.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "); + src.push(" }"); + + src.push("}"); + + return src; + }; + + this._isTexturing = function (states) { + if (states.texture.layers && states.texture.layers.length > 0) { + if (states.geometry.uvBuf || states.geometry.uvBuf2) { + return true; + } + if (states.morphGeometry.targets && (states.morphGeometry.targets[0].uvBuf || states.morphGeometry.targets[0].uvBuf2)) { + return true; + } + } + return false; + }; + + this._isCubeMapping = function (states) { + return (states.flags.reflective && states.cubemap.layers && states.cubemap.layers.length > 0 && states.geometry.normalBuf); + }; + + this._hasNormals = function (states) { + if (states.geometry.normalBuf) { + return true; + } + if (states.morphGeometry.targets && states.morphGeometry.targets[0].normalBuf) { + return true; + } + return false; + }; + + this._hasTangents = function (states) { + if (states.texture) { + var layers = states.texture.layers; + if (!layers) { + return false; + } + for (var i = 0, len = layers.length; i < len; i++) { + if (layers[i].applyTo == "normals") { + return true; + } + } + } + return false; + }; + + this._composeRenderingVertexShader = function (states) { + + var customShaders = states.shader.shaders || {}; + + // Do a full custom shader replacement if code supplied without hooks + if (customShaders.vertex + && customShaders.vertex.code + && customShaders.vertex.code != "" + && SceneJS._isEmpty(customShaders.vertex.hooks)) { + return [customShaders.vertex.code]; + } + + var customVertexShader = customShaders.vertex || {}; + var vertexHooks = customVertexShader.hooks || {}; + + var customFragmentShader = customShaders.fragment || {}; + var fragmentHooks = customFragmentShader.hooks || {}; + + var texturing = this._isTexturing(states); + var normals = this._hasNormals(states); + var tangents = this._hasTangents(states); + var clipping = states.clips.clips.length > 0; + var morphing = !!states.morphGeometry.targets; + + var src = [ + "precision mediump float;" + ]; + + src.push("uniform mat4 SCENEJS_uMMatrix;"); // Model matrix + src.push("uniform mat4 SCENEJS_uVMatrix;"); // View matrix + src.push("uniform mat4 SCENEJS_uPMatrix;"); // Projection matrix + + src.push("attribute vec3 SCENEJS_aVertex;"); // Model coordinates + + src.push("uniform vec3 SCENEJS_uWorldEye;"); // World-space eye position + + src.push("varying vec3 SCENEJS_vViewEyeVec;"); // View-space vector from origin to eye + + if (normals) { + + src.push("attribute vec3 SCENEJS_aNormal;"); // Normal vectors + src.push("uniform mat4 SCENEJS_uMNMatrix;"); // Model normal matrix + src.push("uniform mat4 SCENEJS_uVNMatrix;"); // View normal matrix + + src.push("varying vec3 SCENEJS_vViewNormal;"); // Output view-space vertex normal + + if (tangents) { + src.push("attribute vec4 SCENEJS_aTangent;"); + } + + for (var i = 0; i < states.lights.lights.length; i++) { + + var light = states.lights.lights[i]; + + if (light.mode == "ambient") { + continue; + } + + if (light.mode == "dir") { + src.push("uniform vec3 SCENEJS_uLightDir" + i + ";"); + } + + if (light.mode == "point") { + src.push("uniform vec3 SCENEJS_uLightPos" + i + ";"); + } + + if (light.mode == "spot") { + src.push("uniform vec3 SCENEJS_uLightPos" + i + ";"); + } + + // Vector from vertex to light, packaged with the pre-computed length of that vector + src.push("varying vec4 SCENEJS_vViewLightVecAndDist" + i + ";"); + } + } + + if (texturing) { + + if (states.geometry.uvBuf) { + src.push("attribute vec2 SCENEJS_aUVCoord;"); // UV coords + } + + if (states.geometry.uvBuf2) { + src.push("attribute vec2 SCENEJS_aUVCoord2;"); // UV2 coords + } + } + + if (states.geometry.colorBuf) { + src.push("attribute vec4 SCENEJS_aVertexColor;"); // UV2 coords + src.push("varying vec4 SCENEJS_vColor;"); // Varying for fragment texturing + } + + if (clipping) { + src.push("varying vec4 SCENEJS_vWorldVertex;"); // Varying for fragment clip or world pos hook + } + + src.push("varying vec4 SCENEJS_vViewVertex;"); // Varying for fragment view clip hook + + if (texturing) { // Varyings for fragment texturing + + if (states.geometry.uvBuf) { + src.push("varying vec2 SCENEJS_vUVCoord;"); + } + + if (states.geometry.uvBuf2) { + src.push("varying vec2 SCENEJS_vUVCoord2;"); + } + } + + if (morphing) { + src.push("uniform float SCENEJS_uMorphFactor;"); // LERP factor for morph + if (states.morphGeometry.targets[0].vertexBuf) { // target2 has these arrays also + src.push("attribute vec3 SCENEJS_aMorphVertex;"); + } + if (normals) { + if (states.morphGeometry.targets[0].normalBuf) { + src.push("attribute vec3 SCENEJS_aMorphNormal;"); + } + } + } + + if (customVertexShader.code) { + src.push("\n" + customVertexShader.code + "\n"); + } + + src.push("void main(void) {"); + + src.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "); + + src.push(" vec4 modelVertex = tmpVertex; "); + if (normals) { + src.push(" vec4 modelNormal = vec4(SCENEJS_aNormal, 0.0); "); + } + + // Morphing - morph targets are in same model space as the geometry + if (morphing) { + if (states.morphGeometry.targets[0].vertexBuf) { + src.push(" vec4 vMorphVertex = vec4(SCENEJS_aMorphVertex, 1.0); "); + src.push(" modelVertex = vec4(mix(modelVertex.xyz, vMorphVertex.xyz, SCENEJS_uMorphFactor), 1.0); "); + } + if (normals) { + if (states.morphGeometry.targets[0].normalBuf) { + src.push(" vec4 vMorphNormal = vec4(SCENEJS_aMorphNormal, 1.0); "); + src.push(" modelNormal = vec4( mix(modelNormal.xyz, vMorphNormal.xyz, SCENEJS_uMorphFactor), 1.0); "); + } + } + } + + src.push(" vec4 worldVertex = SCENEJS_uMMatrix * modelVertex;"); + + if (vertexHooks.viewMatrix) { + src.push("vec4 viewVertex = " + vertexHooks.viewMatrix + "(SCENEJS_uVMatrix) * worldVertex;"); + } else { + src.push("vec4 viewVertex = SCENEJS_uVMatrix * worldVertex; "); + } + + if (vertexHooks.viewPos) { + src.push("viewVertex=" + vertexHooks.viewPos + "(viewVertex);"); // Vertex hook function + } + + if (normals) { + src.push(" vec3 worldNormal = (SCENEJS_uMNMatrix * modelNormal).xyz; "); + src.push(" SCENEJS_vViewNormal = (SCENEJS_uVNMatrix * vec4(worldNormal, 1.0)).xyz;"); + } + + if (clipping || fragmentHooks.worldPos) { + src.push(" SCENEJS_vWorldVertex = worldVertex;"); // Varying for fragment world clip or hooks + } + + src.push(" SCENEJS_vViewVertex = viewVertex;"); // Varying for fragment hooks + + if (vertexHooks.projMatrix) { + src.push("gl_Position = " + vertexHooks.projMatrix + "(SCENEJS_uPMatrix) * viewVertex;"); + } else { + src.push(" gl_Position = SCENEJS_uPMatrix * viewVertex;"); + } + + if (tangents) { + + // Compute tangent-bitangent-normal matrix + + src.push("vec3 tangent = normalize((SCENEJS_uVNMatrix * SCENEJS_uMNMatrix * SCENEJS_aTangent).xyz);"); + src.push("vec3 bitangent = cross(SCENEJS_vViewNormal, tangent);"); + src.push("mat3 TBM = mat3(tangent, bitangent, SCENEJS_vViewNormal);"); + } + + src.push(" vec3 tmpVec3;"); + + if (normals) { + + for (var i = 0; i < states.lights.lights.length; i++) { + + light = states.lights.lights[i]; + + if (light.mode == "ambient") { + continue; + } + + if (light.mode == "dir") { + + // Directional light + + if (light.space == "world") { + + // World space light + + src.push("tmpVec3 = normalize(SCENEJS_uLightDir" + i + ");"); + + // Transform to View space + src.push("tmpVec3 = vec3(SCENEJS_uVMatrix * vec4(tmpVec3, 0.0)).xyz;"); + + if (tangents) { + + // Transform to Tangent space + src.push("tmpVec3 *= TBM;"); + } + + } else { + + // View space light + + src.push("tmpVec3 = normalize(SCENEJS_uLightDir" + i + ");"); + + if (tangents) { + + // Transform to Tangent space + src.push("tmpVec3 *= TBM;"); + } + } + + // Output + src.push("SCENEJS_vViewLightVecAndDist" + i + " = vec4(-tmpVec3, 0.0);"); + } + + if (light.mode == "point") { + + // Positional light + + if (light.space == "world") { + + // World space + + src.push("tmpVec3 = SCENEJS_uLightPos" + i + " - worldVertex.xyz;"); // Vector from World coordinate to light pos + + // Transform to View space + src.push("tmpVec3 = vec3(SCENEJS_uVMatrix * vec4(tmpVec3, 0.0)).xyz;"); + + if (tangents) { + + // Transform to Tangent space + src.push("tmpVec3 *= TBM;"); + } + + } else { + + // View space + + src.push("tmpVec3 = SCENEJS_uLightPos" + i + ".xyz - viewVertex.xyz;"); // Vector from View coordinate to light pos + + if (tangents) { + + // Transform to tangent space + src.push("tmpVec3 *= TBM;"); + } + } + + // Output + src.push("SCENEJS_vViewLightVecAndDist" + i + " = vec4(tmpVec3, length( SCENEJS_uLightPos" + i + " - worldVertex.xyz));"); + } + } + } + + src.push("SCENEJS_vViewEyeVec = ((SCENEJS_uVMatrix * vec4(SCENEJS_uWorldEye, 0.0)).xyz - viewVertex.xyz);"); + + if (tangents) { + + src.push("SCENEJS_vViewEyeVec *= TBM;"); + } + + if (texturing) { + + if (states.geometry.uvBuf) { + src.push("SCENEJS_vUVCoord = SCENEJS_aUVCoord;"); + } + + if (states.geometry.uvBuf2) { + src.push("SCENEJS_vUVCoord2 = SCENEJS_aUVCoord2;"); + } + } + + if (states.geometry.colorBuf) { + src.push("SCENEJS_vColor = SCENEJS_aVertexColor;"); + } + src.push("}"); + + return src; + }; + + + /*----------------------------------------------------------------------------------------------------------------- + * Rendering Fragment shader + *---------------------------------------------------------------------------------------------------------------*/ + + this._composeRenderingFragmentShader = function (states) { + + var customShaders = states.shader.shaders || {}; + + // Do a full custom shader replacement if code supplied without hooks + if (customShaders.fragment + && customShaders.fragment.code + && customShaders.fragment.code != "" + && SceneJS._isEmpty(customShaders.fragment.hooks)) { + return [customShaders.fragment.code]; + } + + var customFragmentShader = customShaders.fragment || {}; + var fragmentHooks = customFragmentShader.hooks || {}; + + var texturing = this._isTexturing(states); + var cubeMapping = this._isCubeMapping(states); + var normals = this._hasNormals(states); + var solid = states.flags.solid; + var tangents = this._hasTangents(states); + var clipping = states.clips.clips.length > 0; + + var src = ["\n"]; + + src.push("precision mediump float;"); + + + if (clipping) { + src.push("varying vec4 SCENEJS_vWorldVertex;"); // World-space vertex + } + + // if (fragmentHooks.viewPos) { + src.push("varying vec4 SCENEJS_vViewVertex;"); // View-space vertex + // } + + src.push("uniform float SCENEJS_uZNear;"); // Used in Z-pick mode + src.push("uniform float SCENEJS_uZFar;"); // Used in Z-pick mode + + + /*----------------------------------------------------------------------------------- + * Variables + *----------------------------------------------------------------------------------*/ + + if (clipping) { + for (var i = 0; i < states.clips.clips.length; i++) { + src.push("uniform float SCENEJS_uClipMode" + i + ";"); + src.push("uniform vec4 SCENEJS_uClipNormalAndDist" + i + ";"); + } + } + + if (texturing) { + if (states.geometry.uvBuf) { + src.push("varying vec2 SCENEJS_vUVCoord;"); + } + if (states.geometry.uvBuf2) { + src.push("varying vec2 SCENEJS_vUVCoord2;"); + } + var layer; + for (var i = 0, len = states.texture.layers.length; i < len; i++) { + layer = states.texture.layers[i]; + src.push("uniform sampler2D SCENEJS_uSampler" + i + ";"); + if (layer.matrix) { + src.push("uniform mat4 SCENEJS_uLayer" + i + "Matrix;"); + } + src.push("uniform float SCENEJS_uLayer" + i + "BlendFactor;"); + } + } + + if (normals && cubeMapping) { + var layer; + for (var i = 0, len = states.cubemap.layers.length; i < len; i++) { + layer = states.cubemap.layers[i]; + src.push("uniform samplerCube SCENEJS_uCubeMapSampler" + i + ";"); + src.push("uniform float SCENEJS_uCubeMapIntensity" + i + ";"); + } + } + + // True when lighting + src.push("uniform bool SCENEJS_uClipping;"); + + // True when interior surfaces of solid cross-sections + // are to be rendered without texture and shading + src.push("uniform bool SCENEJS_uSolid;"); + + // Added in v4.0 to support depth targets + src.push("uniform bool SCENEJS_uDepthMode;"); + + /* True when rendering transparency + */ + src.push("uniform bool SCENEJS_uTransparent;"); + + /* Vertex color variable + */ + if (states.geometry.colorBuf) { + src.push("varying vec4 SCENEJS_vColor;"); + } + + src.push("uniform vec3 SCENEJS_uAmbientColor;"); // Scene ambient colour - taken from clear colour + + src.push("uniform vec3 SCENEJS_uMaterialColor;"); + src.push("uniform float SCENEJS_uMaterialAlpha;"); + src.push("uniform float SCENEJS_uMaterialEmit;"); + src.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"); + src.push("uniform float SCENEJS_uMaterialSpecular;"); + src.push("uniform float SCENEJS_uMaterialShine;"); + + src.push("varying vec3 SCENEJS_vViewEyeVec;"); // Direction of world-space vertex from eye + + if (normals) { + + src.push("varying vec3 SCENEJS_vViewNormal;"); // View-space normal + + var light; + for (var i = 0; i < states.lights.lights.length; i++) { + light = states.lights.lights[i]; + if (light.mode == "ambient") { + continue; + } + src.push("uniform vec3 SCENEJS_uLightColor" + i + ";"); + if (light.mode == "point") { + src.push("uniform vec3 SCENEJS_uLightAttenuation" + i + ";"); + } + src.push("varying vec4 SCENEJS_vViewLightVecAndDist" + i + ";"); // Vector from light to vertex + } + } + + if (customFragmentShader.code) { + src.push("\n" + customFragmentShader.code + "\n"); + } + + src.push("void main(void) {"); + + // World-space arbitrary clipping planes + + if (clipping) { + src.push("if (SCENEJS_uClipping) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < states.clips.clips.length; i++) { + src.push(" if (SCENEJS_uClipMode" + i + " != 0.0) {"); + src.push(" dist += clamp(dot(SCENEJS_vWorldVertex.xyz, SCENEJS_uClipNormalAndDist" + i + ".xyz) - SCENEJS_uClipNormalAndDist" + i + ".w, 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); + } + + if (normals) { + + if (solid) { + + src.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"); + src.push(" if (a < 0.0) {"); + src.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"); + src.push(" return;"); + src.push(" }"); + } + } + + src.push(" vec3 ambient= SCENEJS_uAmbientColor;"); + + if (texturing && states.geometry.uvBuf && fragmentHooks.texturePos) { + src.push(fragmentHooks.texturePos + "(SCENEJS_vUVCoord);"); + } + + if (fragmentHooks.viewPos) { + src.push(fragmentHooks.viewPos + "(SCENEJS_vViewVertex);"); + } + + if (normals && fragmentHooks.viewNormal) { + src.push(fragmentHooks.viewNormal + "(SCENEJS_vViewNormal);"); + } + + if (states.geometry.colorBuf) { + src.push(" vec3 color = SCENEJS_vColor.rgb;"); + } else { + src.push(" vec3 color = SCENEJS_uMaterialColor;") + } + + src.push(" float alpha = SCENEJS_uMaterialAlpha;"); + src.push(" float emit = SCENEJS_uMaterialEmit;"); + src.push(" float specular = SCENEJS_uMaterialSpecular;"); + src.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"); + src.push(" float shine = SCENEJS_uMaterialShine;"); + + if (fragmentHooks.materialBaseColor) { + src.push("color=" + fragmentHooks.materialBaseColor + "(color);"); + } + if (fragmentHooks.materialAlpha) { + src.push("alpha=" + fragmentHooks.materialAlpha + "(alpha);"); + } + if (fragmentHooks.materialEmit) { + src.push("emit=" + fragmentHooks.materialEmit + "(emit);"); + } + if (fragmentHooks.materialSpecular) { + src.push("specular=" + fragmentHooks.materialSpecular + "(specular);"); + } + if (fragmentHooks.materialSpecularColor) { + src.push("specularColor=" + fragmentHooks.materialSpecularColor + "(specularColor);"); + } + if (fragmentHooks.materialShine) { + src.push("shine=" + fragmentHooks.materialShine + "(shine);"); + } + + if (normals) { + src.push(" float attenuation = 1.0;"); + if (tangents) { + src.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"); + } else { + + // Normalize the interpolated normals in the per-fragment-fragment-shader, + // because if we linear interpolated two nonparallel normalized vectors, the resulting vector won’t be of length 1 + src.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"); + } + } + + var layer; + if (texturing) { + + src.push(" vec4 texturePos;"); + src.push(" vec2 textureCoord=vec2(0.0,0.0);"); + + for (var i = 0, len = states.texture.layers.length; i < len; i++) { + layer = states.texture.layers[i]; + + /* Texture input + */ + if (layer.applyFrom == "normal" && normals) { + if (states.geometry.normalBuf) { + src.push("texturePos=vec4(viewNormalVec.xyz, 1.0);"); + } else { + SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors"); + continue; + } + } + if (layer.applyFrom == "uv") { + if (states.geometry.uvBuf) { + src.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);"); + } else { + SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates"); + continue; + } + } + if (layer.applyFrom == "uv2") { + if (states.geometry.uvBuf2) { + src.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);"); + } else { + SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates"); + continue; + } + } + + /* Texture matrix + */ + if (layer.matrix) { + src.push("textureCoord=(SCENEJS_uLayer" + i + "Matrix * texturePos).xy;"); + } else { + src.push("textureCoord=texturePos.xy;"); + } + + /* Alpha from Texture + */ + if (layer.applyTo == "alpha") { + if (layer.blendMode == "multiply") { + src.push("alpha = alpha * (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"); + } else if (layer.blendMode == "add") { + src.push("alpha = ((1.0 - SCENEJS_uLayer" + i + "BlendFactor) * alpha) + (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"); + } + } + + /* Texture output + */ + if (layer.applyTo == "baseColor") { + if (layer.blendMode == "multiply") { + src.push("color = color * (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"); + } else { + src.push("color = ((1.0 - SCENEJS_uLayer" + i + "BlendFactor) * color) + (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"); + } + } + + if (layer.applyTo == "emit") { + if (layer.blendMode == "multiply") { + src.push("emit = emit * (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"); + } else { + src.push("emit = ((1.0 - SCENEJS_uLayer" + i + "BlendFactor) * emit) + (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"); + } + } + + if (layer.applyTo == "specular" && normals) { + if (layer.blendMode == "multiply") { + src.push("specular = specular * (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"); + } else { + src.push("specular = ((1.0 - SCENEJS_uLayer" + i + "BlendFactor) * specular) + (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"); + } + } + + if (layer.applyTo == "shine") { + if (layer.blendMode == "multiply") { + src.push("shine = shine * (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"); + } else { + src.push("shine = ((1.0 - SCENEJS_uLayer" + i + "BlendFactor) * shine) + (SCENEJS_uLayer" + i + "BlendFactor * texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"); + } + } + + if (layer.applyTo == "normals" && normals) { + src.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler" + i + ", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);"); + } + + } + } + + if (normals && cubeMapping) { + src.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"); + src.push("envLookup.y = envLookup.y * -1.0;"); // Need to flip textures on Y-axis for some reason + src.push("vec4 envColor;"); + for (var i = 0, len = states.cubemap.layers.length; i < len; i++) { + layer = states.cubemap.layers[i]; + src.push("envColor = textureCube(SCENEJS_uCubeMapSampler" + i + ", envLookup);"); + src.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity" + i + ");"); + } + } + + src.push(" vec4 fragColor;"); + + if (normals) { + + src.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"); + src.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"); + src.push(" vec3 viewLightVec;"); + src.push(" float dotN;"); + src.push(" float lightDist;"); + + var light; + + for (var i = 0, len = states.lights.lights.length; i < len; i++) { + light = states.lights.lights[i]; + + if (light.mode == "ambient") { + continue; + } + + src.push("viewLightVec = SCENEJS_vViewLightVecAndDist" + i + ".xyz;"); + + if (light.mode == "point") { + + src.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"); + + + src.push("lightDist = SCENEJS_vViewLightVecAndDist" + i + ".w;"); + + src.push("attenuation = 1.0 - (" + + " SCENEJS_uLightAttenuation" + i + "[0] + " + + " SCENEJS_uLightAttenuation" + i + "[1] * lightDist + " + + " SCENEJS_uLightAttenuation" + i + "[2] * lightDist * lightDist);"); + + if (light.diffuse) { + src.push(" lightValue += dotN * SCENEJS_uLightColor" + i + " * attenuation;"); + } + + if (light.specular) { + src.push(" specularValue += specularColor * SCENEJS_uLightColor" + i + + " * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;"); + } + } + + if (light.mode == "dir") { + + src.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"); + + if (light.diffuse) { + src.push(" lightValue += dotN * SCENEJS_uLightColor" + i + ";"); + } + + if (light.specular) { + src.push("specularValue += specularColor * SCENEJS_uLightColor" + i + + " * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);"); + } + } + } + + src.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);"); + + } else { // No normals + src.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);"); + } + + if (fragmentHooks.pixelColor) { + src.push("fragColor=" + fragmentHooks.pixelColor + "(fragColor);"); + } + if (false && debugCfg.whitewash === true) { + src.push(" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);"); + } else { + + if (hasDepthTarget(states)) { + + // Only compile in depth mode support if a depth render target is present + + src.push(" if (SCENEJS_uDepthMode) {"); + src.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"); + src.push(" const vec4 bias = vec4(1.0 / 255.0,"); + src.push(" 1.0 / 255.0,"); + src.push(" 1.0 / 255.0,"); + src.push(" 0.0);"); + src.push(" float r = depth;"); + src.push(" float g = fract(r * 255.0);"); + src.push(" float b = fract(g * 255.0);"); + src.push(" float a = fract(b * 255.0);"); + src.push(" vec4 colour = vec4(r, g, b, a);"); + src.push(" gl_FragColor = colour - (colour.yzww * bias);"); + src.push(" } else {"); + src.push(" gl_FragColor = fragColor;"); + src.push(" };"); + + } else { + src.push(" gl_FragColor = fragColor;"); + } + } + src.push("}"); + +// console.log(src.join("\n")); + return src; + }; + + function hasDepthTarget(states) { + if (states.renderTarget && states.renderTarget.targets) { + var targets = states.renderTarget.targets; + for (var i = 0, len = targets.length; i < len; i++) { + if (targets[i].bufType === "depth") { + return true; + } + } + } + return false; + } + +})();;/** + * @class Source code for pick and draw shader programs, to be compiled into one or more {@link SceneJS_Program}s + * @private + * + * @param {String} hash Hash code identifying the rendering capabilities of the programs + * @param {String} pickVertexSrc Source code of the pick vertex shader + * @param {String} pickFragmentSrc Source code of the pick fragment shader + * @param {String} drawVertexSrc Source code of the draw vertex shader + * @param {String} drawFragmentSrc Source code of the draw fragment shader + */ +var SceneJS_ProgramSource = function(hash, pickVertexSrc, pickFragmentSrc, drawVertexSrc, drawFragmentSrc) { + + /** + * Hash code identifying the capabilities of the {@link SceneJS_Program} that is compiled from this source + * @type String + */ + this.hash = hash; + + /** + * Source code for pick vertex shader + * @type String + */ + this.pickVertexSrc = pickVertexSrc; + + /** + * Source code for pick fragment shader + * @type String + */ + this.pickFragmentSrc = pickFragmentSrc; + + /** + * Source code for draw vertex shader + * @type String + */ + this.drawVertexSrc = drawVertexSrc; + + /** + * Source code for draw fragment shader + * @type String + */ + this.drawFragmentSrc = drawFragmentSrc; + + /** + * Count of {@link SceneJS_Program}s compiled from this program source code + * @type Number + */ + this.useCount = 0; +}; + +;/** + * @class Manages creation, sharing and recycle of {@link SceneJS_Program} instances + * @private + */ +var SceneJS_ProgramFactory = function(cfg) { + + this._canvas = cfg.canvas; + + this._programs = {}; + + this._nextProgramId = 0; +}; + +/** + * Gets a program to render the given states + */ +SceneJS_ProgramFactory.prototype.getProgram = function(hash, states) { + + var program = this._programs[hash]; + + if (!program) { + + var source = SceneJS_ProgramSourceFactory.getSource(hash, states); + + program = new SceneJS_Program(this._nextProgramId++, hash, source, this._canvas.gl); + + this._programs[hash] = program; + } + + program.useCount++; + + return program; +}; + +/** + * Releases a program back to the shader factory + */ +SceneJS_ProgramFactory.prototype.putProgram = function(program) { + + if (--program.useCount <= 0) { + + program.draw.destroy(); + program.pick.destroy(); + + SceneJS_ProgramSourceFactory.putSource(program.hash); + + delete this._programs[program.hash]; + } +}; + +/** + * Notifies this shader factory that the WebGL context has been restored after previously being lost + */ +SceneJS_ProgramFactory.prototype.webglRestored = function() { + + var gl = this._canvas.gl; + var program; + + for (var id in this._programs) { + if (this._programs.hasOwnProperty(id)) { + program = this._programs[id]; + if (program && program.build) { + program.build(gl); + } + } + } +}; + +/** + * Destroys this shader factory + */ +SceneJS_ProgramFactory.prototype.destroy = function() { +}; +;/** + * @class Vertex and fragment shaders for pick and draw + * @private + * + * @param {Number} id ID unique among all programs in the owner {@link SceneJS_ProgramFactory} + * @param {String} hash Hash code which uniquely identifies the capabilities of the program, computed from hashes on the {@link Scene_Core}s that the {@link SceneJS_ProgramSource} composed to render + * @param {SceneJS_ProgramSource} source Sourcecode from which the the program is compiled in {@link #build} + * @param {WebGLRenderingContext} gl WebGL context + */ +var SceneJS_Program = function(id, hash, source, gl) { + + /** + * ID for this program, unique among all programs in the display + * @type Number + */ + this.id = id; + + /** + * Hash code for this program's capabilities, same as the hash on {@link #source} + * @type String + */ + this.hash = source.hash; + + /** + * Source code for this program's shaders + * @type SceneJS_ProgramSource + */ + this.source = source; + + /** + * WebGL context on which this program's shaders are allocated + * @type WebGLRenderingContext + */ + this.gl = gl; + + /** + * Whether or not we can use UINT indices + * @type boolean + */ + this.UINT_INDEX_ENABLED = !!gl.getExtension("OES_element_index_uint"); + + /** + * The drawing program + * @type SceneJS._webgl.Program + */ + this.draw = null; + + /** + * The picking program + * @type SceneJS._webgl.Program + */ + this.pick = null; + + /** + * The count of display objects using this program + * @type Number + */ + this.useCount = 0; + + this.build(gl); +}; + +/** + * Creates the render and pick programs. + * This is also re-called to re-create them after WebGL context loss. + */ +SceneJS_Program.prototype.build = function(gl) { + + this.gl = gl; + this.draw = new SceneJS._webgl.Program(gl, [this.source.drawVertexSrc.join("\n")], [this.source.drawFragmentSrc.join("\n")]); + this.pick = new SceneJS._webgl.Program(gl, [this.source.pickVertexSrc.join("\n")], [this.source.pickFragmentSrc.join("\n")]); +}; +;/** + * @class Manages creation and recycle of {@link SceneJS_Object} instances + * @private + */ +var SceneJS_ObjectFactory = function() { + +}; + +/** + * @property {[SceneJS_Object]} _freeObjects Pool of free display objects, shared by all object factories + */ +SceneJS_ObjectFactory.prototype._freeObjects = []; + +/** + * @property {Number} _numFreeObjects Number of free objects + */ +SceneJS_ObjectFactory.prototype._numFreeObjects = 0; + +/** + * Gets a display object from this factory + * + * @param {String} id ID to assign to the object + * @returns {SceneJS_Object} The object + */ +SceneJS_ObjectFactory.prototype.getObject = function(id) { + + var object; + + if (this._numFreeObjects > 0) { + + object = this._freeObjects[--this._numFreeObjects]; + object.id = id; + + return object; + } + + return new SceneJS_Object(id); +}; + +/** + * Releases a display object back to this factory + * @param {SceneJS_Object} object Object to release + */ +SceneJS_ObjectFactory.prototype.putObject = function (object) { + + this._freeObjects[this._numFreeObjects++] = object; +};;/** + * @class An object within a {@link SceneJS_Display} + * @private + */ +var SceneJS_Object = function(id) { + + /** + * ID for this objects, unique among all objects in the display + * @type Number + */ + this.id = id; + + /** + * Hash code for this object, unique among all objects in the display + * @type String + */ + this.hash = null; + + /** + * State sort key, computed from {@link #layer}, {@link #program} and {@link #texture} + * @type Number + */ + this.sortKey = null; + + /** + * Sequence of state chunks applied to render this object + * @type {[SceneJS_Chunk]} chunks + */ + this.chunks = []; + + /** + * Number of state chunks applied to render this object + * @type Number + */ + this.chunksLen = 0; + + /** + * Shader programs that render this object, also used for (re)computing {@link #sortKey} + * @type SceneJS_Program + */ + this.program = null; + + /** + * State core for the {@link SceneJS.Layer} that this object was compiled from, used for (re)computing {@link #sortKey} and visibility cull + */ + this.layer = null; + + /** + * State core for the {@link SceneJS.Texture} that this object was compiled from, used for (re)computing {@link #sortKey} + */ + this.texture = null; + + /** + * State core for the {@link SceneJS.Flags} that this object was compiled from, used for visibility cull + */ + this.flags = null; + + /** + * State core for the {@link SceneJS.Tag} that this object was compiled from, used for visibility cull + */ + this.tag = null; +};;/** + * @class A facade which exposes internal scene rendering state to "rendered" event listeners bound to scene graph nodes with {@link SceneJS.Node#bind}. + * + *

The listener is fired for each {@link SceneJS.Geometry} that is rendered within the subgraph of the bound node. + * An instance of this facade is passed into the listener's handler, enabling the listener to obtain the various transform + * matrices that are active at that {@link SceneJS.Geometry}.

+ * + *

The facade instance is only valid within the callback's execution; internally, SceneJS reuses the same instance of the + * facade with each scene.

+ */ +SceneJS.RenderContext = function(frameCtx) { + this._frameCtx = frameCtx; +}; + +/** + * Get the projection matrix, as defined by the active {@link SceneJS.Camera} node. + */ +SceneJS.RenderContext.prototype.getCameraMatrix = function() { + return this._frameCtx.cameraMat; +}; + +/** + * Get the view matrix, as defined by the active {@link SceneJS.LookAt} node. + */ +SceneJS.RenderContext.prototype.getViewMatrix = function() { + return this._frameCtx.viewMat; +}; + +/** + * Get the model matrix, as defined by the active {@link SceneJS.XForm} node. + */ +SceneJS.RenderContext.prototype.getModelMatrix = function() { + return this._frameCtx.modelMat; +}; + +/** + * Transforms the given world coordinate by the model, view and projection matrices defined by the active {@link SceneJS.XForm}, {@link SceneJS.LookAt} and {@link SceneJS.Camera} nodes. + * @returns [Number] The 2D Canvas-space coordinate + */ +SceneJS.RenderContext.prototype.getCanvasPos = function(offset) { + + this.getProjPos(offset); + + var canvas = this._frameCtx.canvas.canvas; + var ssaaMultiplier = this._frameCtx.canvas.ssaaMultiplier; + var canvasWidth = canvas.width / ssaaMultiplier; + var canvasHeight = canvas.height / ssaaMultiplier; + + /* Projection division and map to canvas + */ + var pc = this._pc; + + var x = (pc[0] / pc[3]) * canvasWidth * 0.5; + var y = (pc[1] / pc[3]) * canvasHeight * 0.5; + + return { + x: x + (canvasWidth * 0.5), + y: canvasHeight - y - (canvasHeight * 0.5) + }; +}; + +/** + * Transforms the given world coordinate by the model and view matrices defined by the active {@link SceneJS.XForm} and {@link SceneJS.LookAt} nodes. + * @returns [Number] The 3D Projection-space coordinate + */ +SceneJS.RenderContext.prototype.getCameraPos = function(offset) { + this.getProjPos(offset); + this._camPos = SceneJS_math_normalizeVec3(this._pc, [0,0,0]); + return { x: this._camPos[0], y: this._camPos[1], z: this._camPos[2] }; // TODO: return _camPos and lose the temp object +}; + + +SceneJS.RenderContext.prototype.getProjPos = function(offset) { + this.getViewPos(offset); + this._pc = SceneJS_math_transformPoint3(this._frameCtx.cameraMat, this._vc); + return { x: this._pc[0], y: this._pc[1], z: this._pc[2], w: this._pc[3] }; +}; + +SceneJS.RenderContext.prototype.getViewPos = function(offset) { + this.getWorldPos(offset); + this._vc = SceneJS_math_transformPoint3(this._frameCtx.viewMat, this._wc); + return { x: this._vc[0], y: this._vc[1], z: this._vc[2], w: this._vc[3] }; +}; + +SceneJS.RenderContext.prototype.getWorldPos = function(offset) { + this._wc = SceneJS_math_transformPoint3(this._frameCtx.modelMat, offset || [0,0,0]); + return { x: this._wc[0], y: this._wc[1], z: this._wc[2], w: this._wc[3] }; +}; +;/** + * @class A chunk of WebGL state changes to render a {@link SceneJS_Core} for drawing and picking (if applicable to the core type). + * + *

Instances of this class are created and recycled by a {@link SceneJS_ChunkFactory}.

+ * + *

Each {@link SceneJS_Object} has a list of chunks to render it's {@link SceneJS_Core}s

+ * + * @private + */ +var SceneJS_Chunk = function() {}; + +/** + * Initialises the chunk. This is called within the constructor, and also to by the owner {@link SceneJS_ChunkFactory} + * when recycling a chunk from its free chunk pool. This method sets the given properties on the chunk, then calls the + * chunk instance's build method if the chunk has been augmented with one. + * + * @param {String} id Chunk ID + * @param {SceneJS_Program} program Program to render the chunk + * @param {SceneJS_Core} core The state core rendered by this chunk + * @param {SceneJS_Core} core2 Another state core rendered by this chunk, only used for geometry + */ +SceneJS_Chunk.prototype.init = function(id, program, core, core2) { + + this.id = id; + this.program = program; + this.core = core; + this.core2 = core2; + + if (this.build) { + this.build(); + } +}; +;/** + * @class Manages creation, reuse and destruction of {@link SceneJS_Chunk}s for the nodes within a single {@link SceneJS_Display}. + * @private + */ +var SceneJS_ChunkFactory = function() { + + this._chunks = {}; + this.chunkTypes = SceneJS_ChunkFactory.chunkTypes; +}; + +/** + * Sub-classes of {@link SceneJS_Chunk} provided by this factory + */ +SceneJS_ChunkFactory.chunkTypes = {}; // Supported chunk classes, installed by #createChunkType + +/** + * Free pool of unused {@link SceneJS_Chunk} instances + */ +SceneJS_ChunkFactory._freeChunks = {}; // Free chunk pool for each type + +/** + * Creates a chunk class for instantiation by this factory + * + * @param params Members to augment the chunk class prototype with + * @param params.type Type name for the new chunk class + * @param params.draw Method to render the chunk in draw render + * @param params.pick Method to render the chunk in pick render + * @param params.drawAndPick Method to render the chunk in both draw and pick renders + */ +SceneJS_ChunkFactory.createChunkType = function(params) { + + if (!params.type) { + throw "'type' expected in params"; + } + + var supa = SceneJS_Chunk; + + var chunkClass = function() { // Create the class + this.useCount = 0; + this.init.apply(this, arguments); + }; + + chunkClass.prototype = new supa(); // Inherit from base class + chunkClass.prototype.constructor = chunkClass; + + if (params.drawAndPick) { // Common method for draw and pick render + params.draw = params.pick = params.drawAndPick; + } + + SceneJS_ChunkFactory.chunkTypes[params.type] = chunkClass; + + SceneJS._apply(params, chunkClass.prototype); // Augment subclass + + SceneJS_ChunkFactory._freeChunks[params.type] = { // Set up free chunk pool for this type + chunks: [], + chunksLen: 0 + }; + + return chunkClass; +}; + +/** + * + */ +SceneJS_ChunkFactory.prototype.getChunk = function(chunkId, type, program, core, core2) { + + var chunkClass = SceneJS_ChunkFactory.chunkTypes[type]; // Check type supported + + if (!chunkClass) { + throw "chunk type not supported: '" + type + "'"; + } + + var chunk = this._chunks[chunkId]; // Try to reference an existing chunk + + if (chunk) { + chunk.useCount++; + return chunk; + } + + var freeChunks = SceneJS_ChunkFactory._freeChunks[type]; // Try to recycle a free chunk + + if (freeChunks.chunksLen > 0) { + chunk = freeChunks.chunks[--freeChunks.chunksLen]; + } + + if (chunk) { // Reinitialise the recycled chunk + + chunk.init(chunkId, program, core, core2); + + } else { // Instantiate a fresh chunk + + chunk = new chunkClass(chunkId, program, core, core2); // Create new chunk + + } + + chunk.type = type; + + chunk.useCount = 1; + + this._chunks[chunkId] = chunk; + + return chunk; +}; + +/** + * Releases a display state chunk back to this factory, destroying it if the chunk's use count is then zero. + * + * @param {SceneJS_Chunk} chunk Chunk to release + */ +SceneJS_ChunkFactory.prototype.putChunk = function (chunk) { + + if (chunk.useCount == 0) { + return; // In case of excess puts + } + + if (--chunk.useCount <= 0) { // Release shared core if use count now zero + + if (chunk.recycle) { + chunk.recycle(); + } + + delete this._chunks[chunk.id]; + + var freeChunks = SceneJS_ChunkFactory._freeChunks[chunk.type]; + + freeChunks.chunks[freeChunks.chunksLen++] = chunk; + } +}; + +/** + * Re-cache shader variable locations for each active chunk and reset VAOs if any + */ +SceneJS_ChunkFactory.prototype.webglRestored = function () { + + var chunk; + + for (var chunkId in this._chunks) { + + if (this._chunks.hasOwnProperty(chunkId)) { + + chunk = this._chunks[chunkId]; // Re-cache chunk's shader variable locations + + if (chunk && chunk.build) { + chunk.build(); + } + } + } +}; +;SceneJS_ChunkFactory.createChunkType({ + + type: "camera", + + build : function() { + + this._uPMatrixDraw = this.program.draw.getUniform("SCENEJS_uPMatrix"); + this._uZNearDraw = this.program.draw.getUniform("SCENEJS_uZNear"); + this._uZFarDraw = this.program.draw.getUniform("SCENEJS_uZFar"); + + this._uPMatrixPick = this.program.pick.getUniform("SCENEJS_uPMatrix"); + this._uZNearPick = this.program.pick.getUniform("SCENEJS_uZNear"); + this._uZFarPick = this.program.pick.getUniform("SCENEJS_uZFar"); + }, + + draw : function(frameCtx) { + + if (this.core.checkAspect) { + this.core.checkAspect(this.core, frameCtx.aspect); + } + + var gl = this.program.gl; + + if (this._uPMatrixDraw) { + this._uPMatrixDraw.setValue(this.core.mat); + } + + if (this._uZNearDraw) { + this._uZNearDraw.setValue(this.core.optics.near); + } + + if (this._uZFarDraw) { + this._uZFarDraw.setValue(this.core.optics.far); + } + + frameCtx.cameraMat = this.core.mat; // Query only in draw pass + }, + + + pick : function(frameCtx) { + + if (this.core.checkAspect) { + this.core.checkAspect(this.core, frameCtx.aspect); + } + + var gl = this.program.gl; + + if (this._uPMatrixPick) { + this._uPMatrixPick.setValue(this.core.mat); + } + + if (frameCtx.rayPick) { // Z-pick pass: feed near and far clip planes into shader + + if (this._uZNearPick) { + this._uZNearPick.setValue(this.core.optics.near); + } + + if (this._uZFarPick) { + this._uZFarPick.setValue(this.core.optics.far); + } + } + + frameCtx.cameraMat = this.core.mat; // Query only in draw pass + } +});;/** + * Create display state chunk type for draw and pick render of user clipping planes + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "clips", + + build : function() { + + this._draw = this._draw || []; + + var draw = this.program.draw; + + for (var i = 0, len = this.core.clips.length; i < len; i++) { + this._draw[i] = { + uClipMode :draw.getUniform("SCENEJS_uClipMode" + i), + uClipNormalAndDist: draw.getUniform("SCENEJS_uClipNormalAndDist" + i) + }; + } + + this._pick = this._pick || []; + + var pick = this.program.pick; + + for (var i = 0, len = this.core.clips.length; i < len; i++) { + this._pick[i] = { + uClipMode :pick.getUniform("SCENEJS_uClipMode" + i), + uClipNormalAndDist: pick.getUniform("SCENEJS_uClipNormalAndDist" + i) + }; + } + }, + + drawAndPick: function(frameCtx) { + + var vars = (frameCtx.pick) ? this._pick : this._draw; + + var mode; + var normalAndDist; + var clips = this.core.clips; + var clip; + var gl = this.program.gl; + + for (var i = 0, len = clips.length; i < len; i++) { + + if (frameCtx.pick) { + mode = vars[i].uClipMode; + normalAndDist = vars[i].uClipNormalAndDist; + } else { + mode = vars[i].uClipMode; + normalAndDist = vars[i].uClipNormalAndDist; + } + + if (mode && normalAndDist) { + + clip = clips[i]; + + if (clip.mode == "inside") { + + mode.setValue(2); + normalAndDist.setValue(clip.normalAndDist); + + } else if (clip.mode == "outside") { + + mode.setValue(1); + normalAndDist.setValue(clip.normalAndDist); + + } else { // disabled + mode.setValue(0); + } + } + } + } +});;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "draw", + + /** + * As we apply a list of state chunks in a {@link SceneJS_Display}, we track the ID of each chunk + * in order to avoid redundantly re-applying the same chunk. + * + * We don't want that for draw chunks however, because they contain GL drawElements calls, + * which we need to do for each object. + */ + unique: true, + + build: function () { + this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); + this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); + }, + + drawAndPick: function (frameCtx) { + + var gl = this.program.gl; + + var indexType = this.program.UINT_INDEX_ENABLED ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT; + + if (frameCtx.pick) { + if (this._depthModePick) { + this._depthModePick.setValue(frameCtx.depthMode); + } + } else { + if (this._depthModeDraw) { + this._depthModeDraw.setValue(frameCtx.depthMode); + } + } + + gl.drawElements(this.core.primitive, this.core.indexBuf.numItems, indexType, 0); + + //frameCtx.textureUnit = 0; + } +}); +;/** + * Create display state chunk type for draw and pick render of flags + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "flags", + + build: function () { + + var draw = this.program.draw; + + this._uClippingDraw = draw.getUniform("SCENEJS_uClipping"); + this._uSolidDraw = draw.getUniform("SCENEJS_uSolid"); + + var pick = this.program.pick; + + this._uClippingPick = pick.getUniform("SCENEJS_uClipping"); + }, + + drawAndPick: function (frameCtx) { + + var gl = this.program.gl; + + var backfaces = this.core.backfaces; + + if (frameCtx.backfaces != backfaces) { + if (backfaces) { + gl.disable(gl.CULL_FACE); + } else { + gl.enable(gl.CULL_FACE); + } + frameCtx.backfaces = backfaces; + } + + var frontface = this.core.frontface; + + if (frameCtx.frontface != frontface) { + if (frontface == "ccw") { + gl.frontFace(gl.CCW); + } else { + gl.frontFace(gl.CW); + } + frameCtx.frontface = frontface; + } + + var transparent = this.core.transparent; + + if (frameCtx.transparent != transparent) { + if (!frameCtx.pick) { + if (transparent) { + + // Entering a transparency bin + + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + frameCtx.blendEnabled = true; + + } else { + + // Leaving a transparency bin + + gl.disable(gl.BLEND); + frameCtx.blendEnabled = false; + } + } + frameCtx.transparent = transparent; + } + + if (frameCtx.pick) { + + if (this._uClippingPick) { + this._uClippingPick.setValue(this.core.clipping); + } + + } else { + + if (this._uClippingDraw) { + this._uClippingDraw.setValue(this.core.clipping); + } + + if (this._uSolidDraw) { + this._uSolidDraw.setValue(this.core.solid); + } + } + } +}); +;/** + * Create display state chunk type for draw and pick render of renderTarget + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "renderTarget", + + // Avoid reapplication of this chunk type after a program switch. + programGlobal: true, + + draw: function (frameCtx) { + + var gl = this.program.gl; + + // Flush and unbind any render buffer already bound + if (frameCtx.renderBuf) { + gl.flush(); + frameCtx.renderBuf.unbind(); + frameCtx.renderBuf = null; + } + + // Set depthMode false and bail if no render buffer for this chunk + var renderBuf = this.core.renderBuf; + if (!renderBuf) { + frameCtx.depthMode = false; + return; + } + + // Bind this chunk's render buffer, set depthMode, enable blend if depthMode false, clear buffer + renderBuf.bind(); + + frameCtx.depthMode = (this.core.bufType === "depth"); + + if (!frameCtx.depthMode) { + + // Enable blending for non-depth targets + if (frameCtx.blendEnabled) { + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + } + } + + gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + gl.clearColor(frameCtx.ambientColor[0], frameCtx.ambientColor[1], frameCtx.ambientColor[2], 1.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); + // gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + frameCtx.renderBuf = renderBuf; + } +});;/** + * Create display state chunk type for draw and pick render of geometry + */ +SceneJS_ChunkFactory.createChunkType({ + + type:"geometry", + + build:function () { + + var draw = this.program.draw; + + this._aVertexDraw = draw.getAttribute("SCENEJS_aVertex"); + this._aNormalDraw = draw.getAttribute("SCENEJS_aNormal"); + this._aUVDraw = draw.getAttribute("SCENEJS_aUVCoord"); + this._aUV2Draw = draw.getAttribute("SCENEJS_aUVCoord2"); + this._aTangentDraw = draw.getAttribute("SCENEJS_aTangent"); + this._aColorDraw = draw.getAttribute("SCENEJS_aVertexColor"); + + this._aMorphVertexDraw = draw.getAttribute("SCENEJS_aMorphVertex"); + this._aMorphNormalDraw = draw.getAttribute("SCENEJS_aMorphNormal"); + this._uMorphFactorDraw = draw.getUniform("SCENEJS_uMorphFactor"); + + var pick = this.program.pick; + + this._aVertexPick = pick.getAttribute("SCENEJS_aVertex"); + this._aMorphVertexPick = pick.getAttribute("SCENEJS_aMorphVertex"); + this._uMorphFactorPick = pick.getUniform("SCENEJS_uMorphFactor"); + + this.VAO = null; + this.VAOMorphKey1 = 0; + this.VAOMorphKey2 = 0; + this.VAOHasInterleavedBuf = false; + }, + + recycle:function () { + if (this.VAO) { + // Guarantee that the old VAO is deleted immediately when recycling the object. + var VAOExt = this.program.gl.getExtension("OES_vertex_array_object"); + VAOExt.deleteVertexArrayOES(this.VAO); + this.VAO = null; + } + }, + + morphDraw:function () { + this.VAOMorphKey1 = this.core.key1; + this.VAOMorphKey2 = this.core.key2; + + var target1 = this.core.targets[this.core.key1]; // Keys will update + var target2 = this.core.targets[this.core.key2]; + + if (this._aMorphVertexDraw) { + this._aVertexDraw.bindFloatArrayBuffer(target1.vertexBuf); + this._aMorphVertexDraw.bindFloatArrayBuffer(target2.vertexBuf); + } else if (this._aVertexDraw) { + this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf); + } + + if (this._aMorphNormalDraw) { + this._aNormalDraw.bindFloatArrayBuffer(target1.normalBuf); + this._aMorphNormalDraw.bindFloatArrayBuffer(target2.normalBuf); + } else if (this._aNormalDraw) { + this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf); + } + + if (this._aUVDraw) { + this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf); + } + + if (this._aUV2Draw) { + this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2); + } + + if (this._aColorDraw) { + this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); + } + + this.setDrawMorphFactor(); + }, + + setDrawMorphFactor:function () { + + if (this._uMorphFactorDraw) { + this._uMorphFactorDraw.setValue*(this.core.factor); // Bind LERP factor + } + + }, + + draw:function (frameCtx) { + var doMorph = this.core.targets && this.core.targets.length; + var cleanInterleavedBuf = this.core2.interleavedBuf && !this.core2.interleavedBuf.dirty; + + if (this.VAO) { + frameCtx.VAO.bindVertexArrayOES(this.VAO); + if (doMorph) { + if (this.VAOMorphKey1 == this.core.key1 && this.VAOMorphKey2 == this.core.key2) { + this.setDrawMorphFactor(); + return; + } + } else if (cleanInterleavedBuf || !this.VAOHasInterleavedBuf) { + return; + } + } else if (frameCtx.VAO) { + // Start creating a new VAO by switching to the default VAO, which doesn't have attribs enabled. + frameCtx.VAO.bindVertexArrayOES(null); + this.VAO = frameCtx.VAO.createVertexArrayOES(); + frameCtx.VAO.bindVertexArrayOES(this.VAO); + var gl = this.program.gl; + } + + if (doMorph) { + this.morphDraw(); + } else { + if (cleanInterleavedBuf) { + this.VAOHasInterleavedBuf = true; + this.core2.interleavedBuf.bind(); + if (this._aVertexDraw) { + this._aVertexDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedPositionOffset); + } + if (this._aNormalDraw) { + this._aNormalDraw.bindInterleavedFloatArrayBuffer(3, this.core2.interleavedStride, this.core2.interleavedNormalOffset); + } + if (this._aUVDraw) { + this._aUVDraw.bindInterleavedFloatArrayBuffer(2, this.core2.interleavedStride, this.core2.interleavedUVOffset); + } + if (this._aUV2Draw) { + this._aUV2Draw.bindInterleavedFloatArrayBuffer(2, this.core2.interleavedStride, this.core2.interleavedUV2Offset); + } + if (this._aColorDraw) { + this._aColorDraw.bindInterleavedFloatArrayBuffer(4, this.core2.interleavedStride, this.core2.interleavedColorOffset); + } + if (this._aTangentDraw) { + + // Lazy-compute tangents as soon as needed. + // Unfortunately we can't include them in interleaving because that happened earlier. + this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf || this.core2.getTangentBuf()); + } + } else { + this.VAOHasInterleavedBuf = false; + if (this._aVertexDraw) { + this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf); + } + if (this._aNormalDraw) { + this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf); + } + if (this._aUVDraw) { + this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf); + } + if (this._aUV2Draw) { + this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2); + } + if (this._aColorDraw) { + this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf); + } + if (this._aTangentDraw) { + + // Lazy-compute tangents + this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf || this.core2.getTangentBuf()); + } + } + } + + this.core2.indexBuf.bind(); + + }, + + morphPick:function () { + + var target1 = this.core.targets[this.core.key1]; // Keys will update + var target2 = this.core.targets[this.core.key2]; + + if (this._aMorphVertexPick) { + this._aVertexPick.bindFloatArrayBuffer(target1.vertexBuf); + this._aMorphVertexPick.bindFloatArrayBuffer(target2.vertexBuf); + } else if (this._aVertexPick) { + this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf); + } + + if (this._uMorphFactorPick) { + this._uMorphFactorPick.setValue(this.core.factor); // Bind LERP factor + } + + }, + + pick:function (frameCtx) { + + if (this.core.targets && this.core.targets.length) { + this.morphPick(); + + } else { + + if (this._aVertexPick) { + this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf); + } + } + + this.core2.indexBuf.bind(); + } +}); +;/** + * Create display state chunk type for draw render of lights projection + */ +SceneJS_ChunkFactory.createChunkType({ + + type:"lights", + + build:function () { + + this._uAmbientColor = this._uAmbientColor || []; + this._uLightColor = this._uLightColor || []; + this._uLightDir = this._uLightDir || []; + this._uLightPos = this._uLightPos || []; + this._uLightCutOff = this._uLightCutOff || []; + this._uLightSpotExp = this._uLightSpotExp || []; + this._uLightAttenuation = this._uLightAttenuation || []; + + var lights = this.core.lights; + var program = this.program; + + for (var i = 0, len = lights.length; i < len; i++) { + + switch (lights[i].mode) { + + case "ambient": + this._uAmbientColor[i] = (program.draw.getUniform("SCENEJS_uAmbientColor")); + break; + + case "dir": + this._uLightColor[i] = program.draw.getUniform("SCENEJS_uLightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.draw.getUniform("SCENEJS_uLightDir" + i); + break; + + case "point": + this._uLightColor[i] = program.draw.getUniform("SCENEJS_uLightColor" + i); + this._uLightPos[i] = program.draw.getUniform("SCENEJS_uLightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.draw.getUniform("SCENEJS_uLightAttenuation" + i); + break; + } + } + }, + + draw:function (frameCtx) { + + if (frameCtx.dirty) { + this.build(); + } + + var lights = this.core.lights; + var light; + + var gl = this.program.gl; + + for (var i = 0, len = lights.length; i < len; i++) { + + light = lights[i]; + + if (this._uAmbientColor[i]) { + this._uAmbientColor[i].setValue(light.color); + + } else { + + if (this._uLightColor[i]) { + this._uLightColor[i].setValue(light.color); + } + + if (this._uLightPos[i]) { + this._uLightPos[i].setValue(light.pos); + + if (this._uLightAttenuation[i]) { + this._uLightAttenuation[i].setValue(light.attenuation); + } + } + + if (this._uLightDir[i]) { + this._uLightDir[i].setValue(light.dir); + } + } + } + } +});;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "listeners", + + // Avoid reapplication of a chunk after a program switch. + programGlobal:true, + + build : function() { + }, + + draw : function(frameCtx) { + + var listeners = this.core.listeners; + var renderListenerCtx = frameCtx.renderListenerCtx; + + for (var i = listeners.length - 1; i >= 0; i--) { // Child listeners first + if (listeners[i](renderListenerCtx) === true) { // Call listener with query facade object as scope + return true; + } + } + } +});;/** + * Create display state chunk type for draw and pick render of lookAt transform + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "lookAt", + + build : function() { + + this._uvMatrixDraw = this.program.draw.getUniform("SCENEJS_uVMatrix"); + this._uVNMatrixDraw = this.program.draw.getUniform("SCENEJS_uVNMatrix"); + this._uWorldEyeDraw = this.program.draw.getUniform("SCENEJS_uWorldEye"); + + this._uvMatrixPick = this.program.pick.getUniform("SCENEJS_uVMatrix"); + }, + + draw : function(frameCtx) { + + if (this.core.dirty) { + this.core.rebuild(); + } + + var gl = this.program.gl; + + if (this._uvMatrixDraw) { + this._uvMatrixDraw.setValue(this.core.mat); + } + + if (this._uVNMatrixDraw) { + this._uVNMatrixDraw.setValue(this.core.normalMat); + } + + if (this._uWorldEyeDraw) { + this._uWorldEyeDraw.setValue(this.core.lookAt.eye); + } + + frameCtx.viewMat = this.core.mat; + }, + + pick : function(frameCtx) { + + var gl = this.program.gl; + + if (this._uvMatrixPick) { + this._uvMatrixPick.setValue(this.core.mat); + } + + frameCtx.viewMat = this.core.mat; + } +});;/** + * Create display state chunk type for draw render of material transform + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "material", + + build: function () { + + var draw = this.program.draw; + + this._uMaterialBaseColor = draw.getUniform("SCENEJS_uMaterialColor"); + this._uMaterialSpecularColor = draw.getUniform("SCENEJS_uMaterialSpecularColor"); + this._uMaterialSpecular = draw.getUniform("SCENEJS_uMaterialSpecular"); + this._uMaterialShine = draw.getUniform("SCENEJS_uMaterialShine"); + this._uMaterialEmit = draw.getUniform("SCENEJS_uMaterialEmit"); + this._uMaterialAlpha = draw.getUniform("SCENEJS_uMaterialAlpha"); + }, + + draw: function () { + + var gl = this.program.gl; + + if (this._uMaterialBaseColor) { + this._uMaterialBaseColor.setValue(this.core.baseColor); + } + + if (this._uMaterialSpecularColor) { + this._uMaterialSpecularColor.setValue(this.core.specularColor); + } + + if (this._uMaterialSpecular) { + this._uMaterialSpecular.setValue(this.core.specular); + } + + if (this._uMaterialShine) { + this._uMaterialShine.setValue(this.core.shine); + } + + if (this._uMaterialEmit) { + this._uMaterialEmit.setValue(this.core.emit); + } + + if (this._uMaterialAlpha) { + this._uMaterialAlpha.setValue(this.core.alpha); + } + } +}); +;/** + * Create display state chunk type for draw render of material transform + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "name", + + build: function () { + this._uPickColor = this.program.pick.getUniform("SCENEJS_uPickColor"); + }, + + pick: function (frameCtx) { + + if (this._uPickColor && this.core.name) { + + frameCtx.pickNames[frameCtx.pickIndex++] = this.core; + + var b = frameCtx.pickIndex >> 16 & 0xFF; + var g = frameCtx.pickIndex >> 8 & 0xFF; + var r = frameCtx.pickIndex & 0xFF; + + this._uPickColor.setValue([r / 255, g / 255, b / 255]); + } + } +});;SceneJS_ChunkFactory.createChunkType({ + + type: "program", + + build : function() { + + // Note that "program" chunks are always after "renderTarget" chunks + this._depthModeDraw = this.program.draw.getUniform("SCENEJS_uDepthMode"); + this._depthModePick = this.program.pick.getUniform("SCENEJS_uDepthMode"); + this._rayPickMode = this.program.pick.getUniform("SCENEJS_uRayPickMode"); + }, + + draw : function(frameCtx) { + var drawProgram = this.program.draw; + drawProgram.bind(); + frameCtx.textureUnit = 0; + var gl = this.program.gl; + if (this._depthModeDraw) { + this._depthModeDraw.setValue(frameCtx.depthMode); + } + if (!frameCtx.VAO) { + for (var i = 0; i < 10; i++) { + gl.disableVertexAttribArray(i); + } + } + + frameCtx.drawProgram = this.program.draw; + }, + + pick : function(frameCtx) { + var pickProgram = this.program.pick; + pickProgram.bind(); + var gl = this.program.gl; + if (this._rayPickMode) { + this._rayPickMode.setValue(frameCtx.rayPick); + } + if (this._depthModePick) { + this._depthModePick.setValue(frameCtx.depthMode); + } + frameCtx.textureUnit = 0; + for (var i = 0; i < 10; i++) { + gl.disableVertexAttribArray(i); + } + } +}); + + + +;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "renderer", + + build: function () { + }, + + drawAndPick: function (frameCtx) { + + if (this.core.props) { + var gl = this.program.gl; + if (frameCtx.renderer) { + frameCtx.renderer.props.restoreProps(gl); + frameCtx.renderer = this.core; + } + this.core.props.setProps(gl); + } + } +}); +;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type:"depthBuffer", + + // Avoid reapplication of a chunk after a program switch. + programGlobal:true, + + drawAndPick:function (frameCtx) { + + var gl = this.program.gl; + + var enabled = this.core.enabled; + + if (frameCtx.depthbufEnabled != enabled) { + if (enabled) { + gl.enable(gl.DEPTH_TEST); + } else { + gl.disable(gl.DEPTH_TEST); + } + frameCtx.depthbufEnabled = enabled; + } + + var clearDepth = this.core.clearDepth; + + if (frameCtx.clearDepth != clearDepth) { + gl.clearDepth(clearDepth); + frameCtx.clearDepth = clearDepth; + } + + var depthFunc = this.core.depthFunc; + + if (frameCtx.depthFunc != depthFunc) { + gl.depthFunc(depthFunc); + frameCtx.depthFunc = depthFunc; + } + + if (this.core.clear) { + gl.clear(gl.DEPTH_BUFFER_BIT); + } + } +}); +;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type:"colorBuffer", + + // Avoid reapplication of a chunk after a program switch. + programGlobal:true, + + build:function () { + }, + + drawAndPick:function (frameCtx) { + + if (!frameCtx.transparent) { // Blending forced when rendering transparent bin + + var blendEnabled = this.core.blendEnabled; + + var gl = this.program.gl; + + if (frameCtx.blendEnabled != blendEnabled) { + if (blendEnabled) { + gl.enable(gl.BLEND); + } else { + gl.disable(gl.BLEND); + } + frameCtx.blendEnabled = blendEnabled; + } + + var colorMask = this.core.colorMask; + gl.colorMask(colorMask.r, colorMask.g, colorMask.b, colorMask.a); + } + } +}); +;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type:"view", + + // Avoid reapplication of a chunk after a program switch. + programGlobal:true, + + build:function () { + }, + + drawAndPick:function (frameCtx) { + + var scissorTestEnabled = this.core.scissorTestEnabled; + + if (frameCtx.scissorTestEnabled != scissorTestEnabled) { + var gl = this.program.gl; + if (scissorTestEnabled) { + gl.enable(gl.SCISSOR_TEST); + } else { + gl.disable(gl.SCISSOR_TEST); + } + frameCtx.scissorTestEnabled = scissorTestEnabled; + } + } +}); +;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "shader", + + build : function() { + }, + + drawAndPick : function(frameCtx) { + + var paramsStack = this.core.paramsStack; + + if (paramsStack) { + + var program = frameCtx.pick ? this.program.pick : this.program.draw; + var params; + var name; + + for (var i = 0, len = paramsStack.length; i < len; i++) { + params = paramsStack[i]; + for (name in params) { + if (params.hasOwnProperty(name)) { + program.setUniform(name, params[name]); // TODO: cache locations + } + } + } + } + } +});;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type: "shaderParams", + + build : function() { + }, + + drawAndPick: function(frameCtx) { + + var paramsStack = this.core.paramsStack; + + if (paramsStack) { + + var program = frameCtx.pick ? this.program.pick : this.program.draw; + var params; + var name; + + for (var i = 0, len = paramsStack.length; i < len; i++) { + params = paramsStack[i]; + for (name in params) { + if (params.hasOwnProperty(name)) { + program.setUniform(name, params[name]); // TODO: cache locations + } + } + } + } + } +});;/** + * + */ +SceneJS_ChunkFactory.createChunkType({ + + type:"style", + + // Avoid reapplication of a chunk after a program switch. + programGlobal:true, + + drawAndPick:function (frameCtx) { + + var lineWidth = this.core.lineWidth; + + if (frameCtx.lineWidth != lineWidth) { + var gl = this.program.gl; + gl.lineWidth(lineWidth); + frameCtx.lineWidth = lineWidth; + } + } +}); +;SceneJS_ChunkFactory.createChunkType({ + + type: "texture", + + build : function() { + + this._uTexSampler = this._uTexSampler || []; + this._uTexMatrix = this._uTexMatrix || []; + this._uTexBlendFactor = this._uTexBlendFactor || []; + + var layers = this.core.layers; + + if (layers) { + + var layer; + var draw = this.program.draw; + + for (var i = 0, len = layers.length; i < len; i++) { + + layer = layers[i]; + + this._uTexSampler[i] = "SCENEJS_uSampler" + i; + + this._uTexMatrix[i] = draw.getUniform("SCENEJS_uLayer" + i + "Matrix"); + + this._uTexBlendFactor[i] = draw.getUniform("SCENEJS_uLayer" + i + "BlendFactor"); + } + } + }, + + draw : function(frameCtx) { + + frameCtx.textureUnit = 0; + + var layers = this.core.layers; + + if (layers) { + + var draw = this.program.draw; + var layer; + + for (var i = 0, len = layers.length; i < len; i++) { + + layer = layers[i]; + + if (this._uTexSampler[i] && layer.texture) { // Lazy-loads + + draw.bindTexture(this._uTexSampler[i], layer.texture, frameCtx.textureUnit++); + + if (layer._matrixDirty && layer.buildMatrix) { + layer.buildMatrix.call(layer); + } + + if (this._uTexMatrix[i]) { + this._uTexMatrix[i].setValue(layer.matrixAsArray); + } + + if (this._uTexBlendFactor[i]) { + this._uTexBlendFactor[i].setValue(layer.blendFactor); + } + + } else { + // draw.bindTexture(this._uTexSampler[i], null, i); // Unbind + } + } + } + + if (frameCtx.textureUnit > 10) { // TODO: Find how many textures allowed + frameCtx.textureUnit = 0; + } + } +});;SceneJS_ChunkFactory.createChunkType({ + + type: "cubemap", + + build: function () { + this._uCubeMapSampler = this._uCubeMapSampler || []; + this._uCubeMapIntensity = this._uCubeMapIntensity || []; + var layers = this.core.layers; + if (layers) { + var layer; + var draw = this.program.draw; + for (var i = 0, len = layers.length; i < len; i++) { + layer = layers[i]; + this._uCubeMapSampler[i] = "SCENEJS_uCubeMapSampler" + i; + this._uCubeMapIntensity[i] = draw.getUniform("SCENEJS_uCubeMapIntensity" + i); + } + } + }, + + draw: function (frameCtx) { + var layers = this.core.layers; + if (layers) { + var layer; + var draw = this.program.draw; + for (var i = 0, len = layers.length; i < len; i++) { + layer = layers[i]; + if (this._uCubeMapSampler[i] && layer.texture) { + draw.bindTexture(this._uCubeMapSampler[i], layer.texture, frameCtx.textureUnit++); + if (this._uCubeMapIntensity[i]) { + this._uCubeMapIntensity[i].setValue(layer.intensity); + } + } + } + } + + if (frameCtx.textureUnit > 10) { // TODO: Find how many textures allowed + frameCtx.textureUnit = 0; + } + } +});;SceneJS_ChunkFactory.createChunkType({ + + type: "xform", + + build: function () { + + var draw = this.program.draw; + + this._uMatLocationDraw = draw.getUniform("SCENEJS_uMMatrix"); + this._uNormalMatLocationDraw = draw.getUniform("SCENEJS_uMNMatrix"); + + var pick = this.program.pick; + + this._uMatLocationPick = pick.getUniform("SCENEJS_uMMatrix"); + }, + + draw: function (frameCtx) { + + /* Rebuild core's matrix from matrices at cores on path up to root + */ + if (SceneJS_configsModule.configs.forceXFormCoreRebuild === true || this.core.dirty && this.core.build) { + this.core.build(); + } + + var gl = this.program.gl; + + if (this._uMatLocationDraw) { + this._uMatLocationDraw.setValue(this.core.mat); + } + + if (this._uNormalMatLocationDraw) { + this._uNormalMatLocationDraw.setValue(this.core.normalMat); + } + + frameCtx.modelMat = this.core.mat; + }, + + pick: function (frameCtx) { + + /* Rebuild core's matrix from matrices at cores on path up to root + */ + if (this.core.dirty) { + this.core.build(); + } + + var gl = this.program.gl; + + if (this._uMatLocationPick) { + this._uMatLocationPick.setValue(this.core.mat); + } + + frameCtx.modelMat = this.core.mat; + } +}); diff --git a/build/4.2.0/scenejs-4.2.0.min.js b/build/4.2.0/scenejs-4.2.0.min.js new file mode 100644 index 00000000..5db1ccc7 --- /dev/null +++ b/build/4.2.0/scenejs-4.2.0.min.js @@ -0,0 +1,22 @@ +/* + * SceneJS V4.2.0 + * + * A WebGL-based 3D scene graph from xeoLabs + * http://scenejs.org/ + * + * Built on 2015-06-10 + * + * MIT License + * Copyright 2015, Lindsay Kay + * http://xeolabs.com/ + * + */ + +if(void 0===require){var requirejs,require,define;!function(ba){function J(a){return"[object Function]"===N.call(a)}function K(a){return"[object Array]"===N.call(a)}function z(a,b){if(a){var c;for(c=0;c-1&&(!a[c]||!b(a[c],c,a));c-=1);}}function t(a,b){return ha.call(a,b)}function m(a,b){return t(a,b)&&a[b]}function H(a,b){for(var c in a)if(t(a,c)&&b(a[c],c))break}function S(a,b,c,d){return b&&H(b,function(b,e){(c||!t(a,e))&&(d&&"string"!=typeof b?(a[e]||(a[e]={}),S(a[e],b,c,d)):a[e]=b)}),a}function v(a,b){return function(){return b.apply(a,arguments)}}function ca(a){throw a}function da(a){if(!a)return a;var b=ba;return z(a.split("."),function(a){b=b[a]}),b}function B(a,b,c,d){return b=Error(b+"\nhttp://requirejs.org/docs/errors.html#"+a),b.requireType=a,b.requireModules=d,c&&(b.originalError=c),b}function ia(a){function b(a,b,c){var d,e,f,g,h,i,j,k=b&&b.split("/");d=k;var l=C.map,n=l&&l["*"];if(a&&"."===a.charAt(0))if(b){for(d=m(C.pkgs,b)?k=[b]:k.slice(0,k.length-1),b=a=d.concat(a.split("/")),d=0;b[d];d+=1)if(e=b[d],"."===e)b.splice(d,1),d-=1;else if(".."===e){if(1===d&&(".."===b[2]||".."===b[0]))break;d>0&&(b.splice(d-1,2),d-=2)}d=m(C.pkgs,b=a[0]),a=a.join("/"),d&&a===b+"/"+d.main&&(a=b)}else 0===a.indexOf("./")&&(a=a.substring(2));if(c&&l&&(k||n)){for(b=a.split("/"),d=b.length;d>0;d-=1){if(f=b.slice(0,d).join("/"),k)for(e=k.length;e>0;e-=1)if((c=m(l,k.slice(0,e).join("/")))&&(c=m(c,f))){g=c,h=d;break}if(g)break;!i&&n&&m(n,f)&&(i=m(n,f),j=d)}!g&&i&&(g=i,h=j),g&&(b.splice(0,h,g),a=b.join("/"))}return a}function c(a){A&&z(document.getElementsByTagName("script"),function(b){return b.getAttribute("data-requiremodule")===a&&b.getAttribute("data-requirecontext")===w.contextName?(b.parentNode.removeChild(b),!0):void 0})}function d(a){var b=m(C.paths,a);return b&&K(b)&&1-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function f(a,c,d,f){var g,h,i=null,j=c?c.name:null,k=a,l=!0,n="";return a||(l=!1,a="_@r"+(M+=1)),a=e(a),i=a[0],a=a[1],i&&(i=b(i,j,f),h=m(I,i)),a&&(i?n=h&&h.normalize?h.normalize(a,function(a){return b(a,j,f)}):b(a,j,f):(n=b(a,j,f),a=e(n),i=a[0],n=a[1],d=!0,g=w.nameToUrl(n))),d=!i||h||d?"":"_unnormalized"+(N+=1),{prefix:i,name:n,parentMap:c,unnormalized:!!d,url:g,originalName:k,isDefine:l,id:(i?i+"!"+n:n)+d}}function g(a){var b=a.id,c=m(D,b);return c||(c=D[b]=new w.Module(a)),c}function i(a,b,c){var d=a.id,e=m(D,d);!t(I,d)||e&&!e.defineEmitComplete?(e=g(a),e.error&&"error"===b?c(e.error):e.on(b,c)):"defined"===b&&c(I[d])}function j(a,b){var c=a.requireModules,d=!1;b?b(a):(z(c,function(b){(b=m(D,b))&&(b.error=a,b.events.error&&(d=!0,b.emit("error",a)))}),d||h.onError(a))}function k(){U.length&&(ja.apply(G,[G.length-1,0].concat(U)),U=[])}function l(a){delete D[a],delete E[a]}function n(a,b,c){var d=a.map.id;a.error?a.emit("error",a.error):(b[d]=!0,z(a.depMaps,function(d,e){var f=d.id,g=m(D,f);g&&!a.depMatched[e]&&!c[f]&&(m(b,f)?(a.defineDep(e,I[f]),a.check()):n(g,b,c))}),c[d]=!0)}function o(){var a,b,e,f,g=(e=1e3*C.waitSeconds)&&w.startTime+e<(new Date).getTime(),h=[],i=[],k=!1,l=!0;if(!s){if(s=!0,H(E,function(e){if(a=e.map,b=a.id,e.enabled&&(a.isDefine||i.push(e),!e.error))if(!e.inited&&g)d(b)?k=f=!0:(h.push(b),c(b));else if(!e.inited&&e.fetched&&a.isDefine&&(k=!0,!a.prefix))return l=!1}),g&&h.length)return e=B("timeout","Load timeout for modules: "+h,null,h),e.contextName=w.contextName,j(e);l&&z(i,function(a){n(a,{},{})}),g&&!f||!k||!A&&!ea||y||(y=setTimeout(function(){y=0,o()},50)),s=!1}}function p(a){t(I,a[0])||g(f(a[0],null,!0)).init(a[1],a[2])}function q(a){var a=a.currentTarget||a.srcElement,b=w.onScriptLoad;return a.detachEvent&&!Z?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1),b=w.onScriptError,(!a.detachEvent||Z)&&a.removeEventListener("error",b,!1),{node:a,id:a&&a.getAttribute("data-requiremodule")}}function r(){var a;for(k();G.length;){if(a=G.shift(),null===a[0])return j(B("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));p(a)}}var s,u,w,x,y,C={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{},config:{}},D={},E={},F={},G=[],I={},L={},M=1,N=1;return x={require:function(a){return a.require?a.require:a.require=w.makeRequire(a.map)},exports:function(a){return a.usingExports=!0,a.map.isDefine?a.exports?a.exports:a.exports=I[a.map.id]={}:void 0},module:function(a){return a.module?a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){var b=m(C.pkgs,a.map.id);return(b?m(C.config,a.map.id+"/"+b.main):m(C.config,a.map.id))||{}},exports:I[a.map.id]}}},u=function(a){this.events=m(F,a.id)||{},this.map=a,this.shim=m(C.shim,a.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0},u.prototype={init:function(a,b,c,d){d=d||{},this.inited||(this.factory=b,c?this.on("error",c):this.events.error&&(c=v(this,function(a){this.emit("error",a)})),this.depMaps=a&&a.slice(0),this.errback=c,this.inited=!0,this.ignore=d.ignore,d.enabled||this.enabled?this.enable():this.check())},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0,w.startTime=(new Date).getTime();var a=this.map;if(!this.shim)return a.prefix?this.callPlugin():this.load();w.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],v(this,function(){return a.prefix?this.callPlugin():this.load()}))}},load:function(){var a=this.map.url;L[a]||(L[a]=!0,w.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var d=this.exports,e=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,1>this.depCount&&!this.defined){if(J(e)){if(this.events.error&&this.map.isDefine||h.onError!==ca)try{d=w.execCb(c,e,b,d)}catch(f){a=f}else d=w.execCb(c,e,b,d);if(this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?d=b.exports:void 0===d&&this.usingExports&&(d=this.exports)),a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",j(this.error=a)}else d=e;this.exports=d,this.map.isDefine&&!this.ignore&&(I[c]=d,h.onResourceLoad)&&h.onResourceLoad(w,this.map,this.depMaps),l(c),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,c=a.id,d=f(a.prefix);this.depMaps.push(d),i(d,"defined",v(this,function(d){var e,k;k=this.map.name;var n=this.map.parentMap?this.map.parentMap.name:null,o=w.makeRequire(a.parentMap,{enableBuildCallback:!0});this.map.unnormalized?(d.normalize&&(k=d.normalize(k,function(a){return b(a,n,!0)})||""),d=f(a.prefix+"!"+k,this.map.parentMap),i(d,"defined",v(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),(k=m(D,d.id))&&(this.depMaps.push(d),this.events.error&&k.on("error",v(this,function(a){this.emit("error",a)})),k.enable())):(e=v(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),e.error=v(this,function(a){this.inited=!0,this.error=a,a.requireModules=[c],H(D,function(a){0===a.map.id.indexOf(c+"_unnormalized")&&l(a.map.id)}),j(a)}),e.fromText=v(this,function(b,d){var i=a.name,k=f(i),l=Q;d&&(b=d),l&&(Q=!1),g(k),t(C.config,c)&&(C.config[i]=C.config[c]);try{h.exec(b)}catch(m){return j(B("fromtexteval","fromText eval for "+c+" failed: "+m,m,[c]))}l&&(Q=!0),this.depMaps.push(k),w.completeLoad(i),o([i],e)}),d.load(a.name,o,e,C))})),w.enable(d,this),this.pluginMaps[d.id]=d},enable:function(){E[this.map.id]=this,this.enabling=this.enabled=!0,z(this.depMaps,v(this,function(a,b){var c,d;if("string"==typeof a){if(a=f(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[b]=a,c=m(x,a.id))return void(this.depExports[b]=c(this));this.depCount+=1,i(a,"defined",v(this,function(a){this.defineDep(b,a),this.check()})),this.errback&&i(a,"error",v(this,this.errback))}c=a.id,d=D[c],!t(x,c)&&d&&!d.enabled&&w.enable(a,this)})),H(this.pluginMaps,v(this,function(a){var b=m(D,a.id);b&&!b.enabled&&w.enable(a,this)})),this.enabling=!1,this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]),c.push(b)},emit:function(a,b){z(this.events[a],function(a){a(b)}),"error"===a&&delete this.events[a]}},w={config:C,contextName:a,registry:D,defined:I,urlFetched:L,defQueue:G,Module:u,makeModuleMap:f,nextTick:h.nextTick,onError:j,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=C.pkgs,c=C.shim,d={paths:!0,config:!0,map:!0};H(a,function(a,b){d[b]?"map"===b?(C.map||(C.map={}),S(C[b],a,!0,!0)):S(C[b],a,!0):C[b]=a}),a.shim&&(H(a.shim,function(a,b){K(a)&&(a={deps:a}),!a.exports&&!a.init||a.exportsFn||(a.exportsFn=w.makeShimExports(a)),c[b]=a}),C.shim=c),a.packages&&(z(a.packages,function(a){a="string"==typeof a?{name:a}:a,b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(fa,"")}}),C.pkgs=b),H(D,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=f(b))}),(a.deps||a.callback)&&w.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;return a.init&&(b=a.init.apply(ba,arguments)),b||a.exports&&da(a.exports)}},makeRequire:function(c,d){function e(b,i,k){var l,m;return d.enableBuildCallback&&i&&J(i)&&(i.__requireJsBuild=!0),"string"==typeof b?J(i)?j(B("requireargs","Invalid require call"),k):c&&t(x,b)?x[b](D[c.id]):h.get?h.get(w,b,c,e):(l=f(b,c,!1,!0),l=l.id,t(I,l)?I[l]:j(B("notloaded",'Module name "'+l+'" has not been loaded yet for context: '+a+(c?"":". Use require([])")))):(r(),w.nextTick(function(){r(),m=g(f(null,c)),m.skipMap=d.skipMap,m.init(b,i,k,{enabled:!0}),o()}),e)}return d=d||{},S(e,{isBrowser:A,toUrl:function(a){var d,e=a.lastIndexOf("."),f=a.split("/")[0];return-1!==e&&("."!==f&&".."!==f||e>1)&&(d=a.substring(e,a.length),a=a.substring(0,e)),w.nameToUrl(b(a,c&&c.id,!0),d,!0)},defined:function(a){return t(I,f(a,c,!1,!0).id)},specified:function(a){return a=f(a,c,!1,!0).id,t(I,a)||t(D,a)}}),c||(e.undef=function(a){k();var b=f(a,c,!0),d=m(D,a);delete I[a],delete L[b.url],delete F[a],d&&(d.events.defined&&(F[a]=d.events),l(a))}),e},enable:function(a){m(D,a.id)&&g(a).enable()},completeLoad:function(a){var b,c,e=m(C.shim,a)||{},f=e.exports;for(k();G.length;){if(c=G.shift(),null===c[0]){if(c[0]=a,b)break;b=!0}else c[0]===a&&(b=!0);p(c)}if(c=m(D,a),!b&&!t(I,a)&&c&&!c.inited){if(C.enforceDefine&&(!f||!da(f)))return d(a)?void 0:j(B("nodefine","No define call for "+a,null,[a]));p([a,e.deps||[],e.exportsFn])}o()},nameToUrl:function(a,b,c){var d,e,f,g,i,j;if(h.jsExtRegExp.test(a))g=a+(b||"");else{for(d=C.paths,e=C.pkgs,g=a.split("/"),i=g.length;i>0;i-=1){if(j=g.slice(0,i).join("/"),f=m(e,j),j=m(d,j)){K(j)&&(j=j[0]),g.splice(0,i,j);break}if(f){a=a===f.name?f.location+"/"+f.main:f.location,g.splice(0,i,a);break}}g=g.join("/"),g+=b||(/\?/.test(g)||c?"":".js"),g=("/"===g.charAt(0)||g.match(/^[\w\+\.\-]+:/)?"":C.baseUrl)+g}return C.urlArgs?g+((-1===g.indexOf("?")?"?":"&")+C.urlArgs):g},load:function(a,b){h.load(w,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){("load"===a.type||la.test((a.currentTarget||a.srcElement).readyState))&&(R=null,a=q(a),w.completeLoad(a.id))},onScriptError:function(a){var b=q(a);return d(b.id)?void 0:j(B("scripterror","Script error for: "+b.id,a,[b.id]))}},w.require=w.makeRequire(),w}var h,x,y,E,L,F,R,M,s,ga,ma=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/gm,na=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,fa=/\.js$/,ka=/^\.\//;x=Object.prototype;var N=x.toString,ha=x.hasOwnProperty,ja=Array.prototype.splice,A=!("undefined"==typeof window||!navigator||!window.document),ea=!A&&"undefined"!=typeof importScripts,la=A&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,Z="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),G={},u={},U=[],Q=!1;if("undefined"==typeof define){if("undefined"!=typeof requirejs){if(J(requirejs))return;u=requirejs,requirejs=void 0}"undefined"!=typeof require&&!J(require)&&(u=require,require=void 0),h=requirejs=function(a,b,c,d){var e,f="_";return!K(a)&&"string"!=typeof a&&(e=a,K(b)?(a=b,b=c,c=d):a=[]),e&&e.context&&(f=e.context),(d=m(G,f))||(d=G[f]=h.s.newContext(f)),e&&d.configure(e),d.require(a,b,c)},h.config=function(a){return h(a)},h.nextTick="undefined"!=typeof setTimeout?function(a){setTimeout(a,4)}:function(a){a()},require||(require=h),h.version="2.1.6",h.jsExtRegExp=/^\/|:|\?|\.js$/,h.isBrowser=A,x=h.s={contexts:G,newContext:ia},h({}),z(["toUrl","undef","defined","specified"],function(a){h[a]=function(){var b=G._;return b.require[a].apply(b,arguments)}}),A&&(y=x.head=document.getElementsByTagName("head")[0],E=document.getElementsByTagName("base")[0])&&(y=x.head=E.parentNode),h.onError=ca,h.load=function(a,b,c){var d,e=a&&a.config||{};if(A)return d=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),d.type=e.scriptType||"text/javascript",d.charset="utf-8",d.async=!0,d.setAttribute("data-requirecontext",a.contextName),d.setAttribute("data-requiremodule",b),!d.attachEvent||d.attachEvent.toString&&0>d.attachEvent.toString().indexOf("[native code")||Z?(d.addEventListener("load",a.onScriptLoad,!1),d.addEventListener("error",a.onScriptError,!1)):(Q=!0,d.attachEvent("onreadystatechange",a.onScriptLoad)),d.src=c,M=d,E?y.insertBefore(d,E):y.appendChild(d),M=null,d;if(ea)try{importScripts(c),a.completeLoad(b)}catch(f){a.onError(B("importscripts","importScripts failed for "+b+" at "+c,f,[b]))}},A&&O(document.getElementsByTagName("script"),function(a){return y||(y=a.parentNode),(L=a.getAttribute("data-main"))?(s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0):void 0}),define=function(a,b,c){var d,e;"string"!=typeof a&&(c=b,b=a,a=null),K(b)||(c=b,b=null),!b&&J(c)&&(b=[],c.length&&(c.toString().replace(ma,"").replace(na,function(a,c){b.push(c)}),b=(1===c.length?["require"]:["require","exports","module"]).concat(b))),Q&&((d=M)||(R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(a){return"interactive"===a.readyState?R=a:void 0}),d=R),d&&(a||(a=d.getAttribute("data-requiremodule")),e=G[d.getAttribute("data-requirecontext")])),(e?e.defQueue:U).push([a,b,c])},define.amd={jQuery:!0},h.exec=function(b){return eval(b)},h(u)}}(this)}WebGLDebugUtils=function(){function a(a){if(null==m){m={};for(var b in a)"number"==typeof a[b]&&(m[a[b]]=b)}}function b(){if(null==m)throw"WebGLDebugUtils.init(ctx) not called"}function c(a){return b(),void 0!==m[a]}function d(a){b();var c=m[a];return void 0!==c?c:"*UNKNOWN WebGL ENUM (0x"+a.toString(16)+")"}function e(a,b,c){var e=l[a];return void 0!==e&&e[b]?d(c):null===c?"null":void 0===c?"undefined":c.toString()}function f(a,b){for(var c="",d=0;dd;++d)a.disableVertexAttribArray(d),a.vertexAttribPointer(d,4,a.FLOAT,!1,0,0),a.vertexAttrib1f(d,0);a.deleteBuffer(c);for(var e=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),d=0;e>d;++d)a.activeTexture(a.TEXTURE0+d),a.bindTexture(a.TEXTURE_CUBE_MAP,null),a.bindTexture(a.TEXTURE_2D,null);for(a.activeTexture(a.TEXTURE0),a.useProgram(null),a.bindBuffer(a.ARRAY_BUFFER,null),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,null),a.bindFramebuffer(a.FRAMEBUFFER,null),a.bindRenderbuffer(a.RENDERBUFFER,null),a.disable(a.BLEND),a.disable(a.CULL_FACE),a.disable(a.DEPTH_TEST),a.disable(a.DITHER),a.disable(a.SCISSOR_TEST),a.blendColor(0,0,0,0),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ONE,a.ZERO),a.clearColor(0,0,0,0),a.clearDepth(1),a.clearStencil(-1),a.colorMask(!0,!0,!0,!0),a.cullFace(a.BACK),a.depthFunc(a.LESS),a.depthMask(!0),a.depthRange(0,1),a.frontFace(a.CCW),a.hint(a.GENERATE_MIPMAP_HINT,a.DONT_CARE),a.lineWidth(1),a.pixelStorei(a.PACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.pixelStorei(a.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),a.UNPACK_COLORSPACE_CONVERSION_WEBGL&&a.pixelStorei(a.UNPACK_COLORSPACE_CONVERSION_WEBGL,a.BROWSER_DEFAULT_WEBGL),a.polygonOffset(0,0),a.sampleCoverage(1,!1),a.scissor(0,0,a.canvas.width,a.canvas.height),a.stencilFunc(a.ALWAYS,0,4294967295),a.stencilMask(4294967295),a.stencilOp(a.KEEP,a.KEEP,a.KEEP),a.viewport(0,0,a.canvas.width,a.canvas.height),a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT|a.STENCIL_BUFFER_BIT);a.getError(););}function j(a){function b(a){return"function"==typeof a?a:function(b){a.handleEvent(b)}}function c(a){var b=a.addEventListener;a.addEventListener=function(c,d,e){switch(c){case"webglcontextlost":x(d);break;case"webglcontextrestored":y(d);break;default:b.apply(a,arguments)}}}function d(){for(var a=Object.keys(w),b=0;b=0&&setTimeout(function(){a.restoreContext()},v)},0)}},a.restoreContext=function(){q&&o.length&&setTimeout(function(){if(!u)throw"can not restore. webglcontestlost listener did not call event.preventDefault";h(),i(l),q=!1,t=0,u=!1;for(var a=o.slice(),b=j("context restored"),c=0;c0)return!1;if(0===b.length)return!0;for(var c in b)if(a.call(b,c))return!1;return!0},this.reset=function(){var a=[];for(var b in this._engines)this._engines.hasOwnProperty(b)&&(a.push(this._engines[b]),delete this._engines[b],this._engineIds.removeItem(b));for(;a.length>0;)a.pop().destroy();SceneJS_events.fireEvent(SceneJS_events.RESET)}};!function(){var a;SceneJS.on("configs",function(b){if(b.pluginPath!=a){a=b.pluginPath;var c=a+"/lib";require.config({paths:{scenejsPluginDeps:c}})}})}();var SceneJS_eventManager=function(){this._handlerIds=new SceneJS_Map,this.typeHandlers={}};SceneJS_eventManager.prototype.createEvent=function(a){this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0})},SceneJS_eventManager.prototype.onEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0}),d=this._handlerIds.addItem(a),e=c.handlers;return e[d]=b,c.numSubs++,d},SceneJS_eventManager.prototype.fireEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0});if(c.numSubs>0){var d=c.handlers;for(var e in d)d.hasOwnProperty(e)&&d[e](b)}},SceneJS_eventManager.prototype.unEvent=function(a){var b=this._handlerIds.items[a];if(b){this._handlerIds.removeItem(a);var c=this.typeHandlers[b];c&&(delete c[a],this.typeHandlers[b].numSubs--)}},SceneJS.Plugins=new function(){function a(a,c,f,g){var h=d[a]||(d[a]={});h[c]=g,b(f,0,function(){for(var b=a+c,d=e[b]||(e[b]=[]);d.length>0;)d.pop()(g);delete e[b]})}function b(a,d,e){if(!a||d>=a.length)return void e();var f=a[d],g=SceneJS_configsModule.configs.pluginPath;if(!g)throw"no pluginPath config";f=g+"/"+f,c(f,function(){b(a,d+1,e)})}function c(a,b){var c=document.createElement("script");c.type="text/javascript",c.readyState?c.onreadystatechange=function(){("loaded"==c.readyState||"complete"==c.readyState)&&(c.onreadystatechange=null,b&&b())}:c.onload=function(){b&&b()},c.src=a,document.getElementsByTagName("head")[0].appendChild(c)}var d={},e={};this.addPlugin=function(){var b,c,d=arguments[0],e=arguments[1];4==arguments.length?(b=arguments[2],c=arguments[3]):c=arguments[2],a(d,e,b,c)},this.hasPlugin=function(a,b){var c=d[a];return c&&!!c[b]},this.getPlugin=function(a,b,f){var g=d[a];if(g){var h=g[b];if(h)return void f(h)}var i=a+b,j=e[i]||(e[i]=[]);if(j.push(f),!(j.length>1)){var k=SceneJS_configsModule.configs.pluginPath;if(!k)throw"no pluginPath config";var l=k+"/"+a+"/"+b+".js";c(l)}}};var SceneJS_events=new function(){this.ERROR=0,this.RESET=1,this.NODE_CREATED=2,this.SCENE_CREATED=3,this.SCENE_COMPILING=4,this.SCENE_DESTROYED=5,this.OBJECT_COMPILING=6,this.WEBGL_CONTEXT_LOST=7,this.WEBGL_CONTEXT_RESTORED=8;var a=[];this.addListener=function(b,c,d){var e=a[b];e||(e=[],a[b]=e);for(var f={command:c,priority:void 0==d?e.length:d},g=-1,h=0,i=e.length;i>h;h++)if(!e[h]){g=h;break}0>g&&(e.push(f),g=e.length-1);var j=b+"."+g;return j},this.removeListener=function(b){var c=b.lastIndexOf("."),d=parseInt(b.substr(0,c)),e=parseInt(b.substr(c+1)),f=a[d];f&&delete f[e]},this.fireEvent=function(b,c){var d=a[b];if(d){c=c||{};for(var e=0;e',e.appendChild(f)}var h=document.getElementById(b);if(!h)throw SceneJS_error.fatalError(SceneJS.errors.CANVAS_NOT_FOUND,"SceneJS.Scene attribute 'canvasId' does not match any elements in the page");this.canvasId=b,this.options=d||{},this.canvas=this.options.simulateWebGLContextLost?WebGLDebugUtils.makeLostContextSimulatingCanvas(h):h,this.ssaaMultiplier=this.options.ssaaMultiplier||1,this.canvas.width=this.canvas.clientWidth*this.ssaaMultiplier,this.canvas.height=this.canvas.clientHeight*this.ssaaMultiplier,this.contextAttr=c,this.gl=null,this.initWebGL()};SceneJS_Canvas.prototype._WEBGL_CONTEXT_NAMES=["webgl","experimental-webgl","webkit-3d","moz-webgl","moz-glweb20"],SceneJS_Canvas.prototype.initWebGL=function(){for(var a=0;!this.gl&&af;f++)d.createNode(a.nodes[f],function(a){c.addNode(a),++e==g&&(b&&b(c),d.scene.publish("nodes/"+c.id,c))});else b&&(b(c),d.scene.publish("nodes/"+c.id,c))})},SceneJS_Engine.prototype._doDestroyNodes=function(){for(var a;this._numNodesToDestroy>0;)a=this._nodesToDestroy[--this._numNodesToDestroy],a._doDestroy(),this._coreFactory.putCore(a._core),this._nodeFactory.putNode(a)},SceneJS_Engine.prototype.findNode=function(a){return this._nodeFactory.nodes.items[a]},SceneJS_Engine.prototype.findNodes=function(a){var b=new RegExp(a),c=[],d=this._nodeFactory.nodes.items;for(var e in d)d.hasOwnProperty(e)&&b.test(e)&&c.push(d[e]);return c},SceneJS_Engine.prototype.hasCore=function(a,b){return this._coreFactory.hasCore(a,b)},SceneJS_Engine.prototype.branchDirty=function(a){if(!this.sceneDirty&&a!=window){a.branchDirty=!0,a.dirty=!0;for(var b=a.parent;b&&!b.dirty&&!b.branchDirty;b=b.parent)b.dirty=!0;this._sceneBranchesDirty=!0}},SceneJS_Engine.prototype.renderFrame=function(a){var b=!1;if(this._needCompile()||a&&a.force)for(var c=(new Date).getTime(),d=a&&a.force,e=0;e0?setTimeout(window[e],1e3/d.fps):requestAnimationFrame(window[e]))},setTimeout(window[e],0)}},SceneJS_Engine.prototype.pick=function(a,b,c){this._needCompile()&&this._doCompile();var d=this.display.pick({canvasX:a,canvasY:b,rayPick:c?c.rayPick:!1});return d},SceneJS_Engine.prototype.readPixels=function(a,b){return this._needCompile()&&this._doCompile(),this.display.readPixels(a,b)},SceneJS_Engine.prototype._needCompile=function(){return this.display.imageDirty||this.display.drawListDirty||this.display.stateSortDirty||this.display.stateOrderDirty||this.display.objectListDirty||this._sceneBranchesDirty||this.sceneDirty},SceneJS_Engine.prototype._doCompile=function(){if(this._sceneBranchesDirty||this.sceneDirty){this._sceneBranchesDirty=!1,SceneJS_events.fireEvent(SceneJS_events.SCENE_COMPILING,{engine:this}),this.pubSubProxy=new SceneJS_PubSubProxy(this.scene,null);var a={pubSubProxy:this.pubSubProxy};this.scene._compileNodes(a),this.sceneDirty=!1}this._doDestroyNodes()},SceneJS_Engine.prototype.pause=function(a){this.paused=a},SceneJS_Engine.prototype.stop=function(){this.running&&(this.running=!1,this.paused=!1,window["__scenejs_sceneLoop"+this.id]=null)},SceneJS_Engine.prototype.destroyNode=function(a){this._nodesToDestroy[this._numNodesToDestroy++]=a;var b=this.sceneStatus.nodes[a.id];b&&(this.sceneStatus.numTasks-=b.numTasks,delete this.sceneStatus.nodes[a.id])},SceneJS_Engine.prototype.destroy=function(){this.destroyed=!0},self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array),function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;ch;h++)i[h](g);SceneJS.publish("configs",this.configs)},this.getConfigs=function(a){if(a){for(var b=this.configs,c=a.split("."),d=0;b&&dc;c++)b.push("----");e=b.join("")},this.error=function(a){this._log("error",a)},this.warn=function(a){this._log("warn",a)},this.info=function(a){this._log("info",a)},this.debug=function(a){this._log("debug",a)},this.setFuncs=function(a){if(a){b=a;for(var d in c)this._flush(d)}},this._flush=function(a){var d=c[a];if(d){var e=b?b[a]:null;if(e){for(var f=0;fy;++y)f=b[y],c=f[0],d=f[1],e=f[2],g[y]=[i*c+m*d+q*e+u,j*c+n*d+r*e+v,k*c+o*d+s*e+w,l*c+p*d+t*e+x];return g},SceneJS_math_transformVector3=function(a,b){var c=b[0],d=b[1],e=b[2];return[a[0]*c+a[4]*d+a[8]*e,a[1]*c+a[5]*d+a[9]*e,a[2]*c+a[6]*d+a[10]*e]},SceneJS_math_transformVector4=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3];return[a[0]*c+a[4]*d+a[8]*e+a[12]*f,a[1]*c+a[5]*d+a[9]*e+a[13]*f,a[2]*c+a[6]*d+a[10]*e+a[14]*f,a[3]*c+a[7]*d+a[11]*e+a[15]*f]},SceneJS_math_projectVec4=function(a){var b=1/a[3];return[a[0]*b,a[1]*b,a[2]*b,1]},SceneJS_math_Plane3=function(a,b,c){if(this.normal=[0,0,1],this.offset=0,a&&b){var d=a[0],e=a[1],f=a[2];if(this.offset=b,c){var g=Math.sqrt(d*d+e*e+f*f);g>0&&(g=1/g,this.normal[0]=d*g,this.normal[1]=e*g,this.normal[2]=f*g,this.offset*=g)}}},SceneJS_math_MAX_DOUBLE=Number.POSITIVE_INFINITY,SceneJS_math_MIN_DOUBLE=Number.NEGATIVE_INFINITY,SceneJS_math_Box3=function(a,b){this.min=a||[SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE],this.max=b||[SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE],this.init=function(a,b){return this.min[0]=a[0],this.min[1]=a[1],this.min[2]=a[2],this.max[0]=b[0],this.max[1]=b[1],this.max[2]=b[2],this},this.fromPoints=function(a){for(var b=a.length,c=0;b>c;++c){var d=a[c][3],e=a[c][0]/d,f=a[c][1]/d,g=a[c][2]/d;ethis.max[0]&&(this.max[0]=e),f>this.max[1]&&(this.max[1]=f),g>this.max[2]&&(this.max[2]=g)}return this},this.isEmpty=function(){return this.min[0]>=this.max[0]&&this.min[1]>=this.max[1]&&this.min[2]>=this.max[2]},this.getCenter=function(){return[(this.max[0]+this.min[0])/2,(this.max[1]+this.min[1])/2,(this.max[2]+this.min[2])/2]},this.getSize=function(){return[this.max[0]-this.min[0],this.max[1]-this.min[1],this.max[2]-this.min[2]]},this.getFacesAreas=function(){var a=this.size;return[a[1]*a[2],a[0]*a[2],a[0]*a[1]]},this.getSurfaceArea=function(){var a=this.getFacesAreas();return 2*(a[0]+a[1]+a[2])},this.getVolume=function(){var a=this.size;return a[0]*a[1]*a[2]},this.getOffset=function(a){return this.min[0]-=a,this.min[1]-=a,this.min[2]-=a,this.max[0]+=a,this.max[1]+=a,this.max[2]+=a,this}},SceneJS_math_AxisBox3=function(a,b){var c=a[0],d=a[1],e=a[2],f=b[0],g=b[1],h=b[2];this.verts=[[c,d,e],[f,d,e],[f,g,e],[c,g,e],[c,d,h],[f,d,h],[f,g,h],[c,g,h]],this.toBox3=function(){for(var a=new SceneJS_math_Box3,b=0;8>b;++b)for(var c=this.verts[b],d=0;3>d;++d)c[d]a.max[d]&&(a.max[d]=c[d])}},SceneJS_math_Sphere3=function(a,b){this.center=[a[0],a[1],a[2]],this.radius=b,this.isEmpty=function(){return 0===this.radius},this.surfaceArea=function(){return 4*Math.PI*this.radius*this.radius},this.getVolume=function(){var a=this.radius;return 4/3*Math.PI*a*a*a}},SceneJS_math_billboardMat=function(a){var b=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],c=[SceneJS_math_lenVec4(b[0]),SceneJS_math_lenVec4(b[1]),SceneJS_math_lenVec4(b[2])],d=SceneJS_math_mat4();SceneJS_math_rcpVec3(c,d);var e=SceneJS_math_scalingMat4v(c);SceneJS_math_mulVec4Scalar(b[0],d[0]),SceneJS_math_mulVec4Scalar(b[1],d[1]),SceneJS_math_mulVec4Scalar(b[2],d[2]);var f=SceneJS_math_identityMat4();return SceneJS_math_setRowMat4(f,0,b[0]),SceneJS_math_setRowMat4(f,1,b[1]),SceneJS_math_setRowMat4(f,2,b[2]),SceneJS_math_mulMat4(f,e)},SceneJS_math_FrustumPlane=function(a,b,c,d){var e=1/Math.sqrt(a*a+b*b+c*c);this.normal=[a*e,b*e,c*e],this.offset=d*e,this.testVertex=[this.normal[0]>=0?1:0,this.normal[1]>=0?1:0,this.normal[2]>=0?1:0]},SceneJS_math_OUTSIDE_FRUSTUM=3,SceneJS_math_INTERSECT_FRUSTUM=4,SceneJS_math_INSIDE_FRUSTUM=5,SceneJS_math_Frustum=function(a,b,c){var d=SceneJS_math_mat4();SceneJS_math_mulMat4(b,a,d);var e=d[0],f=d[1],g=d[2],h=d[3],i=d[4],j=d[5],k=d[6],l=d[7],m=d[8],n=d[9],o=d[10],p=d[11],q=d[12],r=d[13],s=d[14],t=d[15],u=[new SceneJS_math_FrustumPlane(h-e,l-i,p-m,t-q),new SceneJS_math_FrustumPlane(h+e,l+i,p+m,t+q),new SceneJS_math_FrustumPlane(h-f,l-j,p-n,t-r),new SceneJS_math_FrustumPlane(h+f,l+j,p+n,t+r),new SceneJS_math_FrustumPlane(h-g,l-k,p-o,t-s),new SceneJS_math_FrustumPlane(h+g,l+k,p+o,t+s)],v=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],w=[SceneJS_math_lenVec4(v[0]),SceneJS_math_lenVec4(v[1]),SceneJS_math_lenVec4(v[2])],x=SceneJS_math_rcpVec3(w),y=SceneJS_math_scalingMat4v(w),z=SceneJS_math_scalingMat4v(x);SceneJS_math_mulVec4Scalar(v[0],x[0]),SceneJS_math_mulVec4Scalar(v[1],x[1]),SceneJS_math_mulVec4Scalar(v[2],x[2]);var A=SceneJS_math_identityMat4();SceneJS_math_setRowMat4(A,0,v[0]),SceneJS_math_setRowMat4(A,1,v[1]),SceneJS_math_setRowMat4(A,2,v[2]),this.matrix||(this.matrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(b,a,this.matrix),this.billboardMatrix||(this.billboardMatrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(z,SceneJS_math_mulMat4(A,y),this.billboardMatrix),this.viewport=c.slice(0,4),this.textAxisBoxIntersection=function(a){for(var b=SceneJS_math_INSIDE_FRUSTUM,c=[a.min,a.max],d=null,e=0;6>e;++e){if(d=u[e],d.normal[0]*c[d.testVertex[0]][0]+d.normal[1]*c[d.testVertex[1]][1]+d.normal[2]*c[d.testVertex[2]][2]+d.offset<0)return SceneJS_math_OUTSIDE_FRUSTUM;d.normal[0]*c[1-d.testVertex[0]][0]+d.normal[1]*c[1-d.testVertex[1]][1]+d.normal[2]*c[1-d.testVertex[2]][2]+d.offset<0&&(b=SceneJS_math_INTERSECT_FRUSTUM)}return b},this.getProjectedSize=function(a){var b=SceneJS_math_mat4();SceneJS_math_subVec3(a.max,a.min,b);var d=SceneJS_math_lenVec3(b),e=Math.abs(d),f=[.5*(a.min[0]+a.max[0]),.5*(a.min[1]+a.max[1]),.5*(a.min[2]+a.max[2]),0],g=.5*e,h=[-g,0,0,1],i=[g,0,0,1];return h=SceneJS_math_mulMat4v4(this.billboardMatrix,h),h=SceneJS_math_addVec4(h,f),h=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,h)),i=SceneJS_math_mulMat4v4(this.billboardMatrix,i),i=SceneJS_math_addVec4(i,f),i=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,i)),c[2]*Math.abs(i[0]-h[0])},this.getProjectedState=function(a){for(var b,d,e,f=SceneJS_math_transformPoints3(this.matrix,a),g=1e7,h=1e7,i=-1e7,j=-1e7,k=f.length,l=0;k>l;++l)b=SceneJS_math_projectVec4(f[l]),d=b[0],e=b[1],-.5>d&&(d=-.5),-.5>e&&(e=-.5),d>.5&&(d=.5),e>.5&&(e=.5),g>d&&(g=d),h>e&&(h=e),d>i&&(i=d),e>j&&(j=e);g+=.5,h+=.5,i+=.5,j+=.5;var m=c[2],n=c[3];g*=m+15,h*=n+15,i*=m+15,j*=n+15;var o=SceneJS_math_mat4();SceneJS_math_subVec2([i,j],[g,h],o);var p=SceneJS_math_lenVec2(o);return 0>g&&(g=0),i>m&&(i=m),0>h&&(h=0),j>n&&(j=n),{canvasBox:{min:[g,h],max:[i,j]},canvasSize:p}}},SceneJS_math_identityQuaternion=function(){return[0,0,0,1]},SceneJS_math_angleAxisQuaternion=function(a,b,c,d){var e=d/180*Math.PI,f=e/2,g=Math.sin(f);return[g*a,g*b,g*c,Math.cos(f)]},SceneJS_math_mulQuaternions=function(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=b[0],h=b[1],i=b[2],j=b[3];return[f*g+c*j+d*i-e*h,f*h+d*j+e*g-c*i,f*i+e*j+c*h-d*g,f*j-c*g-d*h-e*i]},SceneJS_math_newMat4FromQuaternion=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=2*b,g=2*c,h=2*d,i=f*e,j=g*e,k=h*e,l=f*b,m=g*b,n=h*b,o=g*c,p=h*c,q=h*d,r=SceneJS_math_identityMat4();return SceneJS_math_setCellMat4(r,0,0,1-(o+q)),SceneJS_math_setCellMat4(r,0,1,m-k),SceneJS_math_setCellMat4(r,0,2,n+j),SceneJS_math_setCellMat4(r,1,0,m+k),SceneJS_math_setCellMat4(r,1,1,1-(l+q)),SceneJS_math_setCellMat4(r,1,2,p-i),SceneJS_math_setCellMat4(r,2,0,n-j),SceneJS_math_setCellMat4(r,2,1,p+i),SceneJS_math_setCellMat4(r,2,2,1-(l+o)),r},SceneJS_math_slerp=function(a,b,c){var d=.0174532925*b[3],e=.0174532925*c[3],f=d*e+b[0]*c[0]+b[1]*c[1]+b[2]*c[2];if(Math.abs(f)>=1)return[b[0],b[1],b[2],b[3]];var g=Math.acos(f),h=Math.sqrt(1-f*f);if(Math.abs(h)<.001)return[.5*b[0]+.5*c[0],.5*b[1]+.5*c[1],.5*b[2]+.5*c[2],.5*b[3]+.5*c[3]];var i=Math.sin((1-a)*g)/h,j=Math.sin(a*g)/h;return[b[0]*i+c[0]*j,b[1]*i+c[1]*j,b[2]*i+c[2]*j,57.295779579*(d*i+e*j)]},SceneJS_math_normalizeQuaternion=function(a){var b=SceneJS_math_lenVec4([a[0],a[1],a[2],a[3]]);return[a[0]/b,a[1]/b,a[2]/b,a[3]/b]},SceneJS_math_conjugateQuaternion=function(a){return[-a[0],-a[1],-a[2],a[3]]},SceneJS_math_angleAxisFromQuaternion=function(a){a=SceneJS_math_normalizeQuaternion(a);var b=a[3],c=2*Math.acos(b),d=Math.sqrt(1-b*b);return.001>d?{x:a[0],y:a[1],z:a[2],angle:57.295779579*c}:{x:a[0]/d,y:a[1]/d,z:a[2]/d,angle:57.295779579*c}},SceneJS_sceneStatusModule=new function(){function a(a){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d=c.style;return d.position="absolute",d.width="200px",d.right="10px",d.top="0",d.padding="10px",d["z-index"]="10000",b.appendChild(c),c}function b(a,b){var c=document.createElement("div"),d=c.style;return d["font-family"]="Helvetica",d["font-size"]="14px",d.padding="5px",d.margin="4px",d["padding-left"]="12px",d.border="1px solid #000055",d.color="black",d.background="#AAAAAA",d.opacity="0.8",d["border-radius"]="3px",d["-moz-border-radius"]="3px",d["box-shadow"]="3px 3px 3px #444444",c.innerHTML=b,a.appendChild(c),c}function c(a){a.style.background="#AAFFAA";var b=.8,c=setInterval(function(){0>=b?(a.parentNode.removeChild(a),clearInterval(c)):(a.style.opacity=b,b-=.1)},100)}function d(a){a.style.background="#FFAAAA"}this.sceneStatus={};var e=new SceneJS_Map,f={},g={},h=this;SceneJS_events.addListener(SceneJS_events.SCENE_DESTROYED,function(a){var b=a.engine.id;delete h.sceneStatus[b],delete g[b]}),this.taskStarted=function(c,d){var h=SceneJS_configsModule.configs.statusPopups!==!1,i=c.getScene(),j=i.getId(),k=c.getId(),l=i.getCanvas(),m=e.addItem(),n=this.sceneStatus[j];n||(n=this.sceneStatus[j]={numTasks:0}),n.numTasks++;var o=g[j];o||(o=g[j]={sceneId:j,nodeStates:{},scene:i,popupContainer:h?a(l):null,descCounts:{}});var p=o.descCounts[d];void 0==p&&(p=o.descCounts[d]=0),o.descCounts[d]++;var q=o.nodeStates[k];q||(q=o.nodeStates[k]={nodeId:k,numTasks:0,tasks:{}}),d=d+" "+o.descCounts[d]+"...",q.numTasks++;var r={sceneState:o,nodeState:q,description:d,element:h?b(o.popupContainer,d):null};return q.tasks[m]=r,f[m]=r,m},this.taskFinished=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var d=b.sceneState;this.sceneStatus[d.sceneId].numTasks--,b.element&&c(b.element);var e=b.nodeState;return--e.numTasks<0&&(e.numTasks=0),delete e.tasks[a],0==e.numTasks&&delete d.nodeStates[e.nodeId],null},this.taskFailed=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var c=!!SceneJS_configsModule.configs.statusPopups,e=b.sceneState;this.sceneStatus[e.sceneId].numTasks--,c&&d(b.element);var g=b.nodeState;return g.numTasks--,delete g.tasks[a],0==g.numTasks&&delete b.sceneState.nodeStates[g.nodeId],null}};SceneJS._webgl={},SceneJS._webgl.ArrayBuffer=function(a,b,c,d,e,f){this.allocated=!1,this.gl=a,this.type=b, +this.numItems=d,this.itemSize=e,this.usage=f,this._allocate(c,d)},SceneJS._webgl.ArrayBuffer.prototype._allocate=function(a,b){if(this.allocated=!1,this.handle=this.gl.createBuffer(),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to allocate WebGL ArrayBuffer");this.handle&&(this.gl.bindBuffer(this.type,this.handle),this.gl.bufferData(this.type,a,this.usage),this.gl.bindBuffer(this.type,null),this.numItems=b,this.length=a.length,this.allocated=!0)},SceneJS._webgl.ArrayBuffer.prototype.setData=function(a,b){this.allocated&&(a.length>this.length?(this.destroy(),this._allocate(a,a.length)):b||0===b?this.gl.bufferSubData(this.type,b,a):this.gl.bufferData(this.type,a))},SceneJS._webgl.ArrayBuffer.prototype.unbind=function(){this.allocated&&this.gl.bindBuffer(this.type,null)},SceneJS._webgl.ArrayBuffer.prototype.destroy=function(){this.allocated&&(this.gl.deleteBuffer(this.handle),this.handle=null,this.allocated=!1)},SceneJS._webgl.ArrayBuffer.prototype.bind=function(){this.allocated&&this.gl.bindBuffer(this.type,this.handle)},SceneJS._webgl.Attribute=function(a,b,c,d,e,f){this.gl=a,this.location=f,this.bindFloatArrayBuffer=function(b){b&&(b.bind(),a.enableVertexAttribArray(f),a.vertexAttribPointer(f,b.itemSize,a.FLOAT,!1,0,0))}},SceneJS._webgl.Attribute.prototype.bindInterleavedFloatArrayBuffer=function(a,b,c){this.gl.enableVertexAttribArray(this.location),this.gl.vertexAttribPointer(this.location,a,this.gl.FLOAT,!1,b,c)},SceneJS._webgl.enumMap={funcAdd:"FUNC_ADD",funcSubtract:"FUNC_SUBTRACT",funcReverseSubtract:"FUNC_REVERSE_SUBTRACT",zero:"ZERO",one:"ONE",srcColor:"SRC_COLOR",oneMinusSrcColor:"ONE_MINUS_SRC_COLOR",dstColor:"DST_COLOR",oneMinusDstColor:"ONE_MINUS_DST_COLOR",srcAlpha:"SRC_ALPHA",oneMinusSrcAlpha:"ONE_MINUS_SRC_ALPHA",dstAlpha:"DST_ALPHA",oneMinusDstAlpha:"ONE_MINUS_DST_ALPHA",contantColor:"CONSTANT_COLOR",oneMinusConstantColor:"ONE_MINUS_CONSTANT_COLOR",constantAlpha:"CONSTANT_ALPHA",oneMinusConstantAlpha:"ONE_MINUS_CONSTANT_ALPHA",srcAlphaSaturate:"SRC_ALPHA_SATURATE",front:"FRONT",back:"BACK",frontAndBack:"FRONT_AND_BACK",never:"NEVER",less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL",always:"ALWAYS",cw:"CW",ccw:"CCW",linear:"LINEAR",nearest:"NEAREST",linearMipMapNearest:"LINEAR_MIPMAP_NEAREST",nearestMipMapNearest:"NEAREST_MIPMAP_NEAREST",nearestMipMapLinear:"NEAREST_MIPMAP_LINEAR",linearMipMapLinear:"LINEAR_MIPMAP_LINEAR",repeat:"REPEAT",clampToEdge:"CLAMP_TO_EDGE",mirroredRepeat:"MIRRORED_REPEAT",alpha:"ALPHA",rgb:"RGB",rgba:"RGBA",luminance:"LUMINANCE",luminanceAlpha:"LUMINANCE_ALPHA",textureBinding2D:"TEXTURE_BINDING_2D",textureBindingCubeMap:"TEXTURE_BINDING_CUBE_MAP",compareRToTexture:"COMPARE_R_TO_TEXTURE",unsignedByte:"UNSIGNED_BYTE"},SceneJS._webgl.RenderBuffer=function(a){this.allocated=!1,this.canvas=a.canvas,this.gl=a.canvas.gl,this.buf=null,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.webglRestored=function(a){this.gl=a,this.buf=null,this.allocated=!1,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.bind=function(){this._touch(),this.bound||(this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.bound=!0)},SceneJS._webgl.RenderBuffer.prototype._touch=function(){var a=this.canvas.canvas.width,b=this.canvas.canvas.height;if(this.buf){if(this.buf.width==a&&this.buf.height==b)return;this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf)}this.buf={framebuf:this.gl.createFramebuffer(),renderbuf:this.gl.createRenderbuffer(),texture:this.gl.createTexture(),width:a,height:b},this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.gl.bindTexture(this.gl.TEXTURE_2D,this.buf.texture),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE);try{this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,null)}catch(c){var d=new WebGLUnsignedByteArray(a*b*3);this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,d)}if(this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.DEPTH_COMPONENT16,a,b),this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER,this.gl.COLOR_ATTACHMENT0,this.gl.TEXTURE_2D,this.buf.texture,0),this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER,this.gl.DEPTH_ATTACHMENT,this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.bindTexture(this.gl.TEXTURE_2D,null),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),!this.gl.isFramebuffer(this.buf.framebuf))throw SceneJS_error.fatalError(SceneJS.errors.INVALID_FRAMEBUFFER,"Invalid framebuffer");var e=this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);switch(e){case this.gl.FRAMEBUFFER_COMPLETE:break;case this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");case this.gl.FRAMEBUFFER_UNSUPPORTED:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");default:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: "+e)}this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.clear=function(){if(!this.bound)throw"Render buffer not bound";this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT),this.gl.disable(this.gl.BLEND)},SceneJS._webgl.RenderBuffer.prototype.read=function(a,b){var c=a,d=this.canvas.canvas.height-b,e=new Uint8Array(4);return this.gl.readPixels(c,d,1,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),e},SceneJS._webgl.RenderBuffer.prototype.unbind=function(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.getTexture=function(){var a=this;return{bind:function(b){return a.buf&&a.buf.texture?(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,a.buf.texture),!0):!1},unbind:function(b){a.buf&&a.buf.texture&&(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,null))}}},SceneJS._webgl.RenderBuffer.prototype.destroy=function(){this.buf&&(this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf),this.buf=null,this.bound=!1)},SceneJS._webgl.Program=function(a,b,c){this.allocated=!1,this.gl=a,this._uniforms={},this._samplers={},this._attributes={},this.uniformValues=[],this.materialSettings={specularColor:[0,0,0],specular:0,shine:0,emit:0,alpha:0},this._shaders=[];var d,e,f,g,h,i;for(e=0;ee;++e)f=a.getActiveUniform(this.handle,e),f&&(g=f.name,"\x00"==g[g.length-1]&&(g=g.substr(0,g.length-1)),h=a.getUniformLocation(this.handle,g),f.type==a.SAMPLER_2D||f.type==a.SAMPLER_CUBE||35682==f.type?this._samplers[g]=new SceneJS._webgl.Sampler(a,this.handle,g,f.type,f.size,h):(this._uniforms[g]=new SceneJS._webgl.Uniform(a,this.handle,g,f.type,f.size,h,k),this.uniformValues[k]=null,++k));var l=a.getProgramParameter(this.handle,a.ACTIVE_ATTRIBUTES);for(e=0;l>e;e++)d=a.getActiveAttrib(this.handle,e),d&&(h=a.getAttribLocation(this.handle,d.name),this._attributes[d.name]=new SceneJS._webgl.Attribute(a,this.handle,d.name,d.type,d.size,h));this.allocated=!0}},SceneJS._webgl.Program.prototype.bind=function(){this.allocated&&this.gl.useProgram(this.handle)},SceneJS._webgl.Program.prototype.getUniformLocation=function(a){if(this.allocated){var b=this._uniforms[a];return b?b.getLocation():void 0}},SceneJS._webgl.Program.prototype.getUniform=function(a){if(this.allocated){var b=this._uniforms[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.getAttribute=function(a){if(this.allocated){var b=this._attributes[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.bindFloatArrayBuffer=function(a,b){if(this.allocated){var c=this._attributes[a];c&&c.bindFloatArrayBuffer(b)}},SceneJS._webgl.Program.prototype.bindTexture=function(a,b,c){if(!this.allocated)return!1;var d=this._samplers[a];return d?d.bindTexture(b,c):!1},SceneJS._webgl.Program.prototype.destroy=function(){if(this.allocated){this.gl.deleteProgram(this.handle);for(var a in this._shaders)this.gl.deleteShader(this._shaders[a].handle);this.handle=null,this._attributes=null,this._uniforms=null,this._samplers=null,this.allocated=!1}},SceneJS._webgl.Program.prototype.setUniform=function(a,b){if(this.allocated){var c=this._uniforms[a];c&&(this.uniformValues[c.index]===b&&c.numberValue||(c.setValue(b),this.uniformValues[c.index]=b))}},SceneJS._webgl.Sampler=function(a,b,c,d,e,f){this.bindTexture=function(b,c){return b.bind(c)?(a.uniform1i(f,c),!0):!1}},SceneJS._webgl.Shader=function(a,b,c){if(this.allocated=!1,this.handle=a.createShader(b),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to create WebGL shader");if(a.shaderSource(this.handle,c),a.compileShader(this.handle),this.valid=0!=a.getShaderParameter(this.handle,a.COMPILE_STATUS),!this.valid&&!a.isContextLost()){SceneJS.log.error("Shader program failed to compile: "+a.getShaderInfoLog(this.handle)),SceneJS.log.error("Shader source:");for(var d=c.split("\n"),e=0;eb){var d=b/c,e=a.width*d,f=a.height*d,g=document.createElement("canvas");g.width=SceneJS._webgl.nextHighestPowerOfTwo(e),g.height=SceneJS._webgl.nextHighestPowerOfTwo(f);var h=g.getContext("2d");h.drawImage(a,0,0,a.width,a.height,0,0,g.width,g.height),a=g}return a},SceneJS._webgl.ensureImageSizePowerOfTwo=function(a){if(!SceneJS._webgl.isPowerOfTwo(a.width)||!SceneJS._webgl.isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=SceneJS._webgl.nextHighestPowerOfTwo(a.width),b.height=SceneJS._webgl.nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b}return a},SceneJS._webgl.isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS._webgl.nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS._webgl.Uniform=function(a,b,c,d,e,f,g,h){var i=null,j=null;if(d===a.BOOL)i=function(b){j!==b&&(j=b,a.uniform1i(f,b))};else if(d===a.BOOL_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.BOOL_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.BOOL_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.INT)i=function(b){j!==b&&(j=b,a.uniform1iv(f,b))};else if(d===a.INT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.INT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.INT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.FLOAT)i=function(b){j!==b&&(j=b,a.uniform1f(f,b))};else if(d===a.FLOAT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2fv(f,b))};else if(d===a.FLOAT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3fv(f,b))};else if(d===a.FLOAT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4fv(f,b))};else if(d===a.FLOAT_MAT2)i=function(b){a.uniformMatrix2fv(f,a.FALSE,b)};else if(d===a.FLOAT_MAT3)i=function(b){a.uniformMatrix3fv(f,a.FALSE,b)};else{if(d!==a.FLOAT_MAT4)throw"Unsupported shader uniform type: "+d;i=function(b){a.uniformMatrix4fv(f,a.FALSE,b)}}this.setValue=i,this.getLocation=function(){return f},this.index=g};var SceneJS_nodeEventsModule=new function(){var a,b=[],c=[],d=0,e={type:"listeners",stateId:SceneJS._baseStateId++,empty:!0,listeners:[]};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){d=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(d>0){var g={type:"listeners",stateId:b[d-1],listeners:c.slice(0,d)};f.display.renderListeners=g}else f.display.renderListeners=e;a=!1}}),this.preVisitNode=function(e){var f=e._topicSubs.rendered,g=e._topicSubs.worldPos,h=e._topicSubs.viewPos,i=e._topicSubs.cameraPos,j=e._topicSubs.projPos,k=e._topicSubs.canvasPos;(f||g||h||i||j||k)&&(b[d]=e.id,c[d]=function(a){f&&e.publish("rendered",a,!0),g&&e.publish("worldPos",a.getWorldPos()),h&&e.publish("viewPos",a.getViewPos()),i&&e.publish("cameraPos",a.getCameraPos()),j&&e.publish("projPos",a.getProjPos()),k&&e.publish("canvasPos",a.getCanvasPos())},d++,a=!0)},this.postVisitNode=function(c){c.id==b[d-1]&&(d--,a=!0)}},SceneJS_Core=function(a){this.type=a,this.coreId=null,this.stateId=null,this.useCount=0},SceneJS_CoreFactory=function(){this._stateMap=new SceneJS_Map(null,SceneJS._baseStateId),this._cores={}};SceneJS_CoreFactory.coreTypes={},SceneJS_CoreFactory.createCoreType=function(a,b){},SceneJS_CoreFactory.addCoreBuilder=function(a,b){},SceneJS_CoreFactory.coreAliases={rotate:"xform",translate:"xform",scale:"xform",matrix:"xform",xform:"xform"},SceneJS_CoreFactory.prototype.getCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];d||(d=this._cores[a]={});var e;return b&&(e=d[b])?(e.useCount++,e):(e=new SceneJS_Core(a),e.useCount=1,e.stateId=this._stateMap.addItem(e),e.coreId=void 0!=b&&null!=b?b:e.stateId,d[e.coreId]=e,e)},SceneJS_CoreFactory.prototype.hasCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];return d&&d[b]},SceneJS_CoreFactory.prototype.putCore=function(a){if(0!=a.useCount&&--a.useCount<=0){var b=this._cores[a.type];delete b[a.coreId],this._stateMap.removeItem(a.stateId)}},SceneJS_CoreFactory.prototype.webglRestored=function(){var a,b;for(var c in this._cores)if(this._cores.hasOwnProperty(c)&&(a=this._cores[c]))for(var d in a)a.hasOwnProperty(d)&&(b=a[d],b&&b.webglRestored&&b.webglRestored())},SceneJS.Node=function(){},SceneJS.Node.prototype.constructor=SceneJS.Node,SceneJS.Node.prototype._construct=function(a,b,c,d){this._engine=a,this._core=b,this.coreId=b.coreId,this.id=c.id||c.nodeId||d,this.type=c.type||"node",this.data=c.data,this.parent=null,this.nodes=[],this._handleMap=new SceneJS_Map,this._topicSubs={},this._handleTopics={},this._topicPubs={},this._listeners={},this._numListeners=0,this.dirty=!1,this.branchDirty=!1,this._init&&this._init(c)},SceneJS.Node.prototype.taskStarted=function(a){return SceneJS_sceneStatusModule.taskStarted(this,a||"Task")},SceneJS.Node.prototype.taskFinished=function(a){return SceneJS_sceneStatusModule.taskFinished(a)},SceneJS.Node.prototype.taskFailed=function(a){return SceneJS_sceneStatusModule.taskFailed(a)},SceneJS.Node.prototype.log=function(){var a,b;switch(1==arguments.length?(a="info",b=arguments[0]):2==arguments.length&&(a=arguments[0],b=arguments[1]),a){case"warn":b="WARN; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;case"error":b="ERROR; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;default:b="INFO; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b}console[a]?console[a](b):console.log(b)},SceneJS.Node.prototype.publish=function(a,b,c){if(c||(this._topicPubs[a]=b),this._topicSubs[a]){var d=this._topicSubs[a];for(var e in d)d.hasOwnProperty(e)&&d[e].call(this,b)}},SceneJS.Node.prototype.unpublish=function(a){var b=this._topicSubs[a];if(b)for(var c in b)b.hasOwnProperty(c)&&b[c].call(this,null);delete this._topicPubs[a]},SceneJS.Node.prototype.on=function(a,b){var c=this._topicSubs[a];c||(c={},this._topicSubs[a]=c);var d=this._handleMap.addItem();c[d]=b,this._handleTopics[d]=a;var e=this._topicPubs[a];return e&&b.call(this,e),"rendered"==a&&this._engine.branchDirty(this),d},SceneJS.Node.prototype.off=function(a){var b=this._handleTopics[a];if(b){delete this._handleTopics[a];var c=this._topicSubs[b];c&&delete c[a],this._handleMap.removeItem(a),"rendered"==b&&this._engine.branchDirty(this)}},SceneJS.Node.prototype.once=function(a,b){var c=this,d=this.on(a,function(a){c.off(d),b(a)})},SceneJS.Node.prototype.getScene=function(){return this._engine.scene},SceneJS.Node.prototype.getCoreId=function(){return this._core.coreId},SceneJS.Node.prototype.getID=function(){return this.id},SceneJS.Node.prototype.getId=function(){return this.id},SceneJS.Node.prototype.getNodeId=function(){return this.id},SceneJS.Node.prototype.getType=function(){return this.type},SceneJS.Node.prototype.getData=function(){return this.data},SceneJS.Node.prototype.setData=function(a){return this.data=a,this},SceneJS.Node.prototype.getNumNodes=function(){return this.nodes.length},SceneJS.Node.prototype.getNodes=function(){return this.nodes.slice(0)},SceneJS.Node.prototype.getNodeAt=function(a){return 0>a||a>=this.nodes.length?null:this.nodes[a]},SceneJS.Node.prototype.getFirstNode=function(){return 0==this.nodes.length?null:this.nodes[0]},SceneJS.Node.prototype.getLastNode=function(){return 0==this.nodes.length?null:this.nodes[this.nodes.length-1]},SceneJS.Node.prototype.getNode=function(a){for(var b=0;b0?(b[0].parent=null,this._engine.display.objectListDirty=!0,b[0]):null},SceneJS.Node.prototype.disconnect=function(){if(this.parent){for(var a=0;ab;b++)this.nodes[b].parent=null;var c=this.nodes;return this.nodes=[],this._engine.display.objectListDirty=!0,c},SceneJS.Node.prototype.removeNodes=function(){for(var a=this.disconnectNodes(),b=0;ba;a++)d[a].parent=this.parent;for(a=0,b=c.nodes.length;b>a;a++)if(c.nodes[a]===this)return c.nodes.splice.apply(c.nodes,[a,1].concat(d)),this.nodes=[],this.parent=null,this.destroy(),this._engine.branchDirty(c),c},SceneJS.Node.prototype.addNodes=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNodes - nodes argument is undefined");for(var c,d=[],e=a.length,f=a.length-1;f>=0;f--){var g=a[f];if("node"==g.type||this._engine.hasNodeType(g.type)){if(c=this.addNode(g),d[f]=c,0==--e)return b&&b(a),a}else{var h=this;!function(){var c=f;h.addNode(g,function(f){d[c]=f,0==--e&&b&&b(a)})}()}}return null},SceneJS.Node.prototype.addNode=function(a,b){if(a=a||{},a._compile){if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if("string"==typeof a){var c=this._engine.findNode(a);if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node not found: '"+a+"'");if(a=c,null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if(a.type=a.type||"node","node"==a.type||this._engine.hasNodeType(a.type))return a=this._engine.createNode(a),this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a;var d=this;return this._engine.createNode(a,function(a){d.nodes.push(a),a.parent=d,d._engine.branchDirty(a),b&&b(a)}),null},SceneJS.Node.prototype.insertNode=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is undefined");if(a._compile||(a=this._engine.createNode(a)),!a._compile)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is not a SceneJS.Node");if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is still attached to another parent");if(void 0===b||null===b)a.addNodes(this.disconnectNodes()),this.addNode(a);else{if(0>b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node index out of range: -1");b>=this.nodes.length?this.nodes.push(a):this.nodes.splice(b,0,a)}return a.parent=this,a},SceneJS.Node.prototype.mapNodes=function(a){if(a(this))return this;for(var b,c=0;cg;g++)e=d[g],e.options.scope?e.fn.call(e.options.scope,f):e.fn.call(this,f)}},SceneJS.Node.prototype.removeListener=function(a,b){var c=this._listeners[a];if(!c)return null;for(var d=0;d0},SceneJS.Node.prototype.removeListeners=function(){return this._listeners={},this._numListeners=0,this},SceneJS.Node.prototype.getParent=function(a){return this.parent},SceneJS.Node.prototype.getParentOfType=function(a){for(var b=this.parent;b&&b.type!=a;)b=b.parent;return b},SceneJS.Node.prototype.eachParent=function(a){if(!a)throw"SceneJS.Node.eachParent param 'fn' is null or undefined";for(var b=0,c=this;c.parent;){if(a.call(c.parent,b++)===!0)return c.parent;c=c.parent}return null},SceneJS.Node.prototype.hasNode=function(a){if(null===a||void 0===a)throw"SceneJS.Node.hasNode param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.hasNode param 'node' should be either an index number or an ID string";b=this.getNode(a)}return void 0!=b&&null!=b},SceneJS.Node.prototype.node=function(a){if(null===a||void 0===a)throw"SceneJS.Node.node param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.node param 'node' should be either an index number or an ID string";b=this.getNode(a)}if(!b)throw"SceneJS.Node.node - node not found: '"+a+"'";return b},SceneJS.Node.prototype.eachNode=function(a,b){if(!a)throw"SceneJS.Node.eachNode param 'fn' is null or undefined";if("function"!=typeof a)throw"SceneJS.Node.eachNode param 'fn' should be a function";var c;b=b||{};var d=0;return b.andSelf&&a.call(this,d++)===!0?this:(b.depthFirst||b.breadthFirst?b.depthFirst&&(c=this._iterateEachNodeDepthFirst(a,this,d,!1)):c=this._iterateEachNode(a,this,d),c?c:void 0)},SceneJS.Node.prototype.numNodes=function(){return this.nodes.length},SceneJS.Node.prototype._iterateEachNode=function(a,b,c){for(var d,e=b.nodes.length,f=0;e>f;f++)if(d=b.nodes[f],a.call(d,c++)===!0)return d;return null},SceneJS.Node.prototype._iterateEachNodeDepthFirst=function(a,b,c,d){if(d&&a.call(b,c++)===!0)return b;d=!0;for(var e,f=b.nodes.length,g=0;f>g;g++)if(e=this._iterateEachNodeDepthFirst(a,b.nodes[g],c,d))return e;return null},SceneJS.Node.prototype.findNodesByType=function(a,b){return this._findNodesByType(a,[],b)},SceneJS.Node.prototype._findNodesByType=function(a,b,c){var d;for(d=0;dd;d++)c=this.nodes[d],c.branchDirty=c.branchDirty||this.branchDirty,(c.dirty||c.branchDirty||this._engine.sceneDirty)&&(c._compile(a),c.dirty=!1,c.branchDirty=!1);b&&SceneJS_nodeEventsModule.postVisitNode(this)},SceneJS.Node.prototype.destroy=function(){if(!this.destroyed){if(this.parent)for(var a=0;aa;a++)this.nodes[a]._destroyTree()},SceneJS.Node.prototype._doDestroy=function(){return this._destroy&&this._destroy(),this},SceneJS_PubSubProxy=function(a,b){this.scene=a,this.proxy=b};var SceneJS_NodeFactory=function(){this.nodes=new SceneJS_Map({})};SceneJS_NodeFactory.nodeTypes={},SceneJS_NodeFactory._subs={},SceneJS_NodeFactory.createNodeType=function(a,b,c){if(SceneJS_NodeFactory.nodeTypes[a])throw"Node type already defined: "+a;var d=function(){SceneJS.Node.apply(this,arguments),this.type=a};d.prototype=new SceneJS.Node,d.prototype.constructor=d,SceneJS_NodeFactory.nodeTypes[a]=d;var e=SceneJS_NodeFactory.nodeTypes[a];if(!e)throw"Node type plugin did not install itself correctly";c&&c(d);var f=SceneJS_NodeFactory._subs[a];if(f){for(;f.length>0;)f.pop()(e);delete f[a]}return d},SceneJS_NodeFactory.prototype.getNode=function(a,b,c,d){b.type=b.type||"node";var e;if(e="node"==b.type?SceneJS.Node:SceneJS_NodeFactory.nodeTypes[b.type])return this._createNode(e,a,b,c,d);var f=this;this._getType(a,b.type,function(e){f._createNode(e,a,b,c,d)})},SceneJS_NodeFactory.prototype._createNode=function(a,b,c,d,e){var f=new a,g=c.id||c.nodeId;return g?this.nodes.addItem(g,f):g=this.nodes.addItem(f),f._construct(b,d,c,g),e&&e(f),f},SceneJS_NodeFactory.prototype._getType=function(a,b,c){var d=SceneJS_NodeFactory.nodeTypes[b];if(d)return void c(d);var e=SceneJS_NodeFactory._subs[b]||(SceneJS_NodeFactory._subs[b]=[]);if(e.push(c),!(e.length>1)){var f=SceneJS_sceneStatusModule.taskStarted(a.scene,"Loading plugin");e.push(function(){SceneJS_sceneStatusModule.taskFinished(f)});var g=SceneJS_configsModule.configs.pluginPath; +if(!g)throw"no typePath config";this._loadScript(g+"/node/"+b+".js",function(){SceneJS_sceneStatusModule.taskFailed(f)})}},SceneJS_NodeFactory.prototype._loadScript=function(a,b){var c=document.createElement("script");c.type="text/javascript",c.src=a,c.onerror=b,document.getElementsByTagName("head")[0].appendChild(c)},SceneJS_NodeFactory.prototype.putNode=function(a){this.nodes.removeItem(a.id)},function(){function a(a){var b=a.optics;if("ortho"==b.type?a.matrix=SceneJS_math_orthoMat4c(b.left,b.right,b.bottom,b.top,b.near,b.far):"frustum"==b.type?a.matrix=SceneJS_math_frustumMatrix4(b.left,b.right,b.bottom,b.top,b.near,b.far):"perspective"==b.type&&(a.matrix=SceneJS_math_perspectiveMatrix4(b.fovy*Math.PI/180,b.aspect,b.near,b.far)),a.pan){var c=a.pan,d=SceneJS_math_translationMat4v([c.x||0,c.y||0,c.z||0]);a.matrix=SceneJS_math_mulMat4(d,a.matrix,[])}a.mat?a.mat.set(a.matrix):a.mat=new Float32Array(a.matrix)}var b=SceneJS_math_perspectiveMatrix4(45,1,.1,1e4),c=new Float32Array(b),d={type:"camera",stateId:SceneJS._baseStateId++,matrix:b,mat:c,optics:{type:"perspective",fovy:45,aspect:1,near:.1,far:1e4},checkAspect:function(b,c){b.optics.aspect!=c&&(b.optics.aspect=c,a(this))}},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.projTransform=d,f=0}),SceneJS.Camera=SceneJS_NodeFactory.createNodeType("camera"),SceneJS.Camera.prototype._init=function(b){if(1==this._core.useCount){b.optics=b.optics||{};var c=this.getScene().getCanvas();b.optics.aspect=c.width/c.height,this.setOptics(b.optics),b.pan&&this.setPan(b.pan);var d=this;this._canvasSizeSub=this.getScene().on("canvasSize",function(b){d._core.optics.aspect=b.aspect,a(d._core),d._engine.display.imageDirty=!0})}},SceneJS.Camera.getDefaultMatrix=function(){return c},SceneJS.Camera.prototype.setOptics=function(b){var c=this._core;if(b){var d=b.type||c.optics.type||"perspective";if("ortho"==d)c.optics=SceneJS._applyIf(SceneJS_math_ORTHO_OBJ,{type:d,left:b.left,bottom:b.bottom,near:b.near,right:b.right,top:b.top,far:b.far});else if("frustum"==d)c.optics={type:d,left:b.left||-1,bottom:b.bottom||-1,near:b.near||.1,right:b.right||1,top:b.top||1,far:b.far||1e4};else{if("perspective"!=d)throw b.type?SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not supported - supported types are 'perspective', 'frustum' and 'ortho'"):SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not specified - supported types are 'perspective', 'frustum' and 'ortho'");c.optics={type:d,fovy:b.fovy||60,aspect:void 0==b.aspect?1:b.aspect,near:b.near||.1,far:b.far||1e4}}}else c.optics={type:"perspective",fovy:60,aspect:1,near:.1,far:1e4};this._core.optics.pan=b.pan,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.setPan=function(b){this._core.pan=b,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.getOptics=function(){var a={};for(var b in this._core.optics)this._core.optics.hasOwnProperty(b)&&(a[b]=this._core.optics[b]);return a},SceneJS.Camera.prototype.getMatrix=function(){return this._core.matrix.slice(0)},SceneJS.Camera.prototype._compile=function(a){this._engine.display.projTransform=e[f++]=this._core,this._compileNodes(a),this._engine.display.projTransform=--f>0?e[f-1]:d},SceneJS.Camera.prototype._destroy=function(){this.getScene().off(this._canvasSizeSub)}}(),function(){var a={type:"clips",stateId:SceneJS._baseStateId++,empty:!0,hash:"",clips:[]},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.clips=a,c=0}),SceneJS.Clips=SceneJS_NodeFactory.createNodeType("clips"),SceneJS.Clips.prototype._init=function(a){if(1==this._core.useCount){var b=a.clips;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"clips node attribute missing : 'clips'");this._core.clips=this._core.clips||[];for(var c=0,d=b.length;d>c;c++)this._setClip(c,b[c])}},SceneJS.Clips.prototype.setClips=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.clips.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'clips': index out of range ("+this._core.clips.length+" clips defined)");this._setClip(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Clips.prototype._setClip=function(a,b){var c=this._core.clips[a]||(this._core.clips[a]={});c.normalAndDist=[b.x||0,b.y||0,b.z||0,b.dist||0];var d=b.mode||c.mode||"disabled";if("inside"!=d&&"outside"!=d&&"disabled"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'");c.mode=d,this._core.hash=null},SceneJS.Clips.prototype._compile=function(d){this._core.hash||(this._core.hash=this._core.clips.length),this._engine.display.clips=b[c++]=this._core,this._compileNodes(d),this._engine.display.clips=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"enable",enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.enable=a,c=0}),SceneJS.Enable=SceneJS_NodeFactory.createNodeType("enable"),SceneJS.Enable.prototype._init=function(a){1==this._core.useCount&&(this._core.enabled=!0,void 0!=a.enabled&&this.setEnabled(a.enabled))},SceneJS.Enable.prototype.setEnabled=function(a){return a!==this._core.enabled&&(this._core.enabled=a,this._engine.display.drawListDirty=!0,this.publish("enabled",a)),this},SceneJS.Enable.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Enable.prototype._compile=function(d){this._engine.display.enable=b[c++]=this._core,this._compileNodes(d),this._engine.display.enable=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"flags",picking:!0,clipping:!0,enabled:!0,transparent:!1,backfaces:!0,frontface:"ccw",reflective:!0,solid:!0,hash:"refl;s;"},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.flags=a,c=0}),SceneJS.Flags=SceneJS_NodeFactory.createNodeType("flags"),SceneJS.Flags.prototype._init=function(a){1==this._core.useCount&&(this._core.picking=!0,this._core.clipping=!0,this._core.enabled=!0,this._core.transparent=!1,this._core.backfaces=!0,this._core.frontface="ccw",this._core.reflective=!0,this._core.solid=!0,a.flags&&this.setFlags(a.flags))},SceneJS.Flags.prototype.setFlags=function(a){var b=this._core;return void 0!=a.picking&&(b.picking=!!a.picking,this._engine.display.drawListDirty=!0),void 0!=a.clipping&&(b.clipping=!!a.clipping,this._engine.display.imageDirty=!0),void 0!=a.enabled&&(b.enabled=!!a.enabled,this._engine.display.drawListDirty=!0),void 0!=a.transparent&&(b.transparent=!!a.transparent,this._engine.display.stateSortDirty=!0),void 0!=a.backfaces&&(b.backfaces=!!a.backfaces,this._engine.display.imageDirty=!0),void 0!=a.frontface&&(b.frontface=a.frontface,this._engine.display.imageDirty=!0),void 0!=a.reflective&&(b.reflective=a.reflective,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),void 0!=a.solid&&(b.solid=a.solid,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.addFlags=function(a){return this.setFlags(a)},SceneJS.Flags.prototype.getFlags=function(){var a=this._core;return{picking:a.picking,clipping:a.clipping,enabled:a.enabled,transparent:a.transparent,backfaces:a.backfaces,frontface:a.frontface,reflective:a.reflective,solid:a.solid}},SceneJS.Flags.prototype.setPicking=function(a){return a=!!a,this._core.picking!=a&&(this._core.picking=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getPicking=function(){return this._core.picking},SceneJS.Flags.prototype.setClipping=function(a){return a=!!a,this._core.clipping!=a&&(this._core.clipping=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getClipping=function(){return this._core.clipping},SceneJS.Flags.prototype.setEnabled=function(a){return a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Flags.prototype.setTransparent=function(a){return a=!!a,this._core.transparent!=a&&(this._core.transparent=a,this._engine.display.stateOrderDirty=!0),this},SceneJS.Flags.prototype.getTransparent=function(){return this._core.transparent},SceneJS.Flags.prototype.setBackfaces=function(a){return a=!!a,this._core.backfaces!=a&&(this._core.backfaces=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getBackfaces=function(){return this._core.backfaces},SceneJS.Flags.prototype.setFrontface=function(a){return this._core.frontface!=a&&(this._core.frontface=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getFrontface=function(){return this._core.frontface},SceneJS.Flags.prototype.setReflective=function(a){return a=!!a,this._core.reflective!=a&&(this._core.reflective=a,this._core.hash=(a?"refl":"")+this._core.solid?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getReflective=function(){return this._core.reflective},SceneJS.Flags.prototype.setSolid=function(a){return a=!!a,this._core.solid!=a&&(this._core.solid=a,this._core.hash=(this._core.reflective?"refl":"")+a?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getSolid=function(){return this._core.solid},SceneJS.Flags.prototype._compile=function(d){this._engine.display.flags=b[c++]=this._core,this._compileNodes(d),this._engine.display.flags=--c>0?b[c-1]:a}}(),new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._core.renderBuf.webglRestored()}),SceneJS.ColorTarget=SceneJS_NodeFactory.createNodeType("colorTarget"),SceneJS.ColorTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="color",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.ColorTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.ColorTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._buildNodeCore()}),SceneJS.DepthTarget=SceneJS_NodeFactory.createNodeType("depthTarget"),SceneJS.DepthTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="depth",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.DepthTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.DepthTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a=[],b=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){b=0}),SceneJS.Geometry=SceneJS_NodeFactory.createNodeType("geometry"),SceneJS.Geometry.prototype._init=function(a){if(1==this._core.useCount){this._initNodeCore(a,{origin:a.origin,scale:a.scale,autoNormals:"auto"==a.normals}),this._buildNodeCore(this._engine.canvas.gl,this._core);var b=this;this._core.webglRestored=function(){b._buildNodeCore(b._engine.canvas.gl,b._core)}}},SceneJS.Geometry.prototype._initNodeCore=function(a,b){var c=this;b=b||{};var d=a.primitive||"triangles",e=this._core,f=this._engine.canvas.UINT_INDEX_ENABLED?Uint32Array:Uint16Array;e.primitive=this._getPrimitiveType(d),a.normals&&"triangles"==d&&("auto"===a.normals||a.normals===!0)&&a.positions&&a.indices&&this._buildNormals(a),e.arrays={positions:a.positions?new Float32Array(b.scale||b.origin?this._applyOptions(a.positions,b):a.positions):void 0,normals:a.normals?new Float32Array(a.normals):void 0,uv:a.uv?new Float32Array(a.uv):void 0,uv2:a.uv2?new Float32Array(a.uv2):void 0,colors:a.colors?new Float32Array(a.colors):void 0,indices:a.indices?new f(a.indices):void 0},delete a.positions,delete a.normals,delete a.uv,delete a.uv2,delete a.indices,delete a.colors,e.getTangentBuf=function(){if(e.tangentBuf)return e.tangentBuf;var a=e.arrays;if(a.positions&&a.indices&&a.uv){var b=c._engine.canvas.gl,d=new Float32Array(c._buildTangents(a));e.arrays.tangents=d;var f=b.STATIC_DRAW;return e.tangentBuf=new SceneJS._webgl.ArrayBuffer(b,b.ARRAY_BUFFER,d,d.length,3,f)}}},SceneJS.Geometry.prototype._getPrimitiveType=function(a){var b=this._engine.canvas.gl;switch(a){case"points":return b.POINTS;case"lines":return b.LINES;case"line-loop":return b.LINE_LOOP;case"line-strip":return b.LINE_STRIP;case"triangles":return b.TRIANGLES;case"triangle-strip":return b.TRIANGLE_STRIP;case"triangle-fan":return b.TRIANGLE_FAN;default:throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"geometry primitive unsupported: '"+a+"' - supported types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'")}},SceneJS.Geometry.prototype._applyOptions=function(a,b){var c=a.slice?a.slice(0):new Float32Array(a);if(b.scale)for(var d=void 0!=b.scale.x?b.scale.x:1,e=void 0!=b.scale.y?b.scale.y:1,f=void 0!=b.scale.z?b.scale.z:1,g=0,h=c.length;h>g;g+=3)c[g]*=d,c[g+1]*=e,c[g+2]*=f;if(b.origin)for(var i=void 0!=b.origin.x?b.origin.x:0,j=void 0!=b.origin.y?b.origin.y:0,k=void 0!=b.origin.z?b.origin.z:0,g=0,h=c.length;h>g;g+=3)c[g]-=i,c[g+1]-=j,c[g+2]-=k;return c};var c=function(a){a.vertexBuf&&(a.vertexBuf.destroy(),a.vertexBuf=null),a.normalBuf&&(a.normalBuf.destroy(),a.normalBuf=null),a.uvBuf&&(a.uvBuf.destroy(),a.uvBuf=null),a.uvBuf2&&(a.uvBuf2.destroy(),a.uvBuf2=null),a.colorBuf&&(a.colorBuf.destroy(),a.colorBuf=null),a.tangentBuf&&(a.tangentBuf.destroy(),a.tangentBuf=null),a.indexBuf&&(a.indexBuf.destroy(),a.indexBuf=null),a.interleavedBuf&&(a.interleavedBuf.destroy(),a.interleavedBuf=null)};SceneJS.Geometry.prototype._buildNodeCore=function(a,b){var d=a.STATIC_DRAW;try{var e=b.arrays,f=SceneJS.getConfigs("enableInterleaving")!==!1,g=0,h=0,i=[],j=[],k=function(a,b){return 0==g?g=a.length/b:a.length/b!=g&&(f=!1),i.push(a),j.push(b),h+=b,4*(h-b)};if(e.positions&&(f&&(b.interleavedPositionOffset=k(e.positions,3)),b.vertexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.positions,e.positions.length,3,d)),e.normals&&(f&&(b.interleavedNormalOffset=k(e.normals,3)),b.normalBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.normals,e.normals.length,3,d)),e.uv&&(f&&(b.interleavedUVOffset=k(e.uv,2)),b.uvBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv,e.uv.length,2,d)),e.uv2&&(f&&(b.interleavedUV2Offset=k(e.uv2,2)),b.uvBuf2=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv2,e.uv2.length,2,d)),e.colors&&(f&&(b.interleavedColorOffset=k(e.colors,4)),b.colorBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.colors,e.colors.length,4,d)),e.indices&&(b.indexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ELEMENT_ARRAY_BUFFER,e.indices,e.indices.length,1,d)),h>0&&f){for(var l=[],m=i.length,n=0;g>n;++n)for(var o=0;m>o;++o)for(var p=j[o],q=0;p>q;++q)l.push(i[o][n*p+q]);b.interleavedStride=4*h,b.interleavedBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,new Float32Array(l),l.length,h,d),b.interleavedBuf.dirty=!1}}catch(r){throw c(b),SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate geometry: "+r)}},SceneJS.Geometry.prototype._updateArray=function(a,b,c){var d=a.length,e=b.length;e+c>d&&(e-=e+c-d);for(var f=c,g=0;e>g;f++,g++)a[f]=b[g]},SceneJS.Geometry.prototype._buildNormals=function(a){for(var b,c,d,e,f,g,h=a.positions,i=a.indices,j=new Array(h.length/3),k=0,l=i.length-3;l>k;k+=3){b=i[k+0],c=i[k+1],d=i[k+2],e=[h[3*b+0],h[3*b+1],h[3*b+2]],f=[h[3*c+0],h[3*c+1],h[3*c+2]],g=[h[3*d+0],h[3*d+1],h[3*d+2]],f=SceneJS_math_subVec4(f,e,[0,0,0,0]),g=SceneJS_math_subVec4(g,e,[0,0,0,0]);var m=SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(f,g,[0,0,0,0]),[0,0,0,0]);j[b]||(j[b]=[]),j[c]||(j[c]=[]),j[d]||(j[d]=[]),j[b].push(m),j[c].push(m),j[d].push(m)}for(var n=new Array(h.length),k=0,l=j.length;l>k;k++){for(var o=j[k].length,p=0,q=0,r=0,s=0;o>s;s++)p+=j[k][s][0],q+=j[k][s][1],r+=j[k][s][2];n[3*k+0]=p/o,n[3*k+1]=q/o,n[3*k+2]=r/o}a.normals=n},SceneJS.Geometry.prototype._buildTangents=function(a){for(var b=a.positions,c=a.indices,d=a.uv,e=[],f=0;ft;t++){var u=c[f+t];"undefined"!=typeof e[u]?e[u]=SceneJS_math_addVec3(e[u],s,[]):e[u]=s}}for(var v=[],w=0;wf;f+=3)c=b[f],d=b[f+1],e=b[f+2],cthis._boundary.xmax&&(this._boundary.xmax=c),d>this._boundary.ymax&&(this._boundary.ymax=d),e>this._boundary.zmax&&(this._boundary.zmax=e);return this._boundary},SceneJS.Geometry.prototype._compile=function(c){if(this._core._loading)return void this._compileNodes(c);var d=this._core;d.vertexBuf||(d=this._inheritVBOs(d)),d.indexBuf?(d.hash=[d.normalBuf?"t":"f",d.arrays&&d.arrays.tangents?"t":"f",d.uvBuf?"t":"f",d.uvBuf2?"t":"f",d.colorBuf?"t":"f",d.primitive].join(""),d.stateId=this._core.stateId,d.type="geometry",this._engine.display.geometry=a[b++]=d,SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING,{display:this._engine.display}),this._engine.display.buildObject(this.id)):a[b++]=this._core,this._compileNodes(c),b--},SceneJS.Geometry.prototype._inheritVBOs=function(c){for(var d={primitive:c.primitive,boundary:c.boundary,normalBuf:c.normalBuf,uvBuf:c.uvBuf,uvBuf2:c.uvBuf2,colorBuf:c.colorBuf,interleavedBuf:c.interleavedBuf,indexBuf:c.indexBuf,interleavedStride:c.interleavedStride,interleavedPositionOffset:c.interleavedPositionOffset,interleavedNormalOffset:c.interleavedNormalOffset,interleavedUVOffset:c.interleavedUVOffset,interleavedUV2Offset:c.interleavedUV2Offset,interleavedColorOffset:c.interleavedColorOffset},e=b-1;e>=0;e--)if(a[e].vertexBuf)return d.vertexBuf=a[e].vertexBuf,d.boundary=a[e].boundary,d.normalBuf=a[e].normalBuf,d.uvBuf=a[e].uvBuf,d.uvBuf2=a[e].uvBuf2,d.colorBuf=a[e].colorBuf,d.interleavedBuf=a[e].interleavedBuf,d.interleavedStride=a[e].interleavedStride,d.interleavedPositionOffset=a[e].interleavedPositionOffset,d.interleavedNormalOffset=a[e].interleavedNormalOffset,d.interleavedUVOffset=a[e].interleavedUVOffset,d.interleavedUV2Offset=a[e].interleavedUV2Offset,d.interleavedColorOffset=a[e].interleavedColorOffset,d;return d},SceneJS.Geometry.prototype._destroy=function(){this._engine.display.removeObject(this.id),1==this._core.useCount&&(this._destroyNodeCore(),this._source&&this._source.destroy&&this._source.destroy())},SceneJS.Geometry.prototype._destroyNodeCore=function(){document.getElementById(this._engine.canvas.canvasId)&&c(this._core)}},function(){var a={type:"stage",stateId:SceneJS._baseStateId++,priority:0,pickable:!0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.stage=a,c=0}),SceneJS.Stage=SceneJS_NodeFactory.createNodeType("stage"),SceneJS.Stage.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1,this._core.pickable=!!a.pickable)},SceneJS.Stage.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Stage.prototype.getPriority=function(){return this._core.priority},SceneJS.Stage.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype._compile=function(d){this._engine.display.stage=b[c++]=this._core,this._compileNodes(d),this._engine.display.stage=--c>0?b[c-1]:a}}(),function(){var a={type:"layer",stateId:SceneJS._baseStateId++,priority:0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.layer=a,c=0}),SceneJS.Layer=SceneJS_NodeFactory.createNodeType("layer"),SceneJS.Layer.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1)},SceneJS.Layer.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Layer.prototype.getPriority=function(){return this._core.priority},SceneJS.Layer.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.setClearDepth=function(a){a=a||0,this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Layer.prototype._compile=function(d){this._engine.display.layer=b[c++]=this._core,this._compileNodes(d),this._engine.display.layer=--c>0?b[c-1]:a}}(),SceneJS.Library=SceneJS_NodeFactory.createNodeType("library"),SceneJS.Library.prototype._compile=function(a){},function(){function a(a){if(a.lights&&a.lights.length>0){for(var b,c=a.lights,d=[],e=0,f=c.length;f>e;e++)b=c[e],d.push(b.mode),b.specular&&d.push("s"),b.diffuse&&d.push("d"),d.push("world"==b.space?"w":"v");a.hash=d.join("")}else a.hash=""}var b={type:"lights",stateId:SceneJS._baseStateId++,hash:null,empty:!1,lights:[{mode:"ambient",color:[.7,.7,.8],diffuse:!0,specular:!1},{mode:"dir",color:[1,1,1],diffuse:!0,specular:!0,dir:[-.5,-.5,-1],space:"view"},{mode:"dir",color:[1,1,1],diffuse:!1,specular:!0,dir:[1,-.9,-.7],space:"view"}]};a(b);var c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.lights=b,d=0}),SceneJS.Lights=SceneJS_NodeFactory.createNodeType("lights"),SceneJS.Lights.prototype._init=function(a){if(1==this._core.useCount){var b=a.lights;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"lights node attribute missing : 'lights'");this._core.lights=this._core.lights||[];for(var c=0,d=b.length;d>c;c++)this._initLight(c,b[c])}},SceneJS.Lights.prototype._initLight=function(a,b){var c=[];this._core.lights[a]=c;var d=b.mode||"dir";if("dir"!=d&&"point"!=d&&"ambient"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");var e=b.pos,f=b.dir,g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],c.mode=d,c.diffuse="ambient"==d?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==d?!1:void 0!=b.specular?b.specular:!0,c.pos=b.pos?[e.x||0,e.y||0,e.z||0]:[0,0,0],c.dir=b.dir?[f.x||0,f.y||0,f.z||0]:[0,0,1],c.attenuation=[void 0!=b.constantAttenuation?b.constantAttenuation:0,b.linearAttenuation||0,b.quadraticAttenuation||0];var h=b.space;if(h){if("view"!=h&&"world"!=h)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+h+"' - should be 'view' or 'world'")}else h="world";c.space=h,this._core.hash=null},SceneJS.Lights.prototype.setLights=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.lights.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'lights': index out of range ("+this._core.lights.length+" lights defined)");this._setLight(b,a[c]||{})}this._engine.branchDirty(this)},SceneJS.Lights.prototype._setLight=function(a,b){var c=this._core.lights[a],d=!1,e=!1;if(b.mode&&b.mode!=c.mode){var f=b.mode;if("dir"!=f&&"point"!=f&&"ambient"!=f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");c.mode=f,c.diffuse="ambient"==f?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==f?!1:void 0!=b.specular?b.specular:!0,e=!0}if(b.color){var g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],d=!0}var h=b.pos;h&&(c.pos=[h.x||0,h.y||0,h.z||0],d=!0);var i=b.dir;if(i&&(c.dir=[i.x||0,i.y||0,i.z||0],d=!0),void 0!=b.constantAttenuation&&(c.attenuation[0]=b.constantAttenuation,d=!0),void 0!=b.linearAttenuation&&(c.attenuation[1]=b.linearAttenuation,d=!0),void 0!=b.quadraticAttenuation&&(c.attenuation[2]=b.quadraticAttenuation,d=!0),b.space&&b.space!=c.space){var j=b.space;if("view"!=j&&"world"!=j)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+j+"' - should be 'view' or 'world'");c.space=j,this._core.hash=null,e=!0}void 0!=b.specular&&b.specular!=c.specular&&(c.specular=b.specular,e=!0),void 0!=b.diffuse&&b.diffuse!=c.diffuse&&(c.diffuse=b.diffuse,e=!0),e?this._engine.branchDirty(this):d&&(this._engine.display.imageDirty=!0),this._core.hash=null},SceneJS.Lights.prototype._compile=function(e){this._core.hash||a(this._core),this._engine.display.lights=c[d++]=this._core,this._compileNodes(e),this._engine.display.lights=--d>0?c[d-1]:b}}(),function(){var a=SceneJS_math_lookAtMat4c(0,0,10,0,0,0,0,1,0),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4())),d=new Float32Array(c),e={type:"lookAt",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,lookAt:SceneJS_math_LOOKAT_ARRAYS},f=[],g=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.viewTransform=e,g=0}),SceneJS.Lookat=SceneJS_NodeFactory.createNodeType("lookAt"),SceneJS.Lookat.prototype._init=function(a){if(this._mat=null,this._xf={type:"lookat"},1==this._core.useCount){this._core.eyeX=0,this._core.eyeY=0,this._core.eyeZ=10,this._core.lookX=0,this._core.lookY=0,this._core.lookZ=0,this._core.upX=0,this._core.upY=1,this._core.upZ=0,a.eye||a.look||a.up?(this.setEye(a.eye),this.setLook(a.look),this.setUp(a.up)):(this.setEye({x:0,y:0,z:10}),this.setLook({x:0,y:0,z:0}),this.setUp({x:0,y:1,z:0}));var b=this._core,c=this;this._core.rebuild=function(){b.matrix=SceneJS_math_lookAtMat4c(b.eyeX,b.eyeY,b.eyeZ,b.lookX,b.lookY,b.lookZ,b.upX,b.upY,b.upZ),b.lookAt={eye:[b.eyeX,b.eyeY,b.eyeZ],look:[b.lookX,b.lookY,b.lookZ],up:[b.upX,b.upY,b.upZ]},b.mat?(b.mat.set(b.matrix),b.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))):(b.mat=new Float32Array(b.matrix),b.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))),c.publish("matrix",b.matrix),b.dirty=!1},this._core.dirty=!0,this._tick=this.getScene().on("tick",function(){c._core.dirty&&c._core.rebuild()})}},SceneJS.Lookat.getDefaultMatrix=function(){return b},SceneJS.Lookat.prototype.setEye=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.eyeX=a.x),void 0!=a.y&&null!=a.y&&(this._core.eyeY=a.y),void 0!=a.z&&null!=a.z&&(this._core.eyeZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEye=function(a){return a=a||{},this._core.eyeX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.eyeY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.eyeZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeX=function(a){return this._core.eyeX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeY=function(a){return this._core.eyeY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0, +this},SceneJS.Lookat.prototype.setEyeZ=function(a){return this._core.eyeZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeX=function(a){return this._core.eyeX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeY=function(a){return this._core.eyeY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeZ=function(a){return this._core.eyeZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getEye=function(){return{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ}},SceneJS.Lookat.prototype.setLook=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.lookX=a.x),void 0!=a.y&&null!=a.y&&(this._core.lookY=a.y),void 0!=a.z&&null!=a.z&&(this._core.lookZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLook=function(a){return a=a||{},this._core.lookX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.lookY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.lookZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookX=function(a){return this._core.lookX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookY=function(a){return this._core.lookY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookZ=function(a){return this._core.lookZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookX=function(a){return this._core.lookX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookY=function(a){return this._core.lookY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookZ=function(a){return this._core.lookZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getLook=function(){return{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ}},SceneJS.Lookat.prototype.setUp=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.upX=a.x),void 0!=a.y&&null!=a.y&&(this._core.upY=a.y),void 0!=a.z&&null!=a.z&&(this._core.upZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUp=function(a){return a=a||{},this._core.upX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.upY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.upZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpX=function(a){return this._core.upX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpY=function(a){return this._core.upY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpZ=function(a){return this._core.upZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpX=function(a){return this._core.upX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpY=function(a){return this._core.upY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpZ=function(a){return this._core.upZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getUp=function(){return{x:this._core.upX,y:this._core.upY,z:this._core.upZ}},SceneJS.Lookat.prototype.getMatrix=function(){return this._core.dirty&&this._core.rebuild(),this._core.matrix.slice(0)},SceneJS.Lookat.prototype.getAttributes=function(){return{look:{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ},eye:{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ},up:{x:this._core.upX,y:this._core.upY,z:this._core.upZ}}},SceneJS.Lookat.prototype._compile=function(a){this._engine.display.viewTransform=f[g++]=this._core,this._compileNodes(a),this._engine.display.viewTransform=--g>0?f[g-1]:e},SceneJS.Lookat.prototype._destroy=function(){this.getScene().off(this._tick)}}(),new function(){var a={type:"material",stateId:SceneJS._baseStateId++,baseColor:[1,1,1],specularColor:[1,1,1],specular:1,shine:70,alpha:1,emit:0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.material=a,c=0}),SceneJS.Material=SceneJS_NodeFactory.createNodeType("material"),SceneJS.Material.prototype._init=function(a){1==this._core.useCount&&(this.setBaseColor(a.color||a.baseColor),this.setSpecularColor(a.specularColor),this.setSpecular(a.specular),this.setShine(a.shine),this.setEmit(a.emit),this.setAlpha(a.alpha))},SceneJS.Material.prototype.setBaseColor=function(b){var c=a.baseColor;return this._core.baseColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.baseColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.setColor=SceneJS.Material.prototype.setBaseColor,SceneJS.Material.prototype.getBaseColor=function(){return{r:this._core.baseColor[0],g:this._core.baseColor[1],b:this._core.baseColor[2]}},SceneJS.Material.prototype.getColor=SceneJS.Material.prototype.getBaseColor,SceneJS.Material.prototype.setSpecularColor=function(b){var c=a.specularColor;return this._core.specularColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.specularColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecularColor=function(){return{r:this._core.specularColor[0],g:this._core.specularColor[1],b:this._core.specularColor[2]}},SceneJS.Material.prototype.setSpecular=function(b){return this._core.specular=void 0!=b&&null!=b?b:a.specular,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecular=function(){return this._core.specular},SceneJS.Material.prototype.setShine=function(b){return this._core.shine=void 0!=b&&null!=b?b:a.shine,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getShine=function(){return this._core.shine},SceneJS.Material.prototype.setEmit=function(b){return this._core.emit=void 0!=b&&null!=b?b:a.emit,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getEmit=function(){return this._core.emit},SceneJS.Material.prototype.setAlpha=function(b){return this._core.alpha=void 0!=b&&null!=b?b:a.alpha,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getAlpha=function(){return this._core.alpha},SceneJS.Material.prototype._compile=function(d){this._engine.display.material=b[c++]=this._core,this._compileNodes(d),this._engine.display.material=--c>0?b[c-1]:a}},new function(){var a={type:"morphGeometry",stateId:SceneJS._baseStateId++,hash:"",morph:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.morphGeometry=a,c=0}),SceneJS.MorphGeometry=SceneJS_NodeFactory.createNodeType("morphGeometry"),SceneJS.MorphGeometry.prototype._init=function(a){if(1==this._core.useCount){if(this._sourceConfigs=a.source,this._source=null,a.source){if(!a.source.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry config expected: source.type");var b=this;SceneJS.Plugins.getPlugin("morphGeometry",this._sourceConfigs.type,function(c){if(!c)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: no support for source type '"+b._sourceConfigs.type+"' - need to include plugin for self source type, or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '"+b._sourceConfigs.type+"', ).");if(!c.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)");if(b._source=c.getSource(),!b._source.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'subscribe' method not found on source provided by plugin type '"+a.source.type+"'");var d=!1;b._source.subscribe(function(a){if(d){if(a.targets)for(var c,e,f,g=a.targets,h=b._core.targets,i=0,j=g.length;j>i;i++)c=g[i],e=c.targetIndex,f=h[e],c.positions&&f.vertexBuf&&(f.vertexBuf.bind(),f.vertexBuf.setData(c.positions,0));b._display.imageDirty=!0}else b._buildNodeCore(a),b._core._loading=!1,b._fireEvent("loaded"),b._engine.branchDirty(b),d=!0}),b._core._loading=!0,b._fireEvent("loading"),b._source.configure(b._sourceConfigs)})}else a.create instanceof Function?this._buildNodeCore(a.create()):this._buildNodeCore(a);this._core.webglRestored=function(){},this.setFactor(a.factor)}this._core.factor=a.factor||0,this._core.clamp=!!a.clamp},SceneJS.MorphGeometry.prototype._buildNodeCore=function(a){var b=a.targets||[];if(b.length<2)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node should have at least two targets");var c=a.keys||[];if(c.length!=b.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node mismatch in number of keys and targets");var d=this._core,e=this._engine.canvas.gl,f=e.STATIC_DRAW;d.keys=c,d.targets=[],d.key1=0,d.key2=1;for(var g,h,i,j,k,l=0,m=b.length;m>l;l++)k=b[l],!g&&k.positions&&(g=k.positions),!h&&k.normals&&(h=k.normals),!i&&k.uv&&(i=k.uv),!j&&k.uv2&&(j=k.uv2);try{for(var n,o,l=0,m=b.length;m>l;l++)k=b[l],n={},o=k.positions||g,o&&(n.positions="Float32Array"==typeof o?o:new Float32Array(o),n.vertexBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.positions,o.length,3,f),g=o),o=k.normals||h,o&&(n.normals="Float32Array"==typeof o?o:new Float32Array(o),n.normalBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.normals,o.length,3,f),h=o),o=k.uv||i,o&&(n.uv="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv,o.length,2,f),i=o),o=k.uv2||j,o&&(n.uv2="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf2=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv2,o.length,2,f),j=o),d.targets.push(n)}catch(p){for(var l=0,m=d.targets.length;m>l;l++)n=d.targets[l],n.vertexBuf&&n.vertexBuf.destroy(),n.normalBuf&&n.normalBuf.destroy(),n.uvBuf&&n.uvBuf.destroy(),n.uvBuf2&&n.uvBuf2.destroy();throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate VBO(s) for morphGeometry: "+p)}},SceneJS.MorphGeometry.prototype.setSource=function(a){this._sourceConfigs=a;var b=this._source;b&&b.configure(a)},SceneJS.MorphGeometry.prototype.getSource=function(){return this._sourceConfigs},SceneJS.MorphGeometry.prototype.setFactor=function(a){a=a||0;var b=this._core,c=b.keys,d=b.key1,e=b.key2,f=b.factor;if(ac[c.length-1])d=c.length-2,e=d+1;else{for(;c[d]>a;)d--,e--;for(;c[e]0?b[c-1]:a},SceneJS.MorphGeometry.prototype._makeHash=function(){var a=this._core;if(a.targets.length>0){var b=a.targets[0],c="t",d="f";a.hash=[b.vertexBuf?c:d,b.normalBuf?c:d,b.uvBuf?c:d,b.uvBuf2?c:d].join("")}else a.hash=""},SceneJS.MorphGeometry.prototype._destroy=function(){if(1==this._core.useCount){if(document.getElementById(this._engine.canvas.canvasId))for(var a,b=this._core,c=0,d=b.targets.length;d>c;c++)a=b.targets[c],a.vertexBuf&&a.vertexBuf.destroy(),a.normalBuf&&a.normalBuf.destroy(),a.uvBuf&&a.uvBuf.destroy(),a.uvBuf2&&a.uvBuf2.destroy();this._source&&this._source.destroy&&this._source.destroy()}}},function(){var a={type:"name",stateId:SceneJS._baseStateId++,name:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.name=a,c=0}),SceneJS.Name=SceneJS_NodeFactory.createNodeType("name"),SceneJS.Name.prototype._init=function(a){this.setName(a.name),this._core.nodeId=this.id},SceneJS.Name.prototype.setName=function(a){this._core.name=a||"unnamed",this._engine.branchDirty(this)},SceneJS.Name.prototype.getName=function(){return this._core.name},SceneJS.Name.prototype._compile=function(d){this._engine.display.name=b[c++]=this._core;for(var e,f=[],g=0;c>g;g++)e=b[g].name,e&&f.push(e);this._core.path=f.join("."),this._compileNodes(d),this._engine.display.name=--c>0?b[c-1]:a}}(),new function(){function a(a){var c;if(f>0){c={};for(var d in a)a.hasOwnProperty(d)&&void 0!=a[d]&&(c[d]=g(d))}return b(a.props),{props:a,setProps:function(b){h(b,a)},restoreProps:function(a){c&&i(a,c)}}}function b(a){var b;for(var c in a)a.hasOwnProperty(c)&&(b=a[c],void 0!=b&&null!=b&&(k[c]?a[c]=k[c](null,b):l[c]&&(a[c]=l[c](null,b))))}var c,d={type:"renderer",stateId:SceneJS._baseStateId++,props:null},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){c=a.engine.canvas,f=0,a.engine.display.renderer=e[f++]=d});var g=function(a){for(var b,c,d=f-1;d>=0;d--)if(b=e[d].props,b&&(c=b[a],void 0!=c&&null!=c))return b[a];return null},h=function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=k[c];d&&d(a,b[c])}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor),b.clear&&l.clear(a,b.clear)},i=function(a,b){var c;for(var d in b)if(b.hasOwnProperty(d)&&(c=b[d],void 0!=c&&null!=c)){var e=k[d];e&&e(a,c)}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor)},j=function(a,b){if(!b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Null SceneJS.State node config: "'+b+'"');var c=SceneJS._webgl.enumMap[b];if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Unrecognised SceneJS.State node config value: "'+b+'"');var d=a[c];if(!d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"This browser's WebGL does not support renderer node config value: \""+b+'"');return d},k={enableBlend:function(a,b){return a?void(b?a.enable(a.BLEND):a.disable(a.BLEND)):((null==b||void 0==b)&&(b=!1),b)},blendColor:function(a,b){return a?void a.blendColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},blendEquation:function(a,b){return a?void a.blendEquation(a,j(a,b)):b||"funcAdd"},blendEquationSeparate:function(a,b){return a?void a.blendEquation(j(a,b.rgb),j(a,b.alpha)):(b=b||{},{rgb:b.rgb||"funcAdd",alpha:b.alpha||"funcAdd"})},blendFunc:function(a,b){return a?void a.blendFunc(j(a,b.sfactor||"srcAlpha"),j(a,b.dfactor||"oneMinusSrcAlpha")):(b=b||{},{sfactor:b.sfactor||"srcAlpha",dfactor:b.dfactor||"oneMinusSrcAlpha"})},blendFuncSeparate:function(a,b){return a?void a.blendFuncSeparate(j(a,b.srcRGB||"zero"),j(a,b.dstRGB||"zero"),j(a,b.srcAlpha||"zero"),j(a,b.dstAlpha||"zero")):(b=b||{},{srcRGB:b.srcRGB||"zero",dstRGB:b.dstRGB||"zero",srcAlpha:b.srcAlpha||"zero",dstAlpha:b.dstAlpha||"zero"})},clearColor:function(a,b){return a?void a.clearColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},clearDepth:function(a,b){return a?void a.clearDepth(b):null==b||void 0==b?1:b},clearStencil:function(a,b){return a?void a.clearStencil(b):b||0},colorMask:function(a,b){return a?void a.colorMask(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},enableCullFace:function(a,b){return a?void(b?a.enable(a.CULL_FACE):a.disable(a.CULL_FACE)):b},cullFace:function(a,b){return a?void a.cullFace(j(a,b)):b||"back"},enableDepthTest:function(a,b){return a?void(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST)):((null==b||void 0==b)&&(b=!0),b)},depthFunc:function(a,b){return a?void a.depthFunc(j(a,b)):b||"less"},enableDepthMask:function(a,b){return a?void a.depthMask(b):((null==b||void 0==b)&&(b=!0),b)},depthRange:function(a,b){return a?void a.depthRange(b.zNear,b.zFar):(b=b||{},{zNear:void 0==b.zNear||null==b.zNear?0:b.zNear,zFar:void 0==b.zFar||null==b.zFar?1:b.zFar})},frontFace:function(a,b){return a?void a.frontFace(j(a,b)):b||"ccw"},lineWidth:function(a,b){return a?void a.lineWidth(b):b||1},enableScissorTest:function(a,b){return a?void(b?a.enable(a.SCISSOR_TEST):(b=!1,a.disable(a.SCISSOR_TEST))):b}},l={viewport:function(a,b){return a?void a.viewport(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||1,y:b.y||1,width:b.width||c.canvas.width,height:b.height||c.canvas.height})},scissor:function(a,b){return a?void a.scissor(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||0,y:b.y||0,width:b.width||1,height:b.height||1})},clear:function(a,b){if(!a)return b=b||{};var c;b.color&&(c=a.COLOR_BUFFER_BIT),b.depth&&(c|=a.DEPTH_BUFFER_BIT),b.stencil&&(c|=a.STENCIL_BUFFER_BIT)}};SceneJS.Renderer=SceneJS_NodeFactory.createNodeType("renderer"),SceneJS.Renderer.prototype._init=function(a){if(1==this._core.useCount){for(var b in a)a.hasOwnProperty(b)&&(this._core[b]=a[b]);this._core.dirty=!0}},SceneJS.Renderer.prototype.setViewport=function(a){this._core.viewport=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getViewport=function(){return this._core.viewport?{x:this._core.viewport.x,y:this._core.viewport.y,width:this._core.viewport.width,height:this._core.viewport.height}:void 0},SceneJS.Renderer.prototype.setScissor=function(a){this._core.scissor=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getScissor=function(){return this._core.scissor?{x:this._core.scissor.x,y:this._core.scissor.y,width:this._core.scissor.width,height:this._core.scissor.height}:void 0},SceneJS.Renderer.prototype.setClear=function(a){this._core.clear=a?{r:a.r||0,g:a.g||0,b:a.b||0}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getClear=function(){return this._core.clear?{r:this._core.clear.r,g:this._core.clear.g,b:this._core.clear.b}:null},SceneJS.Renderer.prototype.setEnableBlend=function(a){this._core.enableBlend=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getEnableBlend=function(){return this._core.enableBlend},SceneJS.Renderer.prototype.setBlendColor=function(a){this._core.blendColor=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendColor=function(){return this._core.blendColor?{r:this._core.blendColor.r,g:this._core.blendColor.g,b:this._core.blendColor.b,a:this._core.blendColor.a}:void 0},SceneJS.Renderer.prototype.setBlendEquation=function(a){this._core.blendEquation=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquation=function(){return this._core.blendEquation},SceneJS.Renderer.prototype.setBlendEquationSeparate=function(a){this._core.blendEquationSeparate=a?{rgb:a.rgb||"funcAdd",alpha:a.alpha||"funcAdd"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquationSeparate=function(){return this._core.blendEquationSeparate?{rgb:this._core.rgb,alpha:this._core.alpha}:void 0},SceneJS.Renderer.prototype.setBlendFunc=function(a){this._core.blendFunc=a?{sfactor:a.sfactor||"srcAlpha",dfactor:a.dfactor||"one"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendFunc=function(){return this._core.blendFunc?{sfactor:this._core.sfactor,dfactor:this._core.dfactor}:void 0},SceneJS.Renderer.prototype.setBlendFuncSeparate=function(a){this._core.blendFuncSeparate=a?{srcRGB:a.srcRGB||"zero",dstRGB:a.dstRGB||"zero",srcAlpha:a.srcAlpha||"zero",dstAlpha:a.dstAlpha||"zero"}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getBlendFuncSeparate=function(){return this._core.blendFuncSeparate?{srcRGB:this._core.blendFuncSeparate.srcRGB,dstRGB:this._core.blendFuncSeparate.dstRGB,srcAlpha:this._core.blendFuncSeparate.srcAlpha,dstAlpha:this._core.blendFuncSeparate.dstAlpha}:void 0},SceneJS.Renderer.prototype.setEnableCullFace=function(a){this._core.enableCullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableCullFace=function(){return this._core.enableCullFace},SceneJS.Renderer.prototype.setCullFace=function(a){this._core.cullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getCullFace=function(){return this._core.cullFace},SceneJS.Renderer.prototype.setEnableDepthTest=function(a){this._core.enableDepthTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthTest=function(){return this._core.enableDepthTest},SceneJS.Renderer.prototype.setDepthFunc=function(a){this._core.depthFunc=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthFunc=function(){return this._core.depthFunc},SceneJS.Renderer.prototype.setEnableDepthMask=function(a){this._core.enableDepthMask=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthMask=function(){return this._core.enableDepthMask},SceneJS.Renderer.prototype.setClearDepth=function(a){this._core.clearDepth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Renderer.prototype.setDepthRange=function(a){this._core.depthRange=a?{zNear:void 0==a.zNear||null==a.zNear?0:a.zNear,zFar:void 0==a.zFar||null==a.zFar?1:a.zFar}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthRange=function(){return this._core.depthRange?{zNear:this._core.depthRange.zNear,zFar:this._core.depthRange.zFar}:void 0},SceneJS.Renderer.prototype.setFrontFace=function(a){this._core.frontFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getFrontFace=function(){return this._core.frontFace},SceneJS.Renderer.prototype.setLineWidth=function(a){this._core.lineWidth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Renderer.prototype.setEnableScissorTest=function(a){this._core.enableScissorTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableScissorTest=function(){return this._core.enableScissorTest},SceneJS.Renderer.prototype.setClearStencil=function(a){this._core.clearStencil=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearStencil=function(){return this._core.clearStencil},SceneJS.Renderer.prototype.setColorMask=function(a){this._core.colorMask=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getColorMask=function(){return this._core.colorMask?{r:this._core.colorMask.r,g:this._core.colorMask.g,b:this._core.colorMask.b,a:this._core.colorMask.a}:void 0},SceneJS.Renderer.prototype._compile=function(b){this._core.dirty&&(this._core.props=a(this._core),this._core.dirty=!1),this._engine.display.renderer=e[f++]=this._core,this._compileNodes(b),this._engine.display.renderer=--f>0?e[f-1]:d}},function(){var a={less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL"},b={type:"depthBuffer",stateId:SceneJS._baseStateId++,enabled:!0,clearDepth:1,depthFunc:null,_depthFuncName:"less"},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){null===b.depthFunc&&(b.depthFunc=a.engine.canvas.gl.LESS),a.engine.display.depthBuffer=b,d=0}),SceneJS.DepthBuf=SceneJS_NodeFactory.createNodeType("depthBuffer"),SceneJS.DepthBuf.prototype._init=function(a){void 0!=a.enabled?this.setEnabled(a.enabled):1==this._core.useCount&&this.setEnabled(!0),void 0!=a.clearDepth?this.setClearDepth(a.clearDepth):1==this._core.useCount&&this.setClearDepth(1),void 0!=a.depthFunc?this.setDepthFunc(a.depthFunc):1==this._core.useCount&&this.setDepthFunc("less"),void 0!=a.clear?this.setClear(a.clear):1==this._core.useCount&&this.setClear(!0)},SceneJS.DepthBuf.prototype.setEnabled=function(a){return this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getEnabled=function(){return this._core.enabled},SceneJS.DepthBuf.prototype.setClear=function(a){return this._core.clear!=a&&(this._core.clear=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClear=function(){return this._core.clear},SceneJS.DepthBuf.prototype.setClearDepth=function(a){return this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.DepthBuf.prototype.setDepthFunc=function(b){if(this._core._depthFuncName!=b){var c=a[b];if(void 0==c)throw"unsupported value for 'clearFunc' attribute on depthBuffer node: '"+b+"' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";this._core.depthFunc=this._engine.canvas.gl[c],this._core._depthFuncName=b,this._engine.display.imageDirty=!0}return this},SceneJS.DepthBuf.prototype.getDepthFunc=function(){return this._core._depthFuncName},SceneJS.DepthBuf.prototype._compile=function(a){this._engine.display.depthBuffer=c[d++]=this._core,this._compileNodes(a),this._engine.display.depthBuffer=--d>0?c[d-1]:b}}(),function(){var a={type:"colorBuffer",stateId:SceneJS._baseStateId++,blendEnabled:!1,colorMask:{r:!0,g:!0,b:!0,a:!0}},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.colorBuffer=a,c=0}),SceneJS.ColorBuffer=SceneJS_NodeFactory.createNodeType("colorBuffer"),SceneJS.ColorBuffer.prototype._init=function(a){void 0!=a.blendEnabled?this.setBlendEnabled(a.blendEnabled):1==this._core.useCount&&this.setBlendEnabled(!1),this.setColorMask(a)},SceneJS.ColorBuffer.prototype.setBlendEnabled=function(a){this._core.blendEnabled!=a&&(this._core.blendEnabled=a,this._engine.display.imageDirty=!0),this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getBlendEnabled=function(){return this._core.blendEnabled},SceneJS.ColorBuffer.prototype.setColorMask=function(a){this._core.colorMask={r:void 0!=a.r&&null!=a.r?a.r:!0,g:void 0!=a.g&&null!=a.g?a.g:!0,b:void 0!=a.b&&null!=a.b?a.b:!0,a:void 0!=a.a&&null!=a.a?a.a:!0},this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getColorMask=function(){return this._core.colorMask},SceneJS.ColorBuffer.prototype._compile=function(d){this._engine.display.colorBuffer=b[c++]=this._core,this._compileNodes(d),this._engine.display.colorBuffer=--c>0?b[c-1]:a,this._engine.display.imageDirty=!0}}(),function(){var a={type:"view",stateId:SceneJS._baseStateId++,scissorTestEnabled:!1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.view=a,c=0}),SceneJS.View=SceneJS_NodeFactory.createNodeType("view"),SceneJS.View.prototype._init=function(a){void 0!=a.scissorTestEnabled?this.setScissorTestEnabled(a.scissorTestEnabled):1==this._core.useCount&&this.setScissorTestEnabled(!1)},SceneJS.View.prototype.setScissorTestEnabled=function(a){return this._core.scissorTestEnabled!=a&&(this._core.scissorTestEnabled=a,this._engine.display.imageDirty=!0),this},SceneJS.View.prototype.getScissorTestEnabled=function(){return this._core.scissorTestEnabled},SceneJS.View.prototype._compile=function(d){this._engine.display.view=b[c++]=this._core,this._compileNodes(d),this._engine.display.view=--c>0?b[c-1]:a}}(),SceneJS.Scene=SceneJS_NodeFactory.createNodeType("scene"),SceneJS.Scene.prototype._init=function(a){a.tagMask&&this.setTagMask(a.tagMask),this._tagSelector=null,this.transparent=a.transparent===!0},SceneJS.Scene.prototype.loseWebGLContext=function(){this._engine.loseWebGLContext()},SceneJS.Scene.prototype.getCanvas=function(){return this._engine.canvas.canvas},SceneJS.Scene.prototype.getGL=function(){return this._engine.canvas.gl},SceneJS.Scene.prototype.getZBufferDepth=function(){var a=this._engine.canvas.gl;return a.getParameter(a.DEPTH_BITS)},SceneJS.Scene.prototype.setSSAAMultiplier=function(a){return this._engine.canvas.setSSAAMultiplier(a)},SceneJS.Scene.prototype.setTagMask=function(a){a=a||"XXXXXXXXXXXXXXXXXXXXXXXXXX",this._tagSelector||(this._tagSelector={}),this._tagSelector.mask=a,this._tagSelector.regex=a?new RegExp(a):null,this._engine.display.selectTags(this._tagSelector)},SceneJS.Scene.prototype.getTagMask=function(){return this._tagSelector?this._tagSelector.mask:null},SceneJS.Scene.prototype.setNumPasses=function(a){this._engine.setNumPasses(a)},SceneJS.Scene.prototype.renderFrame=function(a){return this._engine.renderFrame(a)},SceneJS.Scene.prototype.needFrame=function(){this._engine.display.imageDirty=!0},SceneJS.Scene.prototype.start=function(a){this._engine.start(a)},SceneJS.Scene.prototype.setFPS=function(a){this._engine.fps=a},SceneJS.Scene.prototype.pause=function(a){this._engine.pause(a)},SceneJS.Scene.prototype.isRunning=function(){return this._engine.running},SceneJS.Scene.prototype.pick=function(a,b,c){var d=this._engine.pick(a,b,c);return this.renderFrame({force:!0}),d?(this.publish("pick",d),d):void this.publish("nopick")},SceneJS.Scene.prototype.readPixels=function(a,b){return this._engine.readPixels(a,b)},SceneJS.Scene.prototype._destroy=function(){this.destroyed||(delete SceneJS._engines[this.id],SceneJS._engineIds.removeItem(this.id),this.destroyed=!0)},SceneJS.Scene.prototype.isActive=function(){return!this._engine.destroyed},SceneJS.Scene.prototype.stop=function(){this._engine.stop()},SceneJS.Scene.prototype.containsNode=function(a){return!!this._engine.findNode(a)},SceneJS.Scene.prototype.findNodes=function(a){return this._engine.findNodes(a)},SceneJS.Scene.prototype.findNode=function(a,b){return this.getNode(a,b)},SceneJS.Scene.prototype.getNode=function(a,b){var c=this._engine.findNode(a);return c?(b&&b(c),c):b?void this.once("nodes/"+a,b):null},SceneJS.Scene.prototype.hasCore=function(a,b){return this._engine.hasCore(a,b)},SceneJS.Scene.prototype.getStatus=function(){var a=SceneJS_sceneStatusModule.sceneStatus[this.id];return a?SceneJS._shallowClone(a):{destroyed:!0}},new function(){function a(a){for(var b,c,d={},e=0;i>e;e++){b=a[e];for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c])}return d}var b={type:"shader",stateId:SceneJS._baseStateId++,hash:"",empty:!0,shader:{}},c=[],d=[],e=[],f=[],g=[],h=[],i=0,j=!0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.shader=b,i=0,j=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(k){if(j){if(i>0){var l={type:"shader",stateId:c[i-1],hash:c.slice(0,i).join("."),shaders:{fragment:{code:f.slice(0,i).join(""),hooks:a(g)},vertex:{code:d.slice(0,i).join(""),hooks:a(e)}},paramsStack:h.slice(0,i)};k.display.shader=l}else k.display.shader=b;j=!1}}),SceneJS.Shader=SceneJS_NodeFactory.createNodeType("shader"),SceneJS.Shader.prototype._init=function(a){1==this._core.useCount&&(this._setShaders(a.shaders),this.setParams(a.params))},SceneJS.Shader.prototype._setShaders=function(a){a=a||[],this._core.shaders={};for(var b,c=0,d=a.length;d>c;c++){if(b=a[c],!b.stage)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"shader 'stage' attribute expected");var e;b.code&&(e=SceneJS._isArray(b.code)?b.code.join(""):b.code),this._core.shaders[b.stage]={code:e,hooks:b.hooks}}},SceneJS.Shader.prototype.setParams=function(a){a=a||{};var b=this._core.params;b||(b=this._core.params={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.Shader.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.Shader.prototype._compile=function(a){c[i]=this._core.coreId;var b=this._core.shaders,k=b.fragment||{},l=b.vertex||{};f[i]=k.code||"",g[i]=k.hooks||{},d[i]=l.code||"", +e[i]=l.hooks||{},h[i]=this._core.params||{},i++,j=!0,this._compileNodes(a),i--,j=!0}},new function(){var a,b={type:"shaderParams",stateId:SceneJS._baseStateId++,empty:!0},c=[],d=[],e=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(c){c.engine.display.shaderParams=b,e=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(e>0){var g={type:"shaderParams",stateId:c[e-1],paramsStack:d.slice(0,e)};f.display.shaderParams=g}else f.display.shaderParams=b;a=!1}}),SceneJS.ShaderParams=SceneJS_NodeFactory.createNodeType("shaderParams"),SceneJS.ShaderParams.prototype._init=function(a){1==this._core.useCount&&this.setParams(a.params)},SceneJS.ShaderParams.prototype.setParams=function(a){a=a||{};var b=this._core;b.params||(b.params={});for(var c in a)a.hasOwnProperty(c)&&(b.params[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.ShaderParams.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.ShaderParams.prototype._compile=function(b){c[e]=this._core.coreId,d[e]=this._core.params,e++,a=!0,this._compileNodes(b),e--,a=!0}},function(){var a={type:"style",stateId:SceneJS._baseStateId++,lineWidth:1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.style=a,c=0}),SceneJS.Style=SceneJS_NodeFactory.createNodeType("style"),SceneJS.Style.prototype._init=function(a){void 0!=a.lineWidth&&this.setLineWidth(a.lineWidth)},SceneJS.Style.prototype.setLineWidth=function(a){return this._core.lineWidth!=a&&(this._core.lineWidth=a,this._engine.display.imageDirty=!0),this},SceneJS.Style.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Style.prototype._compile=function(d){this._engine.display.style=b[c++]=this._core,this._compileNodes(d),this._engine.display.style=--c>0?b[c-1]:a}}(),function(){var a={type:"tag",stateId:SceneJS._baseStateId++,tag:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.tag=a,c=0}),SceneJS.Tag=SceneJS_NodeFactory.createNodeType("tag"),SceneJS.Tag.prototype._init=function(a){if(1==this._core.useCount){if(!a.tag)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"tag node attribute missing : 'tag'");this.setTag(a.tag)}},SceneJS.Tag.prototype.setTag=function(a){var b=this._core;b.tag=a,b.pattern=null,b.matched=!1,this._engine.display.drawListDirty=!0},SceneJS.Tag.prototype.getTag=function(){return this._core.tag},SceneJS.Tag.prototype._compile=function(d){this._engine.display.tag=b[c++]=this._core,this._compileNodes(d),this._engine.display.tag=--c>0?b[c-1]:a}}(),new function(){var a={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.texture=a,c=0}),SceneJS.Texture=SceneJS_NodeFactory.createNodeType("_texture"),SceneJS.Texture.prototype._init=function(a){if(1==this._core.useCount){this._core.layers=[],this._core.params={};var b=void 0==a.waitForLoad?!0:a.waitForLoad;if(!a.layers)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers missing");if(!SceneJS._isArray(a.layers))throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers should be an array");for(var c,d=this._engine.canvas.gl,e=0;ec;c++)h._loadLayerTexture(b,a[c])}}},SceneJS.Texture.prototype._loadLayerTexture=function(a,b){var c=this,d=b.source;if(d){if(!d.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"texture layer config expected: source.type");SceneJS.Plugins.getPlugin("texture",d.type,function(e){if(!e.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'getSource' method missing on plugin for texture source type '"+d.type+"'.");var f=e.getSource({gl:a});if(!f.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'subscribe' method missing on plugin for texture source type '"+d.type+"'");var g=SceneJS_sceneStatusModule.taskStarted(c,"Loading texture");f.subscribe(function(){var d=!1;return function(e){d?c._engine.display.imageDirty=!0:(d=!0,c._setLayerTexture(a,b,e),SceneJS_sceneStatusModule.taskFinished(g))}}()),f.configure&&f.configure(d),b._source=f})}else{var e=b.uri||b.src,f=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),g=new Image;g.onload=function(){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);var e=SceneJS_configsModule.configs.maxTextureSize;e&&(g=SceneJS._webgl.clampImageSize(g,e)),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c._ensureImageSizePowerOfTwo(g)),c._setLayerTexture(a,b,d),SceneJS_sceneStatusModule.taskFinished(f),c._engine.display.imageDirty=!0},g.onerror=function(){SceneJS_sceneStatusModule.taskFailed(f)},0==e.indexOf("data")?g.src=e:(g.crossOrigin="Anonymous",g.src=e)}},SceneJS.Texture.prototype._ensureImageSizePowerOfTwo=function(a){if(!this._isPowerOfTwo(a.width)||!this._isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=this._nextHighestPowerOfTwo(a.width),b.height=this._nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b,a.crossOrigin=""}return a},SceneJS.Texture.prototype._isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS.Texture.prototype._nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS.Texture.prototype._setLayerTexture=function(a,b,c){b.texture=new SceneJS._webgl.Texture2D(a,{texture:c,minFilter:this._getGLOption("minFilter",a,b,a.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",a,b,a.LINEAR),wrapS:this._getGLOption("wrapS",a,b,a.REPEAT),wrapT:this._getGLOption("wrapT",a,b,a.REPEAT),isDepth:this._getOption(b.isDepth,!1),depthMode:this._getGLOption("depthMode",a,b,a.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",a,b,a.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",a,b,a.LEQUAL),flipY:this._getOption(b.flipY,!0),width:this._getOption(b.width,1),height:this._getOption(b.height,1),internalFormat:this._getGLOption("internalFormat",a,b,a.LEQUAL),sourceFormat:this._getGLOption("sourceType",a,b,a.ALPHA),sourceType:this._getGLOption("sourceType",a,b,a.UNSIGNED_BYTE),update:null}),this.destroyed&&b.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._getGLOption=function(a,b,c,d){var e=c[a];if(void 0==e)return d;var f=SceneJS._webgl.enumMap[e];if(void 0==f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+e+"'");var g=b[f];return g},SceneJS.Texture.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.Texture.prototype.setLayer=function(a){if(void 0==a.index||null==a.index)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index null or undefined");if(a.index<0||a.index>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(parseInt(a.index),a),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype.setLayers=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._setLayer=function(a,b){b=b||{};var c=this._core.layers[a];if(void 0!=b.blendFactor&&null!=b.blendFactor&&(c.blendFactor=b.blendFactor),b.source){var d=c._source;d&&d.configure&&d.configure(b.source)}(b.translate||b.rotate||b.scale)&&this._setLayerTransform(b,c)},SceneJS.Texture.prototype._setLayerTransform=function(a,b){var c,d;if(a.translate){var e=a.translate;void 0!=e.x&&(b.translate.x=e.x),void 0!=e.y&&(b.translate.y=e.y),c=SceneJS_math_translationMat4v([e.x||0,e.y||0,0])}if(a.scale){var f=a.scale;void 0!=f.x&&(b.scale.x=f.x),void 0!=f.y&&(b.scale.y=f.y),d=SceneJS_math_scalingMat4v([f.x||1,f.y||1,1]),c=c?SceneJS_math_mulMat4(c,d):d}if(a.rotate){var g=a.rotate;void 0!=g.z&&(b.rotate.z=g.z||0),d=SceneJS_math_rotationMat4v(.0174532925*g.z,[0,0,1]),c=c?SceneJS_math_mulMat4(c,d):d}c&&(b.matrix=c,b.matrixAsArray?b.matrixAsArray.set(b.matrix):b.matrixAsArray=new Float32Array(b.matrix),b.matrixAsArray=new Float32Array(b.matrix))},SceneJS.Texture.prototype._compile=function(d){this._core.hash||this._makeHash(),this._engine.display.texture=b[c++]=this._core,this._compileNodes(d),this._engine.display.texture=--c>0?b[c-1]:a},SceneJS.Texture.prototype._makeHash=function(){var a,b=this._core;if(b.layers&&b.layers.length>0){for(var c,d=b.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");a=e.join("")}else a="";b.hash!=a&&(b.hash=a)},SceneJS.Texture.prototype._destroy=function(){if(1==this._core.useCount)for(var a,b,c=this._core.layers,d=0,e=c.length;e>d;d++)a=c[d],a.texture&&a.texture.destroy(),b=a._source,b&&b.destroy&&b.destroy()}},new function(){function a(){var a,b;(0!=this.translate.x||0!=this.translate.y)&&(a=SceneJS_math_translationMat4v([this.translate.x||0,this.translate.y||0,0])),(1!=this.scale.x||1!=this.scale.y)&&(b=SceneJS_math_scalingMat4v([this.scale.x||1,this.scale.y||1,1]),a=a?SceneJS_math_mulMat4(a,b):b),0!=this.rotate&&(b=SceneJS_math_rotationMat4v(.0174532925*this.rotate,[0,0,1]),a=a?SceneJS_math_mulMat4(a,b):b),a&&(this.matrix=a,this.matrixAsArray?this.matrixAsArray.set(this.matrix):this.matrixAsArray=new Float32Array(this.matrix)),this._matrixDirty=!1}var b={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.texture=b,d=0});var c=[],d=0;SceneJS.TextureMap=SceneJS_NodeFactory.createNodeType("texture"),SceneJS.TextureMap.prototype._init=function(b){var c=this;if(1==this._core.useCount){if(b.applyFrom&&"uv"!=b.applyFrom&&"uv2"!=b.applyFrom&&"normal"!=b.applyFrom&&"geometry"!=b.applyFrom)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyFrom value is unsupported - should be either 'uv', 'uv2', 'normal' or 'geometry'");if(b.applyTo&&"baseColor"!=b.applyTo&&"color"!=b.applyTo&&"specular"!=b.applyTo&&"emit"!=b.applyTo&&"alpha"!=b.applyTo&&"normals"!=b.applyTo&&"shine"!=b.applyTo)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyTo value is unsupported - should be either 'color', 'baseColor', 'specular' or 'normals'");if(b.blendMode&&"add"!=b.blendMode&&"multiply"!=b.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layer blendMode value is unsupported - should be either 'add' or 'multiply'");"color"==b.applyTo&&(b.applyTo="baseColor"),SceneJS._apply({waitForLoad:void 0==b.waitForLoad?!0:b.waitForLoad,texture:null,applyFrom:b.applyFrom?b.applyFrom:"uv",applyTo:b.applyTo?b.applyTo:"baseColor",blendMode:b.blendMode?b.blendMode:"multiply",blendFactor:void 0!=b.blendFactor&&null!=b.blendFactor?b.blendFactor:1,translate:b.translate?SceneJS._apply(b.translate,{x:0,y:0}):{x:0,y:0},scale:b.scale?SceneJS._apply(b.scale,{x:1,y:1}):{x:1,y:1},rotate:b.rotate||0,matrix:null,_matrixDirty:!0,buildMatrix:a},this._core),a.call(this._core),b.src?(this._core.src=b.src,this._loadTexture(b.src)):b.image?(this._core.image=b.image,this._initTexture(b.image)):b.target&&this.getScene().getNode(b.target,function(a){c.setTarget(a)}),this._core.webglRestored=function(){c._core.image?c._initTexture(c._core.image):c._core.src?c._loadTexture(c._core.src):c._core.target}}},SceneJS.TextureMap.prototype._loadTexture=function(a){var b=this,c=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),d=new Image;d.onload=function(){b._initTexture(d),SceneJS_sceneStatusModule.taskFinished(c),b._engine.display.imageDirty=!0},d.onerror=function(){SceneJS_sceneStatusModule.taskFailed(c)},0==a.indexOf("data")?d.src=a:(d.crossOrigin="Anonymous",d.src=a)},SceneJS.TextureMap.prototype._initTexture=function(a){var b=this._engine.canvas.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);var d=SceneJS_configsModule.configs.maxTextureSize;d&&(a=SceneJS._webgl.clampImageSize(a,d)),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(a)),this._core.image=a,this._core.texture=new SceneJS._webgl.Texture2D(b,{texture:c,minFilter:this._getGLOption("minFilter",b.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",b.LINEAR),wrapS:this._getGLOption("wrapS",b.REPEAT),wrapT:this._getGLOption("wrapT",b.REPEAT),isDepth:this._getOption(this._core.isDepth,!1),depthMode:this._getGLOption("depthMode",b.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",b.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",b.LEQUAL),flipY:this._getOption(this._core.flipY,!0),width:this._getOption(this._core.width,1),height:this._getOption(this._core.height,1),internalFormat:this._getGLOption("internalFormat",b.ALPHA),sourceFormat:this._getGLOption("sourceFormat",b.ALPHA),sourceType:this._getGLOption("sourceType",b.UNSIGNED_BYTE),update:null}),this.destroyed&&this._core.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype._getGLOption=function(a,b){var c=this._engine.canvas.gl,d=this._core[a];if(void 0==d)return b;var e=SceneJS._webgl.enumMap[d];if(void 0==e)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+d+"'");return c[e]},SceneJS.TextureMap.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.TextureMap.prototype.setSrc=function(a){this._core.image=null,this._core.src=a,this._core.target=null,this._loadTexture(a)},SceneJS.TextureMap.prototype.setImage=function(a){this._core.image=a,this._core.src=null,this._core.target=null,this._initTexture(a)},SceneJS.TextureMap.prototype.setTarget=function(a){return"colorTarget"!=a.type&&"depthTarget"!=a.type?void console.log("Target node type not compatible: "+a.type):(delete this._core.src,this._core.target=a,this._core.src=null,this._core.image=null,this._core.texture=a._core.renderBuf.getTexture(),this._core.texture.bufType=a._core.bufType,void(this._engine.display.imageDirty=!0))},SceneJS.TextureMap.prototype.setBlendFactor=function(a){this._core.blendFactor=a,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getBlendFactor=function(){return this._core.blendFactor},SceneJS.TextureMap.prototype.setTranslate=function(a){this._core.translate||(this._core.translate={x:0,y:0}),this._core.translate.x=a.x,this._core.translate.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getTranslate=function(){return this._core.translate},SceneJS.TextureMap.prototype.setScale=function(a){this._core.scale||(this._core.scale={x:0,y:0}),this._core.scale.x=a.x,this._core.scale.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getScale=function(){return this._core.scale},SceneJS.TextureMap.prototype.setRotate=function(a){this._core.rotate=a,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getRotate=function(){return this._core.rotate},SceneJS.TextureMap.prototype.getMatrix=function(){return this._core._matrixDirty&&this._core.buildMatrix.call(this.core)(),this.core.matrix},SceneJS.TextureMap.prototype._compile=function(a){this.__core||(this.__core=this._engine._coreFactory.getCore("texture"));var e=this._engine.display.texture;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),c[d++]=this.__core,this._engine.display.texture=this.__core,this._compileNodes(a),this._engine.display.texture=--d>0?c[d-1]:b},SceneJS.TextureMap.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.TextureMap.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&!this._core.target&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}},function(){var a={type:"cubemap",stateId:SceneJS._baseStateId++,empty:!0,texture:null,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.cubemap=a,c=0}),SceneJS.Reflect=SceneJS_NodeFactory.createNodeType("reflect"),SceneJS.Reflect.prototype._init=function(a){if(1==this._core.useCount){if(this._core.hash="y",a.blendMode&&"add"!=a.blendMode&&"multiply"!=a.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"reflection blendMode value is unsupported - should be either 'add' or 'multiply'");this._core.blendMode=a.blendMode||"multiply",this._core.intensity=void 0!=a.intensity&&null!=a.intensity?a.intensity:1,this._core.applyTo="reflect";for(var b=this,c=this._engine.canvas.gl,d=c.createTexture(),e=[c.TEXTURE_CUBE_MAP_POSITIVE_X,c.TEXTURE_CUBE_MAP_NEGATIVE_X,c.TEXTURE_CUBE_MAP_POSITIVE_Y,c.TEXTURE_CUBE_MAP_NEGATIVE_Y,c.TEXTURE_CUBE_MAP_POSITIVE_Z,c.TEXTURE_CUBE_MAP_NEGATIVE_Z],f=[],g=SceneJS_sceneStatusModule.taskStarted(this,"Loading reflection texture"),h=!1,i=0;ii;i++)c.texImage2D(e[i],0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(f[i]));b._core.texture=new SceneJS._webgl.Texture2D(c,{texture:d,target:c.TEXTURE_CUBE_MAP,minFilter:c.LINEAR,magFilter:c.LINEAR,wrapS:c.CLAMP_TO_EDGE,wrapT:c.CLAMP_TO_EDGE}),SceneJS_sceneStatusModule.taskFinished(g),b._engine.display.imageDirty=!0}}}(),j.onerror=function(){h=!0,SceneJS_sceneStatusModule.taskFailed(g)},j.src=a.src[i]}}},SceneJS.Reflect.prototype._compile=function(d){this.__core||(this.__core=this._engine._coreFactory.getCore("cubemap"));var e=this._engine.display.cubemap;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),b[c++]=this.__core,this._engine.display.cubemap=this.__core,this._compileNodes(d),this._engine.display.cubemap=--c>0?b[c-1]:a},SceneJS.Reflect.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode);b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.Reflect.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}}(),SceneJS.XForm=SceneJS_NodeFactory.createNodeType("xform"),SceneJS.XForm.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.XForm.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.XForm.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.XForm.prototype.setElements=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.XForm elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.XForm.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Matrix=SceneJS_NodeFactory.createNodeType("matrix"),SceneJS.Matrix.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.Matrix.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Matrix.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Matrix.prototype.setMatrix=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Matrix elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Matrix.prototype.setElements=SceneJS.Matrix.prototype.setMatrix,SceneJS.Matrix.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Rotate=SceneJS_NodeFactory.createNodeType("rotate"),SceneJS.Rotate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setAngle(a.angle),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_rotationMat4v(b.angle*Math.PI/180,[b.x,b.y,b.z])}}},SceneJS.Rotate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Rotate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Rotate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for rotate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.setAngle=function(a){this._core.angle=a||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getAngle=function(){return this._core.angle},SceneJS.Rotate.prototype.setXYZ=function(a){a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Rotate.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getX=function(){return this._core.x},SceneJS.Rotate.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getY=function(){return this._core.y},SceneJS.Rotate.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getZ=function(){return this._core.z},SceneJS.Rotate.prototype.incAngle=function(a){this._core.angle+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Translate=SceneJS_NodeFactory.createNodeType("translate"),SceneJS.Translate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_translationMat4v([b.x,b.y,b.z],b.matrix)}}},SceneJS.Translate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Translate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Translate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for translate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Translate.prototype.setXYZ=function(a){return a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Translate.prototype.setX=function(a){return this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setY=function(a){return this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setZ=function(a){return this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incX=function(a){return this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incY=function(a){return this._core.y+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incZ=function(a){return this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getX=function(){return this._core.x},SceneJS.Translate.prototype.getY=function(){return this._core.y},SceneJS.Translate.prototype.getZ=function(){return this._core.z},SceneJS.Translate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Scale=SceneJS_NodeFactory.createNodeType("scale"),SceneJS.Scale.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_scalingMat4v([b.x,b.y,b.z])}}},SceneJS.Scale.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Scale.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Scale.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for scale node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setXYZ=function(a){a=a||{},this._core.x=void 0==a.x?1:a.x,this._core.y=void 0==a.y?1:a.y,this._core.z=void 0==a.z?1:a.z,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Scale.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getX=function(){return this._core.x},SceneJS.Scale.prototype.getY=function(){return this._core.y},SceneJS.Scale.prototype.getZ=function(){return this._core.z},SceneJS.Scale.prototype.incX=function(a){this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.incY=function(a){this._core.y+=a,this._core.matrixDirty=!0},SceneJS.Scale.prototype.incZ=function(a){this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()};var SceneJS_modelXFormStack=new function(){var a=SceneJS_math_identityMat4(),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(SceneJS_math_identityMat4(),SceneJS_math_mat4())),d=new Float32Array(c),e={type:"xform",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,parent:null,cores:[],numCores:0,dirty:!1,matrixDirty:!1},f=[],g=0;this.top=e;var h,i=this;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){g=0,i.top=e,h=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(a){h&&(g>0?a.display.modelTransform=f[g-1]:a.display.modelTransform=e,h=!1)}),this.buildCore=function(a){function b(a){a.dirty=!0,a.matrixDirty=!0;for(var c=0,d=a.numCores;d>c;c++)b(a.cores[c])}a.parent=null,a.cores=[],a.numCores=0,a.matrixDirty=!1,a.matrix=SceneJS_math_identityMat4(),a.mat=new Float32Array(a.matrix),a.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(a.matrix,SceneJS_math_mat4()))),a.dirty=!1,a.setDirty=function(){a.matrixDirty=!0,a.dirty,b(a)},a.build=function(){a.matrixDirty&&(a.buildMatrix&&a.buildMatrix(),a.matrixDirty=!1);var b,c=a.parent;if(c)for(b=a.matrix.slice(0);c;)c.matrixDirty&&(c.buildMatrix&&c.buildMatrix(),c.mat.set(c.matrix),c.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(c.matrix,SceneJS_math_mat4()))),c.matrixDirty=!1),SceneJS_math_mulMat4(c.matrix,b,b),!c.dirty,c=c.parent;else b=a.matrix;a.mat.set(b),a.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4()))),a.dirty=!1}},this.push=function(a){f[g++]=a,a.parent=this.top,a.dirty=!0,this.top&&(this.top.cores[this.top.numCores++]=a),a.numCores=0,this.top=a,h=!0},this.pop=function(){this.top=--g>0?f[g-1]:e,h=!0}};SceneJS.Types=new function(){this.addType=function(a,b){SceneJS_NodeFactory.createNodeType(a,b,function(a){var c;for(var d in b)if(b.hasOwnProperty(d))switch(c=b[d],d){case"init":case"construct":!function(){var c=b[d];a.prototype._init=function(a){c.call(this,a)},a.prototype._fromPlugin=!0}();break;case"destroy":case"destruct":a.prototype._destroy=c;break;default:a.prototype[d]=c}})},this.hasType=function(a){return!!SceneJS_NodeFactory.nodeTypes[a]}};var SceneJS_Display=function(a){this._canvas=a.canvas,this._programFactory=new SceneJS_ProgramFactory({canvas:a.canvas}),this._chunkFactory=new SceneJS_ChunkFactory,this.transparent=a.transparent===!0, +this.enable=null,this.flags=null,this.layer=null,this.stage=null,this.renderer=null,this.depthBuffer=null,this.colorBuffer=null,this.view=null,this.lights=null,this.material=null,this.texture=null,this.cubemap=null,this.modelTransform=null,this.viewTransform=null,this.projTransform=null,this.renderTarget=null,this.clips=null,this.morphGeometry=null,this.name=null,this.tag=null,this.renderListeners=null,this.shader=null,this.shaderParams=null,this.style=null,this.geometry=null,this._objectFactory=new SceneJS_ObjectFactory,this._objects={},this._ambientColor=[0,0,0,1],this._objectList=[],this._objectListLen=0,this._drawList=[],this._drawListLen=0,this._pickDrawList=[],this._pickDrawListLen=0,this._targetList=[],this._targetListLen=0,this._frameCtx={pickNames:[],canvas:this._canvas,VAO:null},this._frameCtx.renderListenerCtx=new SceneJS.RenderContext(this._frameCtx),this.objectListDirty=!0,this.stateOrderDirty=!0,this.stateSortDirty=!0,this.drawListDirty=!0,this.imageDirty=!0,this.pickBufDirty=!0,this.rayPickBufDirty=!0};SceneJS_Display.prototype.webglRestored=function(){this._programFactory.webglRestored(),this._chunkFactory.webglRestored();var a=this._canvas.gl;this.pickBuf&&this.pickBuf.webglRestored(a),this.rayPickBuf&&this.rayPickBuf.webglRestored(a),this.imageDirty=!0},SceneJS_Display.prototype.buildObject=function(a){var b=this._objects[a];b||(b=this._objects[a]=this._objectFactory.getObject(a),this.objectListDirty=!0),b.stage=this.stage,b.layer=this.layer,b.renderTarget=this.renderTarget,b.texture=this.texture,b.cubemap=this.cubemap,b.geometry=this.geometry,b.enable=this.enable,b.flags=this.flags,b.tag=this.tag;var c=[this.geometry.hash,this.shader.hash,this.clips.hash,this.morphGeometry.hash,this.texture.hash,this.cubemap.hash,this.lights.hash,this.flags.hash].join(";");b.program&&c==b.hash||(b.program&&this._programFactory.putProgram(b.program),b.program=this._programFactory.getProgram(c,this),b.hash=c),this._setChunk(b,0,"program"),this._setChunk(b,1,"xform",this.modelTransform),this._setChunk(b,2,"lookAt",this.viewTransform),this._setChunk(b,3,"camera",this.projTransform),this._setChunk(b,4,"flags",this.flags),this._setChunk(b,5,"shader",this.shader),this._setChunk(b,6,"shaderParams",this.shaderParams),this._setChunk(b,7,"style",this.style),this._setChunk(b,8,"depthBuffer",this.depthBuffer),this._setChunk(b,9,"colorBuffer",this.colorBuffer),this._setChunk(b,10,"view",this.view),this._setChunk(b,11,"name",this.name),this._setChunk(b,12,"lights",this.lights),this._setChunk(b,13,"material",this.material),this._setChunk(b,14,"texture",this.texture),this._setChunk(b,15,"cubemap",this.cubemap),this._setChunk(b,16,"clips",this.clips),this._setChunk(b,17,"renderer",this.renderer),this._setChunk(b,18,"geometry",this.morphGeometry,this.geometry),this._setChunk(b,19,"listeners",this.renderListeners),this._setChunk(b,20,"draw",this.geometry)},SceneJS_Display.prototype._setChunk=function(a,b,c,d,e){var f,g=this._chunkFactory.chunkTypes[c];if(d){if(d.empty){var h=a.chunks[b];return h&&this._chunkFactory.putChunk(h),void(a.chunks[b]=null)}f=g.prototype.programGlobal?"_"+d.stateId:"p"+a.program.id+"_"+d.stateId,e&&(f+="__"+e.stateId)}else f="p"+a.program.id;f=b+"__"+f;var h=a.chunks[b];if(h){if(h.id==f)return;this._chunkFactory.putChunk(h)}a.chunks[b]=this._chunkFactory.getChunk(f,c,a.program,d,e),"lights"==c&&this._setAmbient(d)},SceneJS_Display.prototype._setAmbient=function(a){for(var b,c=a.lights,d=0,e=c.length;e>d;d++)b=c[d],"ambient"==b.mode&&(this._ambientColor[0]=b.color[0],this._ambientColor[1]=b.color[1],this._ambientColor[2]=b.color[2])},SceneJS_Display.prototype.removeObject=function(a){var b=this._objects[a];b&&(this._programFactory.putProgram(b.program),b.program=null,b.hash=null,this._objectFactory.putObject(b),delete this._objects[a],this.objectListDirty=!0)},SceneJS_Display.prototype.selectTags=function(a){this._tagSelector=a,this.drawListDirty=!0},SceneJS_Display.prototype.render=function(a){a=a||{},this.objectListDirty&&(this._buildObjectList(),this.objectListDirty=!1,this.stateOrderDirty=!0),this.stateOrderDirty&&(this._makeStateSortKeys(),this.stateOrderDirty=!1,this.stateSortDirty=!0),this.stateSortDirty&&(this._stateSort(),this.stateSortDirty=!1,this.drawListDirty=!0),this.drawListDirty&&(this._buildDrawList(),this.imageDirty=!0),(this.imageDirty||a.force)&&(this._doDrawList({clear:a.clear!==!1}),this.imageDirty=!1,this.pickBufDirty=!0)},SceneJS_Display.prototype._buildObjectList=function(){this._objectListLen=0;for(var a in this._objects)this._objects.hasOwnProperty(a)&&(this._objectList[this._objectListLen++]=this._objects[a])},SceneJS_Display.prototype._makeStateSortKeys=function(){for(var a,b=0,c=this._objectListLen;c>b;b++)a=this._objectList[b],a.program?a.sortKey=1e12*(a.stage.priority+1)+1e9*(a.flags.transparent?2:1)+1e6*(a.layer.priority+1)+1e3*(a.program.id+1)+a.texture.stateId:a.sortKey=-1},SceneJS_Display.prototype._stateSort=function(){this._objectList.length=this._objectListLen,this._objectList.sort(this._stateSortObjects)},SceneJS_Display.prototype._stateSortObjects=function(a,b){return a.sortKey-b.sortKey},SceneJS_Display.prototype._logObjectList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._objectListLen+" objects");for(var a=0,b=this._objectListLen;b>a;a++){var c=this._objectList[a];console.log("SceneJS_Display : object["+a+"] sortKey = "+c.sortKey)}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._buildDrawList=function(){this._lastStateId=this._lastStateId||[],this._lastPickStateId=this._lastPickStateId||[];for(var a=0;23>a;a++)this._lastStateId[a]=null,this._lastPickStateId[a]=null;this._drawListLen=0,this._pickDrawListLen=0;var b,c,d,e,f,g={},h=[],i=[];this._tagSelector&&(c=this._tagSelector.mask,d=this._tagSelector.regex),this._objectDrawList=this._objectDrawList||[],this._objectDrawListLen=0;for(var a=0,j=this._objectListLen;j>a;a++)if(b=this._objectList[a],b.enable.enabled!==!1&&(f=b.flags,f.enabled!==!1&&b.layer.enabled&&(!c||(e=b.tag,!e.tag||(e.mask!=c&&(e.mask=c,e.matches=d.test(e.tag)),e.matches)))))if(b.renderTarget.targets)for(var k,l,m,n=b.renderTarget.targets,o=0,p=n.length;p>o;o++)k=n[o],l=k.coreId,m=g[l],m||(m=[],g[l]=m,h.push(m),i.push(this._chunkFactory.getChunk(k.stateId,"renderTarget",b.program,k))),m.push(b);else this._objectDrawList[this._objectDrawListLen++]=b;for(var m,k,b,q,a=0,j=h.length;j>a;a++){m=h[a],k=i[a],this._appendRenderTargetChunk(k);for(var o=0,p=m.length;p>o;o++)b=m[o],q=b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q)}b&&this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1,"renderTarget",b.program,{}));for(var a=0,j=this._objectDrawListLen;j>a;a++)b=this._objectDrawList[a],q=!b.stage||b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q);this.drawListDirty=!1},SceneJS_Display.prototype._appendRenderTargetChunk=function(a){this._drawList[this._drawListLen++]=a},SceneJS_Display.prototype._appendObjectToDrawLists=function(a,b){for(var c,d=a.chunks,e=a.flags.picking,f=0,g=d.length;g>f;f++)c=d[f],c&&(c.draw&&(c.unique||this._lastStateId[f]!=c.id)&&(this._drawList[this._drawListLen++]=c,this._lastStateId[f]=c.id),c.pick&&b!==!1&&e&&(c.unique||this._lastPickStateId[f]!=c.id)&&(this._pickDrawList[this._pickDrawListLen++]=c,this._lastPickStateId[f]=c.id))},SceneJS_Display.prototype._logDrawList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._drawListLen+" draw list chunks");for(var a=0,b=this._drawListLen;b>a;a++){var c=this._drawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._logPickList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._pickDrawListLen+" pick list chunks");for(var a=0,b=this._pickDrawListLen;b>a;a++){var c=this._pickDrawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype.pick=function(a){var b=this._canvas.canvas,c=this._canvas.ssaaMultiplier,d=null,e=a.canvasX*c,f=a.canvasY*c,g=this.pickBuf;g||(g=this.pickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.pickBufDirty=!0),this.render(),g.bind(),this.pickBufDirty&&(g.clear(),this._doDrawList({pick:!0,clear:!0}),this._canvas.gl.finish(),this.pickBufDirty=!1,this.rayPickBufDirty=!0);var h=g.read(e,f),i=h[0]+256*h[1]+65536*h[2],j=i>=1?i-1:-1;g.unbind();var k=this._frameCtx.pickNames[j];if(k&&(d={name:k.name,path:k.path,nodeId:k.nodeId,canvasPos:[e,f]},a.rayPick)){var l=this.rayPickBuf;l||(l=this.rayPickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.rayPickBufDirty=!0),l.bind(),this.rayPickBufDirty&&(l.clear(),this._doDrawList({pick:!0,rayPick:!0,clear:!0}),this.rayPickBufDirty=!1),h=l.read(e,f),l.unbind();var m=this._unpackDepth(h),n=b.width,o=b.height,p=(e-n/2)/(n/2),q=-(f-o/2)/(o/2),r=this._frameCtx.cameraMat,s=this._frameCtx.viewMat,t=SceneJS_math_mulMat4(r,s,[]),u=SceneJS_math_inverseMat4(t,[]),v=SceneJS_math_transformVector4(u,[p,q,-1,1]);v=SceneJS_math_mulVec4Scalar(v,1/v[3]);var w=SceneJS_math_transformVector4(u,[p,q,1,1]);w=SceneJS_math_mulVec4Scalar(w,1/w[3]);var x=SceneJS_math_subVec3(w,v,[]),y=SceneJS_math_addVec3(v,SceneJS_math_mulVec4Scalar(x,m,[]),[]);d.worldPos=y}return d},SceneJS_Display.prototype.readPixels=function(a,b){this._readPixelBuf||(this._readPixelBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas})),this._readPixelBuf.bind(),this._readPixelBuf.clear(),this.render({force:!0});for(var c,d,e=0;b>e;e++)c=a[e]||(a[e]={}),d=this._readPixelBuf.read(c.x,c.y),c.r=d[0],c.g=d[1],c.b=d[2],c.a=d[3];this._readPixelBuf.unbind()},SceneJS_Display.prototype._unpackDepth=function(a){var b=[a[0]/256,a[1]/256,a[2]/256,a[3]/256],c=[1/16777216,1/65536,1/256,1];return SceneJS_math_dotVector4(b,c)},SceneJS_Display.prototype._doDrawList=function(a){var b=this._canvas.gl,c=this._frameCtx;c.renderTarget=null,c.targetIndex=0,c.renderBuf=null,c.viewMat=null,c.modelMat=null,c.cameraMat=null,c.renderer=null,c.depthbufEnabled=null,c.clearDepth=null,c.depthFunc=b.LESS,c.scissorTestEnabled=!1,c.blendEnabled=!1,c.backfaces=!0,c.frontface="ccw",c.pick=!!a.pick,c.rayPick=!!a.rayPick,c.pickIndex=0,c.textureUnit=0,c.lineWidth=1,c.transparent=!1,c.ambientColor=this._ambientColor,c.aspect=this._canvas.canvas.width/this._canvas.canvas.height,this._canvas.UINT_INDEX_ENABLED&&b.getExtension("OES_element_index_uint");var d=b.getExtension("OES_vertex_array_object");if(c.VAO=d?d:null,b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),this.transparent?b.clearColor(0,0,0,0):b.clearColor(this._ambientColor[0],this._ambientColor[1],this._ambientColor[2],1),a.clear&&b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),b.frontFace(b.CCW),b.disable(b.CULL_FACE),b.disable(b.BLEND),a.pick)for(var e=0,f=this._pickDrawListLen;f>e;e++)this._pickDrawList[e].pick(c);else for(var e=0,f=this._drawListLen;f>e;e++)this._drawList[e].draw(c);if(b.flush(),c.renderBuf&&c.renderBuf.unbind(),c.VAO){c.VAO.bindVertexArrayOES(null);for(var e=0;10>e;e++)b.disableVertexAttribArray(e)}},SceneJS_Display.prototype.destroy=function(){this._programFactory.destroy()};var SceneJS_ProgramSourceFactory=new function(){function a(a){if(a.renderTarget&&a.renderTarget.targets)for(var b=a.renderTarget.targets,c=0,d=b.length;d>c;c++)if("depth"===b[c].bufType)return!0;return!1}this._sourceCache={},this.getSource=function(a,b){var c=this._sourceCache[a];return c?(c.useCount++,c):this._sourceCache[a]=new SceneJS_ProgramSource(a,this._composePickingVertexShader(b),this._composePickingFragmentShader(b),this._composeRenderingVertexShader(b),this._composeRenderingFragmentShader(b))},this.putSource=function(a){var b=this._sourceCache[a];b&&0==--b.useCount&&(this._sourceCache[b.hash]=null)},this._composePickingVertexShader=function(a){var b=!!a.morphGeometry.targets,c=["precision mediump float;","attribute vec3 SCENEJS_aVertex;","uniform mat4 SCENEJS_uMMatrix;","uniform mat4 SCENEJS_uVMatrix;","uniform mat4 SCENEJS_uVNMatrix;","uniform mat4 SCENEJS_uPMatrix;"];return c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),b&&(c.push("uniform float SCENEJS_uMorphFactor;"),a.morphGeometry.targets[0].vertexBuf&&c.push("attribute vec3 SCENEJS_aMorphVertex;")),c.push("void main(void) {"),c.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "),b&&a.morphGeometry.targets[0].vertexBuf&&c.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "),c.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "),c.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"),c.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"),c.push("}"),c},this._composePickingFragmentShader=function(a){var b=a.clips.clips.length>0,c=["precision mediump float;"];if(c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),c.push("uniform bool SCENEJS_uRayPickMode;"),c.push("uniform vec3 SCENEJS_uPickColor;"),c.push("uniform float SCENEJS_uZNear;"),c.push("uniform float SCENEJS_uZFar;"),c.push("uniform bool SCENEJS_uClipping;"),b)for(var d=0;d 0.0) { discard; }"),c.push("}")}return c.push(" if (SCENEJS_uRayPickMode) {"),c.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"),c.push(" gl_FragColor = packDepth(zNormalizedDepth); "),c.push(" } else {"),c.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "),c.push(" }"),c.push("}"),c},this._isTexturing=function(a){if(a.texture.layers&&a.texture.layers.length>0){if(a.geometry.uvBuf||a.geometry.uvBuf2)return!0;if(a.morphGeometry.targets&&(a.morphGeometry.targets[0].uvBuf||a.morphGeometry.targets[0].uvBuf2))return!0}return!1},this._isCubeMapping=function(a){return a.flags.reflective&&a.cubemap.layers&&a.cubemap.layers.length>0&&a.geometry.normalBuf},this._hasNormals=function(a){return a.geometry.normalBuf?!0:a.morphGeometry.targets&&a.morphGeometry.targets[0].normalBuf?!0:!1},this._hasTangents=function(a){if(a.texture){var b=a.texture.layers;if(!b)return!1;for(var c=0,d=b.length;d>c;c++)if("normals"==b[c].applyTo)return!0}return!1},this._composeRenderingVertexShader=function(a){var b=a.shader.shaders||{};if(b.vertex&&b.vertex.code&&""!=b.vertex.code&&SceneJS._isEmpty(b.vertex.hooks))return[b.vertex.code];var c=b.vertex||{},d=c.hooks||{},e=b.fragment||{},f=e.hooks||{},g=this._isTexturing(a),h=this._hasNormals(a),i=this._hasTangents(a),j=a.clips.clips.length>0,k=!!a.morphGeometry.targets,l=["precision mediump float;"];if(l.push("uniform mat4 SCENEJS_uMMatrix;"),l.push("uniform mat4 SCENEJS_uVMatrix;"),l.push("uniform mat4 SCENEJS_uPMatrix;"),l.push("attribute vec3 SCENEJS_aVertex;"),l.push("uniform vec3 SCENEJS_uWorldEye;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("attribute vec3 SCENEJS_aNormal;"),l.push("uniform mat4 SCENEJS_uMNMatrix;"),l.push("uniform mat4 SCENEJS_uVNMatrix;"),l.push("varying vec3 SCENEJS_vViewNormal;"),i&&l.push("attribute vec4 SCENEJS_aTangent;");for(var m=0;m0,l=["\n"];if(l.push("precision mediump float;"),k&&l.push("varying vec4 SCENEJS_vWorldVertex;"),l.push("varying vec4 SCENEJS_vViewVertex;"),l.push("uniform float SCENEJS_uZNear;"),l.push("uniform float SCENEJS_uZFar;"),k)for(var m=0;mm;m++)n=b.texture.layers[m],l.push("uniform sampler2D SCENEJS_uSampler"+m+";"),n.matrix&&l.push("uniform mat4 SCENEJS_uLayer"+m+"Matrix;"),l.push("uniform float SCENEJS_uLayer"+m+"BlendFactor;")}if(h&&g)for(var n,m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("uniform samplerCube SCENEJS_uCubeMapSampler"+m+";"),l.push("uniform float SCENEJS_uCubeMapIntensity"+m+";");if(l.push("uniform bool SCENEJS_uClipping;"),l.push("uniform bool SCENEJS_uSolid;"),l.push("uniform bool SCENEJS_uDepthMode;"),l.push("uniform bool SCENEJS_uTransparent;"),b.geometry.colorBuf&&l.push("varying vec4 SCENEJS_vColor;"),l.push("uniform vec3 SCENEJS_uAmbientColor;"),l.push("uniform vec3 SCENEJS_uMaterialColor;"),l.push("uniform float SCENEJS_uMaterialAlpha;"),l.push("uniform float SCENEJS_uMaterialEmit;"),l.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"),l.push("uniform float SCENEJS_uMaterialSpecular;"),l.push("uniform float SCENEJS_uMaterialShine;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("varying vec3 SCENEJS_vViewNormal;");for(var p,m=0;m 0.0) { discard; }"),l.push("}")}h&&i&&(l.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"),l.push(" if (a < 0.0) {"),l.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"),l.push(" return;"),l.push(" }")),l.push(" vec3 ambient= SCENEJS_uAmbientColor;"),f&&b.geometry.uvBuf&&e.texturePos&&l.push(e.texturePos+"(SCENEJS_vUVCoord);"),e.viewPos&&l.push(e.viewPos+"(SCENEJS_vViewVertex);"),h&&e.viewNormal&&l.push(e.viewNormal+"(SCENEJS_vViewNormal);"),b.geometry.colorBuf?l.push(" vec3 color = SCENEJS_vColor.rgb;"):l.push(" vec3 color = SCENEJS_uMaterialColor;"),l.push(" float alpha = SCENEJS_uMaterialAlpha;"),l.push(" float emit = SCENEJS_uMaterialEmit;"),l.push(" float specular = SCENEJS_uMaterialSpecular;"),l.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"),l.push(" float shine = SCENEJS_uMaterialShine;"),e.materialBaseColor&&l.push("color="+e.materialBaseColor+"(color);"),e.materialAlpha&&l.push("alpha="+e.materialAlpha+"(alpha);"),e.materialEmit&&l.push("emit="+e.materialEmit+"(emit);"),e.materialSpecular&&l.push("specular="+e.materialSpecular+"(specular);"),e.materialSpecularColor&&l.push("specularColor="+e.materialSpecularColor+"(specularColor);"),e.materialShine&&l.push("shine="+e.materialShine+"(shine);"),h&&(l.push(" float attenuation = 1.0;"),j?l.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"):l.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"));var n;if(f){l.push(" vec4 texturePos;"),l.push(" vec2 textureCoord=vec2(0.0,0.0);");for(var m=0,o=b.texture.layers.length;o>m;m++){if(n=b.texture.layers[m],"normal"==n.applyFrom&&h){if(!b.geometry.normalBuf){SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors");continue}l.push("texturePos=vec4(viewNormalVec.xyz, 1.0);")}if("uv"==n.applyFrom){if(!b.geometry.uvBuf){SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);")}if("uv2"==n.applyFrom){if(!b.geometry.uvBuf2){SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);")}n.matrix?l.push("textureCoord=(SCENEJS_uLayer"+m+"Matrix * texturePos).xy;"):l.push("textureCoord=texturePos.xy;"),"alpha"==n.applyTo&&("multiply"==n.blendMode?l.push("alpha = alpha * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"):"add"==n.blendMode&&l.push("alpha = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * alpha) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);")),"baseColor"==n.applyTo&&("multiply"==n.blendMode?l.push("color = color * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"):l.push("color = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * color) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);")),"emit"==n.applyTo&&("multiply"==n.blendMode?l.push("emit = emit * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("emit = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * emit) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"specular"==n.applyTo&&h&&("multiply"==n.blendMode?l.push("specular = specular * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("specular = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * specular) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"shine"==n.applyTo&&("multiply"==n.blendMode?l.push("shine = shine * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("shine = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * shine) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"normals"==n.applyTo&&h&&l.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);")}}if(h&&g){l.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"),l.push("envLookup.y = envLookup.y * -1.0;"),l.push("vec4 envColor;");for(var m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("envColor = textureCube(SCENEJS_uCubeMapSampler"+m+", envLookup);"),l.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity"+m+");")}if(l.push(" vec4 fragColor;"),h){l.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 viewLightVec;"),l.push(" float dotN;"),l.push(" float lightDist;");for(var p,m=0,o=b.lights.lights.length;o>m;m++)p=b.lights.lights[m],"ambient"!=p.mode&&(l.push("viewLightVec = SCENEJS_vViewLightVecAndDist"+m+".xyz;"),"point"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),l.push("lightDist = SCENEJS_vViewLightVecAndDist"+m+".w;"),l.push("attenuation = 1.0 - ( SCENEJS_uLightAttenuation"+m+"[0] + SCENEJS_uLightAttenuation"+m+"[1] * lightDist + SCENEJS_uLightAttenuation"+m+"[2] * lightDist * lightDist);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+" * attenuation;"),p.specular&&l.push(" specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;")),"dir"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+";"),p.specular&&l.push("specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);")));l.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);")}else l.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);");return e.pixelColor&&l.push("fragColor="+e.pixelColor+"(fragColor);"),a(b)?(l.push(" if (SCENEJS_uDepthMode) {"),l.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"),l.push(" const vec4 bias = vec4(1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 0.0);"),l.push(" float r = depth;"),l.push(" float g = fract(r * 255.0);"),l.push(" float b = fract(g * 255.0);"),l.push(" float a = fract(b * 255.0);"),l.push(" vec4 colour = vec4(r, g, b, a);"),l.push(" gl_FragColor = colour - (colour.yzww * bias);"),l.push(" } else {"),l.push(" gl_FragColor = fragColor;"),l.push(" };")):l.push(" gl_FragColor = fragColor;"),l.push("}"),l}},SceneJS_ProgramSource=function(a,b,c,d,e){this.hash=a,this.pickVertexSrc=b,this.pickFragmentSrc=c,this.drawVertexSrc=d,this.drawFragmentSrc=e,this.useCount=0},SceneJS_ProgramFactory=function(a){this._canvas=a.canvas,this._programs={},this._nextProgramId=0};SceneJS_ProgramFactory.prototype.getProgram=function(a,b){var c=this._programs[a];if(!c){var d=SceneJS_ProgramSourceFactory.getSource(a,b);c=new SceneJS_Program(this._nextProgramId++,a,d,this._canvas.gl),this._programs[a]=c}return c.useCount++,c},SceneJS_ProgramFactory.prototype.putProgram=function(a){--a.useCount<=0&&(a.draw.destroy(),a.pick.destroy(),SceneJS_ProgramSourceFactory.putSource(a.hash),delete this._programs[a.hash])},SceneJS_ProgramFactory.prototype.webglRestored=function(){var a,b=this._canvas.gl;for(var c in this._programs)this._programs.hasOwnProperty(c)&&(a=this._programs[c],a&&a.build&&a.build(b))},SceneJS_ProgramFactory.prototype.destroy=function(){};var SceneJS_Program=function(a,b,c,d){this.id=a,this.hash=c.hash,this.source=c,this.gl=d,this.UINT_INDEX_ENABLED=!!d.getExtension("OES_element_index_uint"),this.draw=null,this.pick=null,this.useCount=0,this.build(d)};SceneJS_Program.prototype.build=function(a){this.gl=a,this.draw=new SceneJS._webgl.Program(a,[this.source.drawVertexSrc.join("\n")],[this.source.drawFragmentSrc.join("\n")]),this.pick=new SceneJS._webgl.Program(a,[this.source.pickVertexSrc.join("\n")],[this.source.pickFragmentSrc.join("\n")])};var SceneJS_ObjectFactory=function(){};SceneJS_ObjectFactory.prototype._freeObjects=[],SceneJS_ObjectFactory.prototype._numFreeObjects=0,SceneJS_ObjectFactory.prototype.getObject=function(a){ +var b;return this._numFreeObjects>0?(b=this._freeObjects[--this._numFreeObjects],b.id=a,b):new SceneJS_Object(a)},SceneJS_ObjectFactory.prototype.putObject=function(a){this._freeObjects[this._numFreeObjects++]=a};var SceneJS_Object=function(a){this.id=a,this.hash=null,this.sortKey=null,this.chunks=[],this.chunksLen=0,this.program=null,this.layer=null,this.texture=null,this.flags=null,this.tag=null};SceneJS.RenderContext=function(a){this._frameCtx=a},SceneJS.RenderContext.prototype.getCameraMatrix=function(){return this._frameCtx.cameraMat},SceneJS.RenderContext.prototype.getViewMatrix=function(){return this._frameCtx.viewMat},SceneJS.RenderContext.prototype.getModelMatrix=function(){return this._frameCtx.modelMat},SceneJS.RenderContext.prototype.getCanvasPos=function(a){this.getProjPos(a);var b=this._frameCtx.canvas.canvas,c=this._frameCtx.canvas.ssaaMultiplier,d=b.width/c,e=b.height/c,f=this._pc,g=f[0]/f[3]*d*.5,h=f[1]/f[3]*e*.5;return{x:g+.5*d,y:e-h-.5*e}},SceneJS.RenderContext.prototype.getCameraPos=function(a){return this.getProjPos(a),this._camPos=SceneJS_math_normalizeVec3(this._pc,[0,0,0]),{x:this._camPos[0],y:this._camPos[1],z:this._camPos[2]}},SceneJS.RenderContext.prototype.getProjPos=function(a){return this.getViewPos(a),this._pc=SceneJS_math_transformPoint3(this._frameCtx.cameraMat,this._vc),{x:this._pc[0],y:this._pc[1],z:this._pc[2],w:this._pc[3]}},SceneJS.RenderContext.prototype.getViewPos=function(a){return this.getWorldPos(a),this._vc=SceneJS_math_transformPoint3(this._frameCtx.viewMat,this._wc),{x:this._vc[0],y:this._vc[1],z:this._vc[2],w:this._vc[3]}},SceneJS.RenderContext.prototype.getWorldPos=function(a){return this._wc=SceneJS_math_transformPoint3(this._frameCtx.modelMat,a||[0,0,0]),{x:this._wc[0],y:this._wc[1],z:this._wc[2],w:this._wc[3]}};var SceneJS_Chunk=function(){};SceneJS_Chunk.prototype.init=function(a,b,c,d){this.id=a,this.program=b,this.core=c,this.core2=d,this.build&&this.build()};var SceneJS_ChunkFactory=function(){this._chunks={},this.chunkTypes=SceneJS_ChunkFactory.chunkTypes};SceneJS_ChunkFactory.chunkTypes={},SceneJS_ChunkFactory._freeChunks={},SceneJS_ChunkFactory.createChunkType=function(a){if(!a.type)throw"'type' expected in params";var b=SceneJS_Chunk,c=function(){this.useCount=0,this.init.apply(this,arguments)};return c.prototype=new b,c.prototype.constructor=c,a.drawAndPick&&(a.draw=a.pick=a.drawAndPick),SceneJS_ChunkFactory.chunkTypes[a.type]=c,SceneJS._apply(a,c.prototype),SceneJS_ChunkFactory._freeChunks[a.type]={chunks:[],chunksLen:0},c},SceneJS_ChunkFactory.prototype.getChunk=function(a,b,c,d,e){var f=SceneJS_ChunkFactory.chunkTypes[b];if(!f)throw"chunk type not supported: '"+b+"'";var g=this._chunks[a];if(g)return g.useCount++,g;var h=SceneJS_ChunkFactory._freeChunks[b];return h.chunksLen>0&&(g=h.chunks[--h.chunksLen]),g?g.init(a,c,d,e):g=new f(a,c,d,e),g.type=b,g.useCount=1,this._chunks[a]=g,g},SceneJS_ChunkFactory.prototype.putChunk=function(a){if(0!=a.useCount&&--a.useCount<=0){a.recycle&&a.recycle(),delete this._chunks[a.id];var b=SceneJS_ChunkFactory._freeChunks[a.type];b.chunks[b.chunksLen++]=a}},SceneJS_ChunkFactory.prototype.webglRestored=function(){var a;for(var b in this._chunks)this._chunks.hasOwnProperty(b)&&(a=this._chunks[b],a&&a.build&&a.build())},SceneJS_ChunkFactory.createChunkType({type:"camera",build:function(){this._uPMatrixDraw=this.program.draw.getUniform("SCENEJS_uPMatrix"),this._uZNearDraw=this.program.draw.getUniform("SCENEJS_uZNear"),this._uZFarDraw=this.program.draw.getUniform("SCENEJS_uZFar"),this._uPMatrixPick=this.program.pick.getUniform("SCENEJS_uPMatrix"),this._uZNearPick=this.program.pick.getUniform("SCENEJS_uZNear"),this._uZFarPick=this.program.pick.getUniform("SCENEJS_uZFar")},draw:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixDraw&&this._uPMatrixDraw.setValue(this.core.mat),this._uZNearDraw&&this._uZNearDraw.setValue(this.core.optics.near),this._uZFarDraw&&this._uZFarDraw.setValue(this.core.optics.far),a.cameraMat=this.core.mat},pick:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixPick&&this._uPMatrixPick.setValue(this.core.mat),a.rayPick&&(this._uZNearPick&&this._uZNearPick.setValue(this.core.optics.near),this._uZFarPick&&this._uZFarPick.setValue(this.core.optics.far)),a.cameraMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"clips",build:function(){this._draw=this._draw||[];for(var a=this.program.draw,b=0,c=this.core.clips.length;c>b;b++)this._draw[b]={uClipMode:a.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:a.getUniform("SCENEJS_uClipNormalAndDist"+b)};this._pick=this._pick||[];for(var d=this.program.pick,b=0,c=this.core.clips.length;c>b;b++)this._pick[b]={uClipMode:d.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:d.getUniform("SCENEJS_uClipNormalAndDist"+b)}},drawAndPick:function(a){for(var b,c,d,e=a.pick?this._pick:this._draw,f=this.core.clips,g=(this.program.gl,0),h=f.length;h>g;g++)a.pick?(b=e[g].uClipMode,c=e[g].uClipNormalAndDist):(b=e[g].uClipMode,c=e[g].uClipNormalAndDist),b&&c&&(d=f[g],"inside"==d.mode?(b.setValue(2),c.setValue(d.normalAndDist)):"outside"==d.mode?(b.setValue(1),c.setValue(d.normalAndDist)):b.setValue(0))}}),SceneJS_ChunkFactory.createChunkType({type:"draw",unique:!0,build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode")},drawAndPick:function(a){var b=this.program.gl,c=this.program.UINT_INDEX_ENABLED?b.UNSIGNED_INT:b.UNSIGNED_SHORT;a.pick?this._depthModePick&&this._depthModePick.setValue(a.depthMode):this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),b.drawElements(this.core.primitive,this.core.indexBuf.numItems,c,0)}}),SceneJS_ChunkFactory.createChunkType({type:"flags",build:function(){var a=this.program.draw;this._uClippingDraw=a.getUniform("SCENEJS_uClipping"),this._uSolidDraw=a.getUniform("SCENEJS_uSolid");var b=this.program.pick;this._uClippingPick=b.getUniform("SCENEJS_uClipping")},drawAndPick:function(a){var b=this.program.gl,c=this.core.backfaces;a.backfaces!=c&&(c?b.disable(b.CULL_FACE):b.enable(b.CULL_FACE),a.backfaces=c);var d=this.core.frontface;a.frontface!=d&&("ccw"==d?b.frontFace(b.CCW):b.frontFace(b.CW),a.frontface=d);var e=this.core.transparent;a.transparent!=e&&(a.pick||(e?(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA),a.blendEnabled=!0):(b.disable(b.BLEND),a.blendEnabled=!1)),a.transparent=e),a.pick?this._uClippingPick&&this._uClippingPick.setValue(this.core.clipping):(this._uClippingDraw&&this._uClippingDraw.setValue(this.core.clipping),this._uSolidDraw&&this._uSolidDraw.setValue(this.core.solid))}}),SceneJS_ChunkFactory.createChunkType({type:"renderTarget",programGlobal:!0,draw:function(a){var b=this.program.gl;a.renderBuf&&(b.flush(),a.renderBuf.unbind(),a.renderBuf=null);var c=this.core.renderBuf;return c?(c.bind(),a.depthMode="depth"===this.core.bufType,a.depthMode||a.blendEnabled&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA)),b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),b.clearColor(a.ambientColor[0],a.ambientColor[1],a.ambientColor[2],1),b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),void(a.renderBuf=c)):void(a.depthMode=!1)}}),SceneJS_ChunkFactory.createChunkType({type:"geometry",build:function(){var a=this.program.draw;this._aVertexDraw=a.getAttribute("SCENEJS_aVertex"),this._aNormalDraw=a.getAttribute("SCENEJS_aNormal"),this._aUVDraw=a.getAttribute("SCENEJS_aUVCoord"),this._aUV2Draw=a.getAttribute("SCENEJS_aUVCoord2"),this._aTangentDraw=a.getAttribute("SCENEJS_aTangent"),this._aColorDraw=a.getAttribute("SCENEJS_aVertexColor"),this._aMorphVertexDraw=a.getAttribute("SCENEJS_aMorphVertex"),this._aMorphNormalDraw=a.getAttribute("SCENEJS_aMorphNormal"),this._uMorphFactorDraw=a.getUniform("SCENEJS_uMorphFactor");var b=this.program.pick;this._aVertexPick=b.getAttribute("SCENEJS_aVertex"),this._aMorphVertexPick=b.getAttribute("SCENEJS_aMorphVertex"),this._uMorphFactorPick=b.getUniform("SCENEJS_uMorphFactor"),this.VAO=null,this.VAOMorphKey1=0,this.VAOMorphKey2=0,this.VAOHasInterleavedBuf=!1},recycle:function(){if(this.VAO){var a=this.program.gl.getExtension("OES_vertex_array_object");a.deleteVertexArrayOES(this.VAO),this.VAO=null}},morphDraw:function(){this.VAOMorphKey1=this.core.key1,this.VAOMorphKey2=this.core.key2;var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexDraw?(this._aVertexDraw.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexDraw.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aMorphNormalDraw?(this._aNormalDraw.bindFloatArrayBuffer(a.normalBuf),this._aMorphNormalDraw.bindFloatArrayBuffer(b.normalBuf)):this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this.setDrawMorphFactor()},setDrawMorphFactor:function(){this._uMorphFactorDraw&&this._uMorphFactorDraw.setValue*this.core.factor},draw:function(a){var b=this.core.targets&&this.core.targets.length,c=this.core2.interleavedBuf&&!this.core2.interleavedBuf.dirty;if(this.VAO){if(a.VAO.bindVertexArrayOES(this.VAO),b){if(this.VAOMorphKey1==this.core.key1&&this.VAOMorphKey2==this.core.key2)return void this.setDrawMorphFactor()}else if(c||!this.VAOHasInterleavedBuf)return}else if(a.VAO){a.VAO.bindVertexArrayOES(null),this.VAO=a.VAO.createVertexArrayOES(),a.VAO.bindVertexArrayOES(this.VAO);this.program.gl}b?this.morphDraw():c?(this.VAOHasInterleavedBuf=!0,this.core2.interleavedBuf.bind(),this._aVertexDraw&&this._aVertexDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedPositionOffset),this._aNormalDraw&&this._aNormalDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedNormalOffset),this._aUVDraw&&this._aUVDraw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUVOffset),this._aUV2Draw&&this._aUV2Draw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUV2Offset),this._aColorDraw&&this._aColorDraw.bindInterleavedFloatArrayBuffer(4,this.core2.interleavedStride,this.core2.interleavedColorOffset),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())):(this.VAOHasInterleavedBuf=!1,this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())),this.core2.indexBuf.bind()},morphPick:function(){var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexPick?(this._aVertexPick.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexPick.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this._uMorphFactorPick&&this._uMorphFactorPick.setValue(this.core.factor)},pick:function(a){this.core.targets&&this.core.targets.length?this.morphPick():this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this.core2.indexBuf.bind()}}),SceneJS_ChunkFactory.createChunkType({type:"lights",build:function(){this._uAmbientColor=this._uAmbientColor||[],this._uLightColor=this._uLightColor||[],this._uLightDir=this._uLightDir||[],this._uLightPos=this._uLightPos||[],this._uLightCutOff=this._uLightCutOff||[],this._uLightSpotExp=this._uLightSpotExp||[],this._uLightAttenuation=this._uLightAttenuation||[];for(var a=this.core.lights,b=this.program,c=0,d=a.length;d>c;c++)switch(a[c].mode){case"ambient":this._uAmbientColor[c]=b.draw.getUniform("SCENEJS_uAmbientColor");break;case"dir":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=null,this._uLightDir[c]=b.draw.getUniform("SCENEJS_uLightDir"+c);break;case"point":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=b.draw.getUniform("SCENEJS_uLightPos"+c),this._uLightDir[c]=null,this._uLightAttenuation[c]=b.draw.getUniform("SCENEJS_uLightAttenuation"+c)}},draw:function(a){a.dirty&&this.build();for(var b,c=this.core.lights,d=(this.program.gl,0),e=c.length;e>d;d++)b=c[d],this._uAmbientColor[d]?this._uAmbientColor[d].setValue(b.color):(this._uLightColor[d]&&this._uLightColor[d].setValue(b.color),this._uLightPos[d]&&(this._uLightPos[d].setValue(b.pos),this._uLightAttenuation[d]&&this._uLightAttenuation[d].setValue(b.attenuation)),this._uLightDir[d]&&this._uLightDir[d].setValue(b.dir))}}),SceneJS_ChunkFactory.createChunkType({type:"listeners",programGlobal:!0,build:function(){},draw:function(a){for(var b=this.core.listeners,c=a.renderListenerCtx,d=b.length-1;d>=0;d--)if(b[d](c)===!0)return!0}}),SceneJS_ChunkFactory.createChunkType({type:"lookAt",build:function(){this._uvMatrixDraw=this.program.draw.getUniform("SCENEJS_uVMatrix"),this._uVNMatrixDraw=this.program.draw.getUniform("SCENEJS_uVNMatrix"),this._uWorldEyeDraw=this.program.draw.getUniform("SCENEJS_uWorldEye"),this._uvMatrixPick=this.program.pick.getUniform("SCENEJS_uVMatrix")},draw:function(a){this.core.dirty&&this.core.rebuild();this.program.gl;this._uvMatrixDraw&&this._uvMatrixDraw.setValue(this.core.mat),this._uVNMatrixDraw&&this._uVNMatrixDraw.setValue(this.core.normalMat),this._uWorldEyeDraw&&this._uWorldEyeDraw.setValue(this.core.lookAt.eye),a.viewMat=this.core.mat},pick:function(a){this.program.gl;this._uvMatrixPick&&this._uvMatrixPick.setValue(this.core.mat),a.viewMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"material",build:function(){var a=this.program.draw;this._uMaterialBaseColor=a.getUniform("SCENEJS_uMaterialColor"),this._uMaterialSpecularColor=a.getUniform("SCENEJS_uMaterialSpecularColor"),this._uMaterialSpecular=a.getUniform("SCENEJS_uMaterialSpecular"),this._uMaterialShine=a.getUniform("SCENEJS_uMaterialShine"),this._uMaterialEmit=a.getUniform("SCENEJS_uMaterialEmit"),this._uMaterialAlpha=a.getUniform("SCENEJS_uMaterialAlpha")},draw:function(){this.program.gl;this._uMaterialBaseColor&&this._uMaterialBaseColor.setValue(this.core.baseColor),this._uMaterialSpecularColor&&this._uMaterialSpecularColor.setValue(this.core.specularColor),this._uMaterialSpecular&&this._uMaterialSpecular.setValue(this.core.specular),this._uMaterialShine&&this._uMaterialShine.setValue(this.core.shine),this._uMaterialEmit&&this._uMaterialEmit.setValue(this.core.emit),this._uMaterialAlpha&&this._uMaterialAlpha.setValue(this.core.alpha)}}),SceneJS_ChunkFactory.createChunkType({type:"name",build:function(){this._uPickColor=this.program.pick.getUniform("SCENEJS_uPickColor")},pick:function(a){if(this._uPickColor&&this.core.name){a.pickNames[a.pickIndex++]=this.core;var b=a.pickIndex>>16&255,c=a.pickIndex>>8&255,d=255&a.pickIndex;this._uPickColor.setValue([d/255,c/255,b/255])}}}),SceneJS_ChunkFactory.createChunkType({type:"program",build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode"),this._rayPickMode=this.program.pick.getUniform("SCENEJS_uRayPickMode")},draw:function(a){var b=this.program.draw;b.bind(),a.textureUnit=0;var c=this.program.gl;if(this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),!a.VAO)for(var d=0;10>d;d++)c.disableVertexAttribArray(d);a.drawProgram=this.program.draw},pick:function(a){var b=this.program.pick;b.bind();var c=this.program.gl;this._rayPickMode&&this._rayPickMode.setValue(a.rayPick),this._depthModePick&&this._depthModePick.setValue(a.depthMode),a.textureUnit=0;for(var d=0;10>d;d++)c.disableVertexAttribArray(d)}}),SceneJS_ChunkFactory.createChunkType({type:"renderer",build:function(){},drawAndPick:function(a){if(this.core.props){var b=this.program.gl;a.renderer&&(a.renderer.props.restoreProps(b),a.renderer=this.core),this.core.props.setProps(b)}}}),SceneJS_ChunkFactory.createChunkType({type:"depthBuffer",programGlobal:!0,drawAndPick:function(a){var b=this.program.gl,c=this.core.enabled;a.depthbufEnabled!=c&&(c?b.enable(b.DEPTH_TEST):b.disable(b.DEPTH_TEST),a.depthbufEnabled=c);var d=this.core.clearDepth;a.clearDepth!=d&&(b.clearDepth(d),a.clearDepth=d);var e=this.core.depthFunc;a.depthFunc!=e&&(b.depthFunc(e),a.depthFunc=e),this.core.clear&&b.clear(b.DEPTH_BUFFER_BIT)}}),SceneJS_ChunkFactory.createChunkType({type:"colorBuffer",programGlobal:!0,build:function(){},drawAndPick:function(a){if(!a.transparent){var b=this.core.blendEnabled,c=this.program.gl;a.blendEnabled!=b&&(b?c.enable(c.BLEND):c.disable(c.BLEND),a.blendEnabled=b);var d=this.core.colorMask;c.colorMask(d.r,d.g,d.b,d.a)}}}),SceneJS_ChunkFactory.createChunkType({type:"view",programGlobal:!0,build:function(){},drawAndPick:function(a){var b=this.core.scissorTestEnabled;if(a.scissorTestEnabled!=b){var c=this.program.gl;b?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST),a.scissorTestEnabled=b}}}),SceneJS_ChunkFactory.createChunkType({type:"shader",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"shaderParams",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"style",programGlobal:!0,drawAndPick:function(a){var b=this.core.lineWidth;if(a.lineWidth!=b){var c=this.program.gl;c.lineWidth(b),a.lineWidth=b}}}),SceneJS_ChunkFactory.createChunkType({type:"texture",build:function(){this._uTexSampler=this._uTexSampler||[],this._uTexMatrix=this._uTexMatrix||[],this._uTexBlendFactor=this._uTexBlendFactor||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uTexSampler[d]="SCENEJS_uSampler"+d,this._uTexMatrix[d]=c.getUniform("SCENEJS_uLayer"+d+"Matrix"),this._uTexBlendFactor[d]=c.getUniform("SCENEJS_uLayer"+d+"BlendFactor")},draw:function(a){a.textureUnit=0;var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uTexSampler[e]&&c.texture&&(d.bindTexture(this._uTexSampler[e],c.texture,a.textureUnit++),c._matrixDirty&&c.buildMatrix&&c.buildMatrix.call(c),this._uTexMatrix[e]&&this._uTexMatrix[e].setValue(c.matrixAsArray),this._uTexBlendFactor[e]&&this._uTexBlendFactor[e].setValue(c.blendFactor));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"cubemap",build:function(){this._uCubeMapSampler=this._uCubeMapSampler||[],this._uCubeMapIntensity=this._uCubeMapIntensity||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uCubeMapSampler[d]="SCENEJS_uCubeMapSampler"+d,this._uCubeMapIntensity[d]=c.getUniform("SCENEJS_uCubeMapIntensity"+d)},draw:function(a){var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uCubeMapSampler[e]&&c.texture&&(d.bindTexture(this._uCubeMapSampler[e],c.texture,a.textureUnit++),this._uCubeMapIntensity[e]&&this._uCubeMapIntensity[e].setValue(c.intensity));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"xform",build:function(){var a=this.program.draw;this._uMatLocationDraw=a.getUniform("SCENEJS_uMMatrix"),this._uNormalMatLocationDraw=a.getUniform("SCENEJS_uMNMatrix");var b=this.program.pick;this._uMatLocationPick=b.getUniform("SCENEJS_uMMatrix")},draw:function(a){(SceneJS_configsModule.configs.forceXFormCoreRebuild===!0||this.core.dirty&&this.core.build)&&this.core.build();this.program.gl;this._uMatLocationDraw&&this._uMatLocationDraw.setValue(this.core.mat),this._uNormalMatLocationDraw&&this._uNormalMatLocationDraw.setValue(this.core.normalMat),a.modelMat=this.core.mat},pick:function(a){this.core.dirty&&this.core.build();this.program.gl;this._uMatLocationPick&&this._uMatLocationPick.setValue(this.core.mat),a.modelMat=this.core.mat}}); \ No newline at end of file From e861d175d57434fe7e102d97424d09c2faba9a1c Mon Sep 17 00:00:00 2001 From: xeolabs Date: Thu, 11 Jun 2015 11:46:52 +0200 Subject: [PATCH 10/14] Set flags "solid" false by default --- src/core/scene/flags.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/core/scene/flags.js b/src/core/scene/flags.js index 379e8ecf..2f059973 100644 --- a/src/core/scene/flags.js +++ b/src/core/scene/flags.js @@ -15,8 +15,8 @@ backfaces: true, // Show backfaces frontface: "ccw", // Default vertex winding for front face reflective: true, // Reflects reflection node cubemap, if it exists, by default. - solid: true, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect - hash: "refl;s;" + solid: false, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect + hash: "refl;;" }; var coreStack = []; @@ -46,7 +46,7 @@ this._core.backfaces = true; // Show backfaces this._core.frontface = "ccw"; // Default vertex winding for front face this._core.reflective = true; // Reflects reflection node cubemap, if it exists, by default. - this._core.solid = true; // Renders backfaces without texture or shading, for a cheap solid cross-section effect + this._core.solid = false; // Renders backfaces without texture or shading, for a cheap solid cross-section effect if (params.flags) { // 'flags' property is actually optional in the node definition this.setFlags(params.flags); } @@ -91,12 +91,14 @@ core.reflective = flags.reflective; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } if (flags.solid != undefined) { core.solid = flags.solid; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; @@ -211,8 +213,9 @@ reflective = !!reflective; if (this._core.reflective != reflective) { this._core.reflective = reflective; - this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";"; + this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";;"; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; }; @@ -225,8 +228,9 @@ solid = !!solid; if (this._core.solid != solid) { this._core.solid = solid; - this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s" : ";"; + this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s;" : ";;"; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; }; From f6ce3d14e7241f5aa68c577dd1f9c3df39d65fce Mon Sep 17 00:00:00 2001 From: xeolabs Date: Thu, 11 Jun 2015 11:47:20 +0200 Subject: [PATCH 11/14] Comment tweak --- src/core/webgl/uniform.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/webgl/uniform.js b/src/core/webgl/uniform.js index 62049c0e..7f754b5f 100644 --- a/src/core/webgl/uniform.js +++ b/src/core/webgl/uniform.js @@ -139,6 +139,9 @@ SceneJS._webgl.Uniform = function (gl, program, name, type, size, location, inde } else if (type === gl.FLOAT_MAT4) { func = function (v) { + + // Caching this matrix is actually slower than not caching + gl.uniformMatrix4fv(location, gl.FALSE, v); }; From 131d27375e81c6c86b2c4913eba53d377d432269 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Thu, 11 Jun 2015 11:47:37 +0200 Subject: [PATCH 12/14] Added FPS meter to two examples --- examples/benchmarks_10000boxes.html | 15 +++++++++++++++ examples/benchmarks_40000boxes.html | 25 +++++++++++++------------ 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/examples/benchmarks_10000boxes.html b/examples/benchmarks_10000boxes.html index 4df258be..52879734 100644 --- a/examples/benchmarks_10000boxes.html +++ b/examples/benchmarks_10000boxes.html @@ -73,6 +73,21 @@ // stats.update(); // }); + // Stats + + var stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.right = '0px'; + stats.domElement.style.zIndex = 100; + document.body.appendChild(stats.domElement); + scene.on("tick", + function () { + stats.end(); + stats.begin(); + }); + + diff --git a/examples/benchmarks_40000boxes.html b/examples/benchmarks_40000boxes.html index 8e68893c..5bcc4b03 100644 --- a/examples/benchmarks_40000boxes.html +++ b/examples/benchmarks_40000boxes.html @@ -59,19 +59,20 @@ ] }); + // Stats + + var stats = new Stats(); + stats.domElement.style.position = 'absolute'; + stats.domElement.style.top = '0px'; + stats.domElement.style.right = '0px'; + stats.domElement.style.zIndex = 100; + document.body.appendChild(stats.domElement); + scene.on("tick", + function () { + stats.end(); + stats.begin(); + }); - // var container = document.createElement('div'); - // document.body.appendChild(container); - // - // var stats = new Stats(); - // stats.domElement.style.position = 'absolute'; - // stats.domElement.style.top = '0px'; - // // stats.domElement.style["z-index"] = 100000; - // container.appendChild(stats.domElement); - // - // scene.on("tick", function () { - // stats.update(); - // }); From a98bec7f5be4fcfacdbe0703a71a36e66f930ca6 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Thu, 11 Jun 2015 11:47:54 +0200 Subject: [PATCH 13/14] Build --- api/latest/scenejs.js | 51 ++++++++++++++++++++++---------- api/latest/scenejs.min.js | 12 ++++---- build/4.2.0/scenejs-4.2.0.js | 51 ++++++++++++++++++++++---------- build/4.2.0/scenejs-4.2.0.min.js | 12 ++++---- 4 files changed, 84 insertions(+), 42 deletions(-) diff --git a/api/latest/scenejs.js b/api/latest/scenejs.js index 6f3ef137..39e3598e 100644 --- a/api/latest/scenejs.js +++ b/api/latest/scenejs.js @@ -4,7 +4,7 @@ * A WebGL-based 3D scene graph from xeoLabs * http://scenejs.org/ * - * Built on 2015-06-10 + * Built on 2015-06-11 * * MIT License * Copyright 2015, Lindsay Kay @@ -5971,6 +5971,9 @@ SceneJS._webgl.nextHighestPowerOfTwo = function (x) { } else if (type === gl.FLOAT_MAT4) { func = function (v) { + + // Caching this matrix is actually slower than not caching + gl.uniformMatrix4fv(location, gl.FALSE, v); }; @@ -8241,8 +8244,8 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { backfaces: true, // Show backfaces frontface: "ccw", // Default vertex winding for front face reflective: true, // Reflects reflection node cubemap, if it exists, by default. - solid: true, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect - hash: "refl;s;" + solid: false, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect + hash: "refl;;" }; var coreStack = []; @@ -8272,7 +8275,7 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { this._core.backfaces = true; // Show backfaces this._core.frontface = "ccw"; // Default vertex winding for front face this._core.reflective = true; // Reflects reflection node cubemap, if it exists, by default. - this._core.solid = true; // Renders backfaces without texture or shading, for a cheap solid cross-section effect + this._core.solid = false; // Renders backfaces without texture or shading, for a cheap solid cross-section effect if (params.flags) { // 'flags' property is actually optional in the node definition this.setFlags(params.flags); } @@ -8317,12 +8320,14 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { core.reflective = flags.reflective; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } if (flags.solid != undefined) { core.solid = flags.solid; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; @@ -8437,8 +8442,9 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { reflective = !!reflective; if (this._core.reflective != reflective) { this._core.reflective = reflective; - this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";"; + this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";;"; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; }; @@ -8451,8 +8457,9 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { solid = !!solid; if (this._core.solid != solid) { this._core.solid = solid; - this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s" : ";"; + this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s;" : ";;"; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; }; @@ -15661,7 +15668,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._sourceCache = {}; // Source codes are shared across all scenes - /** * Get sourcecode for a program to render the given states */ @@ -15698,9 +15704,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._composePickingVertexShader = function (states) { var morphing = !!states.morphGeometry.targets; var src = [ - - "precision mediump float;", - "attribute vec3 SCENEJS_aVertex;", "uniform mat4 SCENEJS_uMMatrix;", "uniform mat4 SCENEJS_uVMatrix;", @@ -15743,8 +15746,10 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = [ - "precision mediump float;" + "precision " + floatPrecision + " float;" ]; src.push("varying vec4 SCENEJS_vWorldVertex;"); @@ -15865,9 +15870,7 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; var morphing = !!states.morphGeometry.targets; - var src = [ - "precision mediump float;" - ]; + var src = []; src.push("uniform mat4 SCENEJS_uMMatrix;"); // Model matrix src.push("uniform mat4 SCENEJS_uVMatrix;"); // View matrix @@ -16165,9 +16168,11 @@ var SceneJS_ProgramSourceFactory = new (function () { var tangents = this._hasTangents(states); var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = ["\n"]; - src.push("precision mediump float;"); + src.push("precision " + floatPrecision + " float;"); if (clipping) { @@ -16577,6 +16582,22 @@ var SceneJS_ProgramSourceFactory = new (function () { return false; } + function getFSFloatPrecision(gl) { + if (!gl.getShaderPrecisionFormat) { + return "mediump"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) { + return "highp"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) { + return "mediump"; + } + + return "lowp"; + } + })();;/** * @class Source code for pick and draw shader programs, to be compiled into one or more {@link SceneJS_Program}s * @private diff --git a/api/latest/scenejs.min.js b/api/latest/scenejs.min.js index 5db1ccc7..3952cf72 100644 --- a/api/latest/scenejs.min.js +++ b/api/latest/scenejs.min.js @@ -4,7 +4,7 @@ * A WebGL-based 3D scene graph from xeoLabs * http://scenejs.org/ * - * Built on 2015-06-10 + * Built on 2015-06-11 * * MIT License * Copyright 2015, Lindsay Kay @@ -15,8 +15,8 @@ if(void 0===require){var requirejs,require,define;!function(ba){function J(a){return"[object Function]"===N.call(a)}function K(a){return"[object Array]"===N.call(a)}function z(a,b){if(a){var c;for(c=0;c-1&&(!a[c]||!b(a[c],c,a));c-=1);}}function t(a,b){return ha.call(a,b)}function m(a,b){return t(a,b)&&a[b]}function H(a,b){for(var c in a)if(t(a,c)&&b(a[c],c))break}function S(a,b,c,d){return b&&H(b,function(b,e){(c||!t(a,e))&&(d&&"string"!=typeof b?(a[e]||(a[e]={}),S(a[e],b,c,d)):a[e]=b)}),a}function v(a,b){return function(){return b.apply(a,arguments)}}function ca(a){throw a}function da(a){if(!a)return a;var b=ba;return z(a.split("."),function(a){b=b[a]}),b}function B(a,b,c,d){return b=Error(b+"\nhttp://requirejs.org/docs/errors.html#"+a),b.requireType=a,b.requireModules=d,c&&(b.originalError=c),b}function ia(a){function b(a,b,c){var d,e,f,g,h,i,j,k=b&&b.split("/");d=k;var l=C.map,n=l&&l["*"];if(a&&"."===a.charAt(0))if(b){for(d=m(C.pkgs,b)?k=[b]:k.slice(0,k.length-1),b=a=d.concat(a.split("/")),d=0;b[d];d+=1)if(e=b[d],"."===e)b.splice(d,1),d-=1;else if(".."===e){if(1===d&&(".."===b[2]||".."===b[0]))break;d>0&&(b.splice(d-1,2),d-=2)}d=m(C.pkgs,b=a[0]),a=a.join("/"),d&&a===b+"/"+d.main&&(a=b)}else 0===a.indexOf("./")&&(a=a.substring(2));if(c&&l&&(k||n)){for(b=a.split("/"),d=b.length;d>0;d-=1){if(f=b.slice(0,d).join("/"),k)for(e=k.length;e>0;e-=1)if((c=m(l,k.slice(0,e).join("/")))&&(c=m(c,f))){g=c,h=d;break}if(g)break;!i&&n&&m(n,f)&&(i=m(n,f),j=d)}!g&&i&&(g=i,h=j),g&&(b.splice(0,h,g),a=b.join("/"))}return a}function c(a){A&&z(document.getElementsByTagName("script"),function(b){return b.getAttribute("data-requiremodule")===a&&b.getAttribute("data-requirecontext")===w.contextName?(b.parentNode.removeChild(b),!0):void 0})}function d(a){var b=m(C.paths,a);return b&&K(b)&&1-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function f(a,c,d,f){var g,h,i=null,j=c?c.name:null,k=a,l=!0,n="";return a||(l=!1,a="_@r"+(M+=1)),a=e(a),i=a[0],a=a[1],i&&(i=b(i,j,f),h=m(I,i)),a&&(i?n=h&&h.normalize?h.normalize(a,function(a){return b(a,j,f)}):b(a,j,f):(n=b(a,j,f),a=e(n),i=a[0],n=a[1],d=!0,g=w.nameToUrl(n))),d=!i||h||d?"":"_unnormalized"+(N+=1),{prefix:i,name:n,parentMap:c,unnormalized:!!d,url:g,originalName:k,isDefine:l,id:(i?i+"!"+n:n)+d}}function g(a){var b=a.id,c=m(D,b);return c||(c=D[b]=new w.Module(a)),c}function i(a,b,c){var d=a.id,e=m(D,d);!t(I,d)||e&&!e.defineEmitComplete?(e=g(a),e.error&&"error"===b?c(e.error):e.on(b,c)):"defined"===b&&c(I[d])}function j(a,b){var c=a.requireModules,d=!1;b?b(a):(z(c,function(b){(b=m(D,b))&&(b.error=a,b.events.error&&(d=!0,b.emit("error",a)))}),d||h.onError(a))}function k(){U.length&&(ja.apply(G,[G.length-1,0].concat(U)),U=[])}function l(a){delete D[a],delete E[a]}function n(a,b,c){var d=a.map.id;a.error?a.emit("error",a.error):(b[d]=!0,z(a.depMaps,function(d,e){var f=d.id,g=m(D,f);g&&!a.depMatched[e]&&!c[f]&&(m(b,f)?(a.defineDep(e,I[f]),a.check()):n(g,b,c))}),c[d]=!0)}function o(){var a,b,e,f,g=(e=1e3*C.waitSeconds)&&w.startTime+e<(new Date).getTime(),h=[],i=[],k=!1,l=!0;if(!s){if(s=!0,H(E,function(e){if(a=e.map,b=a.id,e.enabled&&(a.isDefine||i.push(e),!e.error))if(!e.inited&&g)d(b)?k=f=!0:(h.push(b),c(b));else if(!e.inited&&e.fetched&&a.isDefine&&(k=!0,!a.prefix))return l=!1}),g&&h.length)return e=B("timeout","Load timeout for modules: "+h,null,h),e.contextName=w.contextName,j(e);l&&z(i,function(a){n(a,{},{})}),g&&!f||!k||!A&&!ea||y||(y=setTimeout(function(){y=0,o()},50)),s=!1}}function p(a){t(I,a[0])||g(f(a[0],null,!0)).init(a[1],a[2])}function q(a){var a=a.currentTarget||a.srcElement,b=w.onScriptLoad;return a.detachEvent&&!Z?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1),b=w.onScriptError,(!a.detachEvent||Z)&&a.removeEventListener("error",b,!1),{node:a,id:a&&a.getAttribute("data-requiremodule")}}function r(){var a;for(k();G.length;){if(a=G.shift(),null===a[0])return j(B("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));p(a)}}var s,u,w,x,y,C={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{},config:{}},D={},E={},F={},G=[],I={},L={},M=1,N=1;return x={require:function(a){return a.require?a.require:a.require=w.makeRequire(a.map)},exports:function(a){return a.usingExports=!0,a.map.isDefine?a.exports?a.exports:a.exports=I[a.map.id]={}:void 0},module:function(a){return a.module?a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){var b=m(C.pkgs,a.map.id);return(b?m(C.config,a.map.id+"/"+b.main):m(C.config,a.map.id))||{}},exports:I[a.map.id]}}},u=function(a){this.events=m(F,a.id)||{},this.map=a,this.shim=m(C.shim,a.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0},u.prototype={init:function(a,b,c,d){d=d||{},this.inited||(this.factory=b,c?this.on("error",c):this.events.error&&(c=v(this,function(a){this.emit("error",a)})),this.depMaps=a&&a.slice(0),this.errback=c,this.inited=!0,this.ignore=d.ignore,d.enabled||this.enabled?this.enable():this.check())},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0,w.startTime=(new Date).getTime();var a=this.map;if(!this.shim)return a.prefix?this.callPlugin():this.load();w.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],v(this,function(){return a.prefix?this.callPlugin():this.load()}))}},load:function(){var a=this.map.url;L[a]||(L[a]=!0,w.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var d=this.exports,e=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,1>this.depCount&&!this.defined){if(J(e)){if(this.events.error&&this.map.isDefine||h.onError!==ca)try{d=w.execCb(c,e,b,d)}catch(f){a=f}else d=w.execCb(c,e,b,d);if(this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?d=b.exports:void 0===d&&this.usingExports&&(d=this.exports)),a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",j(this.error=a)}else d=e;this.exports=d,this.map.isDefine&&!this.ignore&&(I[c]=d,h.onResourceLoad)&&h.onResourceLoad(w,this.map,this.depMaps),l(c),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,c=a.id,d=f(a.prefix);this.depMaps.push(d),i(d,"defined",v(this,function(d){var e,k;k=this.map.name;var n=this.map.parentMap?this.map.parentMap.name:null,o=w.makeRequire(a.parentMap,{enableBuildCallback:!0});this.map.unnormalized?(d.normalize&&(k=d.normalize(k,function(a){return b(a,n,!0)})||""),d=f(a.prefix+"!"+k,this.map.parentMap),i(d,"defined",v(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),(k=m(D,d.id))&&(this.depMaps.push(d),this.events.error&&k.on("error",v(this,function(a){this.emit("error",a)})),k.enable())):(e=v(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),e.error=v(this,function(a){this.inited=!0,this.error=a,a.requireModules=[c],H(D,function(a){0===a.map.id.indexOf(c+"_unnormalized")&&l(a.map.id)}),j(a)}),e.fromText=v(this,function(b,d){var i=a.name,k=f(i),l=Q;d&&(b=d),l&&(Q=!1),g(k),t(C.config,c)&&(C.config[i]=C.config[c]);try{h.exec(b)}catch(m){return j(B("fromtexteval","fromText eval for "+c+" failed: "+m,m,[c]))}l&&(Q=!0),this.depMaps.push(k),w.completeLoad(i),o([i],e)}),d.load(a.name,o,e,C))})),w.enable(d,this),this.pluginMaps[d.id]=d},enable:function(){E[this.map.id]=this,this.enabling=this.enabled=!0,z(this.depMaps,v(this,function(a,b){var c,d;if("string"==typeof a){if(a=f(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[b]=a,c=m(x,a.id))return void(this.depExports[b]=c(this));this.depCount+=1,i(a,"defined",v(this,function(a){this.defineDep(b,a),this.check()})),this.errback&&i(a,"error",v(this,this.errback))}c=a.id,d=D[c],!t(x,c)&&d&&!d.enabled&&w.enable(a,this)})),H(this.pluginMaps,v(this,function(a){var b=m(D,a.id);b&&!b.enabled&&w.enable(a,this)})),this.enabling=!1,this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]),c.push(b)},emit:function(a,b){z(this.events[a],function(a){a(b)}),"error"===a&&delete this.events[a]}},w={config:C,contextName:a,registry:D,defined:I,urlFetched:L,defQueue:G,Module:u,makeModuleMap:f,nextTick:h.nextTick,onError:j,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=C.pkgs,c=C.shim,d={paths:!0,config:!0,map:!0};H(a,function(a,b){d[b]?"map"===b?(C.map||(C.map={}),S(C[b],a,!0,!0)):S(C[b],a,!0):C[b]=a}),a.shim&&(H(a.shim,function(a,b){K(a)&&(a={deps:a}),!a.exports&&!a.init||a.exportsFn||(a.exportsFn=w.makeShimExports(a)),c[b]=a}),C.shim=c),a.packages&&(z(a.packages,function(a){a="string"==typeof a?{name:a}:a,b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(fa,"")}}),C.pkgs=b),H(D,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=f(b))}),(a.deps||a.callback)&&w.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;return a.init&&(b=a.init.apply(ba,arguments)),b||a.exports&&da(a.exports)}},makeRequire:function(c,d){function e(b,i,k){var l,m;return d.enableBuildCallback&&i&&J(i)&&(i.__requireJsBuild=!0),"string"==typeof b?J(i)?j(B("requireargs","Invalid require call"),k):c&&t(x,b)?x[b](D[c.id]):h.get?h.get(w,b,c,e):(l=f(b,c,!1,!0),l=l.id,t(I,l)?I[l]:j(B("notloaded",'Module name "'+l+'" has not been loaded yet for context: '+a+(c?"":". Use require([])")))):(r(),w.nextTick(function(){r(),m=g(f(null,c)),m.skipMap=d.skipMap,m.init(b,i,k,{enabled:!0}),o()}),e)}return d=d||{},S(e,{isBrowser:A,toUrl:function(a){var d,e=a.lastIndexOf("."),f=a.split("/")[0];return-1!==e&&("."!==f&&".."!==f||e>1)&&(d=a.substring(e,a.length),a=a.substring(0,e)),w.nameToUrl(b(a,c&&c.id,!0),d,!0)},defined:function(a){return t(I,f(a,c,!1,!0).id)},specified:function(a){return a=f(a,c,!1,!0).id,t(I,a)||t(D,a)}}),c||(e.undef=function(a){k();var b=f(a,c,!0),d=m(D,a);delete I[a],delete L[b.url],delete F[a],d&&(d.events.defined&&(F[a]=d.events),l(a))}),e},enable:function(a){m(D,a.id)&&g(a).enable()},completeLoad:function(a){var b,c,e=m(C.shim,a)||{},f=e.exports;for(k();G.length;){if(c=G.shift(),null===c[0]){if(c[0]=a,b)break;b=!0}else c[0]===a&&(b=!0);p(c)}if(c=m(D,a),!b&&!t(I,a)&&c&&!c.inited){if(C.enforceDefine&&(!f||!da(f)))return d(a)?void 0:j(B("nodefine","No define call for "+a,null,[a]));p([a,e.deps||[],e.exportsFn])}o()},nameToUrl:function(a,b,c){var d,e,f,g,i,j;if(h.jsExtRegExp.test(a))g=a+(b||"");else{for(d=C.paths,e=C.pkgs,g=a.split("/"),i=g.length;i>0;i-=1){if(j=g.slice(0,i).join("/"),f=m(e,j),j=m(d,j)){K(j)&&(j=j[0]),g.splice(0,i,j);break}if(f){a=a===f.name?f.location+"/"+f.main:f.location,g.splice(0,i,a);break}}g=g.join("/"),g+=b||(/\?/.test(g)||c?"":".js"),g=("/"===g.charAt(0)||g.match(/^[\w\+\.\-]+:/)?"":C.baseUrl)+g}return C.urlArgs?g+((-1===g.indexOf("?")?"?":"&")+C.urlArgs):g},load:function(a,b){h.load(w,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){("load"===a.type||la.test((a.currentTarget||a.srcElement).readyState))&&(R=null,a=q(a),w.completeLoad(a.id))},onScriptError:function(a){var b=q(a);return d(b.id)?void 0:j(B("scripterror","Script error for: "+b.id,a,[b.id]))}},w.require=w.makeRequire(),w}var h,x,y,E,L,F,R,M,s,ga,ma=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/gm,na=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,fa=/\.js$/,ka=/^\.\//;x=Object.prototype;var N=x.toString,ha=x.hasOwnProperty,ja=Array.prototype.splice,A=!("undefined"==typeof window||!navigator||!window.document),ea=!A&&"undefined"!=typeof importScripts,la=A&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,Z="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),G={},u={},U=[],Q=!1;if("undefined"==typeof define){if("undefined"!=typeof requirejs){if(J(requirejs))return;u=requirejs,requirejs=void 0}"undefined"!=typeof require&&!J(require)&&(u=require,require=void 0),h=requirejs=function(a,b,c,d){var e,f="_";return!K(a)&&"string"!=typeof a&&(e=a,K(b)?(a=b,b=c,c=d):a=[]),e&&e.context&&(f=e.context),(d=m(G,f))||(d=G[f]=h.s.newContext(f)),e&&d.configure(e),d.require(a,b,c)},h.config=function(a){return h(a)},h.nextTick="undefined"!=typeof setTimeout?function(a){setTimeout(a,4)}:function(a){a()},require||(require=h),h.version="2.1.6",h.jsExtRegExp=/^\/|:|\?|\.js$/,h.isBrowser=A,x=h.s={contexts:G,newContext:ia},h({}),z(["toUrl","undef","defined","specified"],function(a){h[a]=function(){var b=G._;return b.require[a].apply(b,arguments)}}),A&&(y=x.head=document.getElementsByTagName("head")[0],E=document.getElementsByTagName("base")[0])&&(y=x.head=E.parentNode),h.onError=ca,h.load=function(a,b,c){var d,e=a&&a.config||{};if(A)return d=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),d.type=e.scriptType||"text/javascript",d.charset="utf-8",d.async=!0,d.setAttribute("data-requirecontext",a.contextName),d.setAttribute("data-requiremodule",b),!d.attachEvent||d.attachEvent.toString&&0>d.attachEvent.toString().indexOf("[native code")||Z?(d.addEventListener("load",a.onScriptLoad,!1),d.addEventListener("error",a.onScriptError,!1)):(Q=!0,d.attachEvent("onreadystatechange",a.onScriptLoad)),d.src=c,M=d,E?y.insertBefore(d,E):y.appendChild(d),M=null,d;if(ea)try{importScripts(c),a.completeLoad(b)}catch(f){a.onError(B("importscripts","importScripts failed for "+b+" at "+c,f,[b]))}},A&&O(document.getElementsByTagName("script"),function(a){return y||(y=a.parentNode),(L=a.getAttribute("data-main"))?(s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0):void 0}),define=function(a,b,c){var d,e;"string"!=typeof a&&(c=b,b=a,a=null),K(b)||(c=b,b=null),!b&&J(c)&&(b=[],c.length&&(c.toString().replace(ma,"").replace(na,function(a,c){b.push(c)}),b=(1===c.length?["require"]:["require","exports","module"]).concat(b))),Q&&((d=M)||(R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(a){return"interactive"===a.readyState?R=a:void 0}),d=R),d&&(a||(a=d.getAttribute("data-requiremodule")),e=G[d.getAttribute("data-requirecontext")])),(e?e.defQueue:U).push([a,b,c])},define.amd={jQuery:!0},h.exec=function(b){return eval(b)},h(u)}}(this)}WebGLDebugUtils=function(){function a(a){if(null==m){m={};for(var b in a)"number"==typeof a[b]&&(m[a[b]]=b)}}function b(){if(null==m)throw"WebGLDebugUtils.init(ctx) not called"}function c(a){return b(),void 0!==m[a]}function d(a){b();var c=m[a];return void 0!==c?c:"*UNKNOWN WebGL ENUM (0x"+a.toString(16)+")"}function e(a,b,c){var e=l[a];return void 0!==e&&e[b]?d(c):null===c?"null":void 0===c?"undefined":c.toString()}function f(a,b){for(var c="",d=0;dd;++d)a.disableVertexAttribArray(d),a.vertexAttribPointer(d,4,a.FLOAT,!1,0,0),a.vertexAttrib1f(d,0);a.deleteBuffer(c);for(var e=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),d=0;e>d;++d)a.activeTexture(a.TEXTURE0+d),a.bindTexture(a.TEXTURE_CUBE_MAP,null),a.bindTexture(a.TEXTURE_2D,null);for(a.activeTexture(a.TEXTURE0),a.useProgram(null),a.bindBuffer(a.ARRAY_BUFFER,null),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,null),a.bindFramebuffer(a.FRAMEBUFFER,null),a.bindRenderbuffer(a.RENDERBUFFER,null),a.disable(a.BLEND),a.disable(a.CULL_FACE),a.disable(a.DEPTH_TEST),a.disable(a.DITHER),a.disable(a.SCISSOR_TEST),a.blendColor(0,0,0,0),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ONE,a.ZERO),a.clearColor(0,0,0,0),a.clearDepth(1),a.clearStencil(-1),a.colorMask(!0,!0,!0,!0),a.cullFace(a.BACK),a.depthFunc(a.LESS),a.depthMask(!0),a.depthRange(0,1),a.frontFace(a.CCW),a.hint(a.GENERATE_MIPMAP_HINT,a.DONT_CARE),a.lineWidth(1),a.pixelStorei(a.PACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.pixelStorei(a.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),a.UNPACK_COLORSPACE_CONVERSION_WEBGL&&a.pixelStorei(a.UNPACK_COLORSPACE_CONVERSION_WEBGL,a.BROWSER_DEFAULT_WEBGL),a.polygonOffset(0,0),a.sampleCoverage(1,!1),a.scissor(0,0,a.canvas.width,a.canvas.height),a.stencilFunc(a.ALWAYS,0,4294967295),a.stencilMask(4294967295),a.stencilOp(a.KEEP,a.KEEP,a.KEEP),a.viewport(0,0,a.canvas.width,a.canvas.height),a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT|a.STENCIL_BUFFER_BIT);a.getError(););}function j(a){function b(a){return"function"==typeof a?a:function(b){a.handleEvent(b)}}function c(a){var b=a.addEventListener;a.addEventListener=function(c,d,e){switch(c){case"webglcontextlost":x(d);break;case"webglcontextrestored":y(d);break;default:b.apply(a,arguments)}}}function d(){for(var a=Object.keys(w),b=0;b=0&&setTimeout(function(){a.restoreContext()},v)},0)}},a.restoreContext=function(){q&&o.length&&setTimeout(function(){if(!u)throw"can not restore. webglcontestlost listener did not call event.preventDefault";h(),i(l),q=!1,t=0,u=!1;for(var a=o.slice(),b=j("context restored"),c=0;c0)return!1;if(0===b.length)return!0;for(var c in b)if(a.call(b,c))return!1;return!0},this.reset=function(){var a=[];for(var b in this._engines)this._engines.hasOwnProperty(b)&&(a.push(this._engines[b]),delete this._engines[b],this._engineIds.removeItem(b));for(;a.length>0;)a.pop().destroy();SceneJS_events.fireEvent(SceneJS_events.RESET)}};!function(){var a;SceneJS.on("configs",function(b){if(b.pluginPath!=a){a=b.pluginPath;var c=a+"/lib";require.config({paths:{scenejsPluginDeps:c}})}})}();var SceneJS_eventManager=function(){this._handlerIds=new SceneJS_Map,this.typeHandlers={}};SceneJS_eventManager.prototype.createEvent=function(a){this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0})},SceneJS_eventManager.prototype.onEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0}),d=this._handlerIds.addItem(a),e=c.handlers;return e[d]=b,c.numSubs++,d},SceneJS_eventManager.prototype.fireEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0});if(c.numSubs>0){var d=c.handlers;for(var e in d)d.hasOwnProperty(e)&&d[e](b)}},SceneJS_eventManager.prototype.unEvent=function(a){var b=this._handlerIds.items[a];if(b){this._handlerIds.removeItem(a);var c=this.typeHandlers[b];c&&(delete c[a],this.typeHandlers[b].numSubs--)}},SceneJS.Plugins=new function(){function a(a,c,f,g){var h=d[a]||(d[a]={});h[c]=g,b(f,0,function(){for(var b=a+c,d=e[b]||(e[b]=[]);d.length>0;)d.pop()(g);delete e[b]})}function b(a,d,e){if(!a||d>=a.length)return void e();var f=a[d],g=SceneJS_configsModule.configs.pluginPath;if(!g)throw"no pluginPath config";f=g+"/"+f,c(f,function(){b(a,d+1,e)})}function c(a,b){var c=document.createElement("script");c.type="text/javascript",c.readyState?c.onreadystatechange=function(){("loaded"==c.readyState||"complete"==c.readyState)&&(c.onreadystatechange=null,b&&b())}:c.onload=function(){b&&b()},c.src=a,document.getElementsByTagName("head")[0].appendChild(c)}var d={},e={};this.addPlugin=function(){var b,c,d=arguments[0],e=arguments[1];4==arguments.length?(b=arguments[2],c=arguments[3]):c=arguments[2],a(d,e,b,c)},this.hasPlugin=function(a,b){var c=d[a];return c&&!!c[b]},this.getPlugin=function(a,b,f){var g=d[a];if(g){var h=g[b];if(h)return void f(h)}var i=a+b,j=e[i]||(e[i]=[]);if(j.push(f),!(j.length>1)){var k=SceneJS_configsModule.configs.pluginPath;if(!k)throw"no pluginPath config";var l=k+"/"+a+"/"+b+".js";c(l)}}};var SceneJS_events=new function(){this.ERROR=0,this.RESET=1,this.NODE_CREATED=2,this.SCENE_CREATED=3,this.SCENE_COMPILING=4,this.SCENE_DESTROYED=5,this.OBJECT_COMPILING=6,this.WEBGL_CONTEXT_LOST=7,this.WEBGL_CONTEXT_RESTORED=8;var a=[];this.addListener=function(b,c,d){var e=a[b];e||(e=[],a[b]=e);for(var f={command:c,priority:void 0==d?e.length:d},g=-1,h=0,i=e.length;i>h;h++)if(!e[h]){g=h;break}0>g&&(e.push(f),g=e.length-1);var j=b+"."+g;return j},this.removeListener=function(b){var c=b.lastIndexOf("."),d=parseInt(b.substr(0,c)),e=parseInt(b.substr(c+1)),f=a[d];f&&delete f[e]},this.fireEvent=function(b,c){var d=a[b];if(d){c=c||{};for(var e=0;e',e.appendChild(f)}var h=document.getElementById(b);if(!h)throw SceneJS_error.fatalError(SceneJS.errors.CANVAS_NOT_FOUND,"SceneJS.Scene attribute 'canvasId' does not match any elements in the page");this.canvasId=b,this.options=d||{},this.canvas=this.options.simulateWebGLContextLost?WebGLDebugUtils.makeLostContextSimulatingCanvas(h):h,this.ssaaMultiplier=this.options.ssaaMultiplier||1,this.canvas.width=this.canvas.clientWidth*this.ssaaMultiplier,this.canvas.height=this.canvas.clientHeight*this.ssaaMultiplier,this.contextAttr=c,this.gl=null,this.initWebGL()};SceneJS_Canvas.prototype._WEBGL_CONTEXT_NAMES=["webgl","experimental-webgl","webkit-3d","moz-webgl","moz-glweb20"],SceneJS_Canvas.prototype.initWebGL=function(){for(var a=0;!this.gl&&af;f++)d.createNode(a.nodes[f],function(a){c.addNode(a),++e==g&&(b&&b(c),d.scene.publish("nodes/"+c.id,c))});else b&&(b(c),d.scene.publish("nodes/"+c.id,c))})},SceneJS_Engine.prototype._doDestroyNodes=function(){for(var a;this._numNodesToDestroy>0;)a=this._nodesToDestroy[--this._numNodesToDestroy],a._doDestroy(),this._coreFactory.putCore(a._core),this._nodeFactory.putNode(a)},SceneJS_Engine.prototype.findNode=function(a){return this._nodeFactory.nodes.items[a]},SceneJS_Engine.prototype.findNodes=function(a){var b=new RegExp(a),c=[],d=this._nodeFactory.nodes.items;for(var e in d)d.hasOwnProperty(e)&&b.test(e)&&c.push(d[e]);return c},SceneJS_Engine.prototype.hasCore=function(a,b){return this._coreFactory.hasCore(a,b)},SceneJS_Engine.prototype.branchDirty=function(a){if(!this.sceneDirty&&a!=window){a.branchDirty=!0,a.dirty=!0;for(var b=a.parent;b&&!b.dirty&&!b.branchDirty;b=b.parent)b.dirty=!0;this._sceneBranchesDirty=!0}},SceneJS_Engine.prototype.renderFrame=function(a){var b=!1;if(this._needCompile()||a&&a.force)for(var c=(new Date).getTime(),d=a&&a.force,e=0;e0?setTimeout(window[e],1e3/d.fps):requestAnimationFrame(window[e]))},setTimeout(window[e],0)}},SceneJS_Engine.prototype.pick=function(a,b,c){this._needCompile()&&this._doCompile();var d=this.display.pick({canvasX:a,canvasY:b,rayPick:c?c.rayPick:!1});return d},SceneJS_Engine.prototype.readPixels=function(a,b){return this._needCompile()&&this._doCompile(),this.display.readPixels(a,b)},SceneJS_Engine.prototype._needCompile=function(){return this.display.imageDirty||this.display.drawListDirty||this.display.stateSortDirty||this.display.stateOrderDirty||this.display.objectListDirty||this._sceneBranchesDirty||this.sceneDirty},SceneJS_Engine.prototype._doCompile=function(){if(this._sceneBranchesDirty||this.sceneDirty){this._sceneBranchesDirty=!1,SceneJS_events.fireEvent(SceneJS_events.SCENE_COMPILING,{engine:this}),this.pubSubProxy=new SceneJS_PubSubProxy(this.scene,null);var a={pubSubProxy:this.pubSubProxy};this.scene._compileNodes(a),this.sceneDirty=!1}this._doDestroyNodes()},SceneJS_Engine.prototype.pause=function(a){this.paused=a},SceneJS_Engine.prototype.stop=function(){this.running&&(this.running=!1,this.paused=!1,window["__scenejs_sceneLoop"+this.id]=null)},SceneJS_Engine.prototype.destroyNode=function(a){this._nodesToDestroy[this._numNodesToDestroy++]=a;var b=this.sceneStatus.nodes[a.id];b&&(this.sceneStatus.numTasks-=b.numTasks,delete this.sceneStatus.nodes[a.id])},SceneJS_Engine.prototype.destroy=function(){this.destroyed=!0},self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array),function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;ch;h++)i[h](g);SceneJS.publish("configs",this.configs)},this.getConfigs=function(a){if(a){for(var b=this.configs,c=a.split("."),d=0;b&&dc;c++)b.push("----");e=b.join("")},this.error=function(a){this._log("error",a)},this.warn=function(a){this._log("warn",a)},this.info=function(a){this._log("info",a)},this.debug=function(a){this._log("debug",a)},this.setFuncs=function(a){if(a){b=a;for(var d in c)this._flush(d)}},this._flush=function(a){var d=c[a];if(d){var e=b?b[a]:null;if(e){for(var f=0;fy;++y)f=b[y],c=f[0],d=f[1],e=f[2],g[y]=[i*c+m*d+q*e+u,j*c+n*d+r*e+v,k*c+o*d+s*e+w,l*c+p*d+t*e+x];return g},SceneJS_math_transformVector3=function(a,b){var c=b[0],d=b[1],e=b[2];return[a[0]*c+a[4]*d+a[8]*e,a[1]*c+a[5]*d+a[9]*e,a[2]*c+a[6]*d+a[10]*e]},SceneJS_math_transformVector4=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3];return[a[0]*c+a[4]*d+a[8]*e+a[12]*f,a[1]*c+a[5]*d+a[9]*e+a[13]*f,a[2]*c+a[6]*d+a[10]*e+a[14]*f,a[3]*c+a[7]*d+a[11]*e+a[15]*f]},SceneJS_math_projectVec4=function(a){var b=1/a[3];return[a[0]*b,a[1]*b,a[2]*b,1]},SceneJS_math_Plane3=function(a,b,c){if(this.normal=[0,0,1],this.offset=0,a&&b){var d=a[0],e=a[1],f=a[2];if(this.offset=b,c){var g=Math.sqrt(d*d+e*e+f*f);g>0&&(g=1/g,this.normal[0]=d*g,this.normal[1]=e*g,this.normal[2]=f*g,this.offset*=g)}}},SceneJS_math_MAX_DOUBLE=Number.POSITIVE_INFINITY,SceneJS_math_MIN_DOUBLE=Number.NEGATIVE_INFINITY,SceneJS_math_Box3=function(a,b){this.min=a||[SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE],this.max=b||[SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE],this.init=function(a,b){return this.min[0]=a[0],this.min[1]=a[1],this.min[2]=a[2],this.max[0]=b[0],this.max[1]=b[1],this.max[2]=b[2],this},this.fromPoints=function(a){for(var b=a.length,c=0;b>c;++c){var d=a[c][3],e=a[c][0]/d,f=a[c][1]/d,g=a[c][2]/d;ethis.max[0]&&(this.max[0]=e),f>this.max[1]&&(this.max[1]=f),g>this.max[2]&&(this.max[2]=g)}return this},this.isEmpty=function(){return this.min[0]>=this.max[0]&&this.min[1]>=this.max[1]&&this.min[2]>=this.max[2]},this.getCenter=function(){return[(this.max[0]+this.min[0])/2,(this.max[1]+this.min[1])/2,(this.max[2]+this.min[2])/2]},this.getSize=function(){return[this.max[0]-this.min[0],this.max[1]-this.min[1],this.max[2]-this.min[2]]},this.getFacesAreas=function(){var a=this.size;return[a[1]*a[2],a[0]*a[2],a[0]*a[1]]},this.getSurfaceArea=function(){var a=this.getFacesAreas();return 2*(a[0]+a[1]+a[2])},this.getVolume=function(){var a=this.size;return a[0]*a[1]*a[2]},this.getOffset=function(a){return this.min[0]-=a,this.min[1]-=a,this.min[2]-=a,this.max[0]+=a,this.max[1]+=a,this.max[2]+=a,this}},SceneJS_math_AxisBox3=function(a,b){var c=a[0],d=a[1],e=a[2],f=b[0],g=b[1],h=b[2];this.verts=[[c,d,e],[f,d,e],[f,g,e],[c,g,e],[c,d,h],[f,d,h],[f,g,h],[c,g,h]],this.toBox3=function(){for(var a=new SceneJS_math_Box3,b=0;8>b;++b)for(var c=this.verts[b],d=0;3>d;++d)c[d]a.max[d]&&(a.max[d]=c[d])}},SceneJS_math_Sphere3=function(a,b){this.center=[a[0],a[1],a[2]],this.radius=b,this.isEmpty=function(){return 0===this.radius},this.surfaceArea=function(){return 4*Math.PI*this.radius*this.radius},this.getVolume=function(){var a=this.radius;return 4/3*Math.PI*a*a*a}},SceneJS_math_billboardMat=function(a){var b=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],c=[SceneJS_math_lenVec4(b[0]),SceneJS_math_lenVec4(b[1]),SceneJS_math_lenVec4(b[2])],d=SceneJS_math_mat4();SceneJS_math_rcpVec3(c,d);var e=SceneJS_math_scalingMat4v(c);SceneJS_math_mulVec4Scalar(b[0],d[0]),SceneJS_math_mulVec4Scalar(b[1],d[1]),SceneJS_math_mulVec4Scalar(b[2],d[2]);var f=SceneJS_math_identityMat4();return SceneJS_math_setRowMat4(f,0,b[0]),SceneJS_math_setRowMat4(f,1,b[1]),SceneJS_math_setRowMat4(f,2,b[2]),SceneJS_math_mulMat4(f,e)},SceneJS_math_FrustumPlane=function(a,b,c,d){var e=1/Math.sqrt(a*a+b*b+c*c);this.normal=[a*e,b*e,c*e],this.offset=d*e,this.testVertex=[this.normal[0]>=0?1:0,this.normal[1]>=0?1:0,this.normal[2]>=0?1:0]},SceneJS_math_OUTSIDE_FRUSTUM=3,SceneJS_math_INTERSECT_FRUSTUM=4,SceneJS_math_INSIDE_FRUSTUM=5,SceneJS_math_Frustum=function(a,b,c){var d=SceneJS_math_mat4();SceneJS_math_mulMat4(b,a,d);var e=d[0],f=d[1],g=d[2],h=d[3],i=d[4],j=d[5],k=d[6],l=d[7],m=d[8],n=d[9],o=d[10],p=d[11],q=d[12],r=d[13],s=d[14],t=d[15],u=[new SceneJS_math_FrustumPlane(h-e,l-i,p-m,t-q),new SceneJS_math_FrustumPlane(h+e,l+i,p+m,t+q),new SceneJS_math_FrustumPlane(h-f,l-j,p-n,t-r),new SceneJS_math_FrustumPlane(h+f,l+j,p+n,t+r),new SceneJS_math_FrustumPlane(h-g,l-k,p-o,t-s),new SceneJS_math_FrustumPlane(h+g,l+k,p+o,t+s)],v=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],w=[SceneJS_math_lenVec4(v[0]),SceneJS_math_lenVec4(v[1]),SceneJS_math_lenVec4(v[2])],x=SceneJS_math_rcpVec3(w),y=SceneJS_math_scalingMat4v(w),z=SceneJS_math_scalingMat4v(x);SceneJS_math_mulVec4Scalar(v[0],x[0]),SceneJS_math_mulVec4Scalar(v[1],x[1]),SceneJS_math_mulVec4Scalar(v[2],x[2]);var A=SceneJS_math_identityMat4();SceneJS_math_setRowMat4(A,0,v[0]),SceneJS_math_setRowMat4(A,1,v[1]),SceneJS_math_setRowMat4(A,2,v[2]),this.matrix||(this.matrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(b,a,this.matrix),this.billboardMatrix||(this.billboardMatrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(z,SceneJS_math_mulMat4(A,y),this.billboardMatrix),this.viewport=c.slice(0,4),this.textAxisBoxIntersection=function(a){for(var b=SceneJS_math_INSIDE_FRUSTUM,c=[a.min,a.max],d=null,e=0;6>e;++e){if(d=u[e],d.normal[0]*c[d.testVertex[0]][0]+d.normal[1]*c[d.testVertex[1]][1]+d.normal[2]*c[d.testVertex[2]][2]+d.offset<0)return SceneJS_math_OUTSIDE_FRUSTUM;d.normal[0]*c[1-d.testVertex[0]][0]+d.normal[1]*c[1-d.testVertex[1]][1]+d.normal[2]*c[1-d.testVertex[2]][2]+d.offset<0&&(b=SceneJS_math_INTERSECT_FRUSTUM)}return b},this.getProjectedSize=function(a){var b=SceneJS_math_mat4();SceneJS_math_subVec3(a.max,a.min,b);var d=SceneJS_math_lenVec3(b),e=Math.abs(d),f=[.5*(a.min[0]+a.max[0]),.5*(a.min[1]+a.max[1]),.5*(a.min[2]+a.max[2]),0],g=.5*e,h=[-g,0,0,1],i=[g,0,0,1];return h=SceneJS_math_mulMat4v4(this.billboardMatrix,h),h=SceneJS_math_addVec4(h,f),h=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,h)),i=SceneJS_math_mulMat4v4(this.billboardMatrix,i),i=SceneJS_math_addVec4(i,f),i=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,i)),c[2]*Math.abs(i[0]-h[0])},this.getProjectedState=function(a){for(var b,d,e,f=SceneJS_math_transformPoints3(this.matrix,a),g=1e7,h=1e7,i=-1e7,j=-1e7,k=f.length,l=0;k>l;++l)b=SceneJS_math_projectVec4(f[l]),d=b[0],e=b[1],-.5>d&&(d=-.5),-.5>e&&(e=-.5),d>.5&&(d=.5),e>.5&&(e=.5),g>d&&(g=d),h>e&&(h=e),d>i&&(i=d),e>j&&(j=e);g+=.5,h+=.5,i+=.5,j+=.5;var m=c[2],n=c[3];g*=m+15,h*=n+15,i*=m+15,j*=n+15;var o=SceneJS_math_mat4();SceneJS_math_subVec2([i,j],[g,h],o);var p=SceneJS_math_lenVec2(o);return 0>g&&(g=0),i>m&&(i=m),0>h&&(h=0),j>n&&(j=n),{canvasBox:{min:[g,h],max:[i,j]},canvasSize:p}}},SceneJS_math_identityQuaternion=function(){return[0,0,0,1]},SceneJS_math_angleAxisQuaternion=function(a,b,c,d){var e=d/180*Math.PI,f=e/2,g=Math.sin(f);return[g*a,g*b,g*c,Math.cos(f)]},SceneJS_math_mulQuaternions=function(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=b[0],h=b[1],i=b[2],j=b[3];return[f*g+c*j+d*i-e*h,f*h+d*j+e*g-c*i,f*i+e*j+c*h-d*g,f*j-c*g-d*h-e*i]},SceneJS_math_newMat4FromQuaternion=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=2*b,g=2*c,h=2*d,i=f*e,j=g*e,k=h*e,l=f*b,m=g*b,n=h*b,o=g*c,p=h*c,q=h*d,r=SceneJS_math_identityMat4();return SceneJS_math_setCellMat4(r,0,0,1-(o+q)),SceneJS_math_setCellMat4(r,0,1,m-k),SceneJS_math_setCellMat4(r,0,2,n+j),SceneJS_math_setCellMat4(r,1,0,m+k),SceneJS_math_setCellMat4(r,1,1,1-(l+q)),SceneJS_math_setCellMat4(r,1,2,p-i),SceneJS_math_setCellMat4(r,2,0,n-j),SceneJS_math_setCellMat4(r,2,1,p+i),SceneJS_math_setCellMat4(r,2,2,1-(l+o)),r},SceneJS_math_slerp=function(a,b,c){var d=.0174532925*b[3],e=.0174532925*c[3],f=d*e+b[0]*c[0]+b[1]*c[1]+b[2]*c[2];if(Math.abs(f)>=1)return[b[0],b[1],b[2],b[3]];var g=Math.acos(f),h=Math.sqrt(1-f*f);if(Math.abs(h)<.001)return[.5*b[0]+.5*c[0],.5*b[1]+.5*c[1],.5*b[2]+.5*c[2],.5*b[3]+.5*c[3]];var i=Math.sin((1-a)*g)/h,j=Math.sin(a*g)/h;return[b[0]*i+c[0]*j,b[1]*i+c[1]*j,b[2]*i+c[2]*j,57.295779579*(d*i+e*j)]},SceneJS_math_normalizeQuaternion=function(a){var b=SceneJS_math_lenVec4([a[0],a[1],a[2],a[3]]);return[a[0]/b,a[1]/b,a[2]/b,a[3]/b]},SceneJS_math_conjugateQuaternion=function(a){return[-a[0],-a[1],-a[2],a[3]]},SceneJS_math_angleAxisFromQuaternion=function(a){a=SceneJS_math_normalizeQuaternion(a);var b=a[3],c=2*Math.acos(b),d=Math.sqrt(1-b*b);return.001>d?{x:a[0],y:a[1],z:a[2],angle:57.295779579*c}:{x:a[0]/d,y:a[1]/d,z:a[2]/d,angle:57.295779579*c}},SceneJS_sceneStatusModule=new function(){function a(a){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d=c.style;return d.position="absolute",d.width="200px",d.right="10px",d.top="0",d.padding="10px",d["z-index"]="10000",b.appendChild(c),c}function b(a,b){var c=document.createElement("div"),d=c.style;return d["font-family"]="Helvetica",d["font-size"]="14px",d.padding="5px",d.margin="4px",d["padding-left"]="12px",d.border="1px solid #000055",d.color="black",d.background="#AAAAAA",d.opacity="0.8",d["border-radius"]="3px",d["-moz-border-radius"]="3px",d["box-shadow"]="3px 3px 3px #444444",c.innerHTML=b,a.appendChild(c),c}function c(a){a.style.background="#AAFFAA";var b=.8,c=setInterval(function(){0>=b?(a.parentNode.removeChild(a),clearInterval(c)):(a.style.opacity=b,b-=.1)},100)}function d(a){a.style.background="#FFAAAA"}this.sceneStatus={};var e=new SceneJS_Map,f={},g={},h=this;SceneJS_events.addListener(SceneJS_events.SCENE_DESTROYED,function(a){var b=a.engine.id;delete h.sceneStatus[b],delete g[b]}),this.taskStarted=function(c,d){var h=SceneJS_configsModule.configs.statusPopups!==!1,i=c.getScene(),j=i.getId(),k=c.getId(),l=i.getCanvas(),m=e.addItem(),n=this.sceneStatus[j];n||(n=this.sceneStatus[j]={numTasks:0}),n.numTasks++;var o=g[j];o||(o=g[j]={sceneId:j,nodeStates:{},scene:i,popupContainer:h?a(l):null,descCounts:{}});var p=o.descCounts[d];void 0==p&&(p=o.descCounts[d]=0),o.descCounts[d]++;var q=o.nodeStates[k];q||(q=o.nodeStates[k]={nodeId:k,numTasks:0,tasks:{}}),d=d+" "+o.descCounts[d]+"...",q.numTasks++;var r={sceneState:o,nodeState:q,description:d,element:h?b(o.popupContainer,d):null};return q.tasks[m]=r,f[m]=r,m},this.taskFinished=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var d=b.sceneState;this.sceneStatus[d.sceneId].numTasks--,b.element&&c(b.element);var e=b.nodeState;return--e.numTasks<0&&(e.numTasks=0),delete e.tasks[a],0==e.numTasks&&delete d.nodeStates[e.nodeId],null},this.taskFailed=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var c=!!SceneJS_configsModule.configs.statusPopups,e=b.sceneState;this.sceneStatus[e.sceneId].numTasks--,c&&d(b.element);var g=b.nodeState;return g.numTasks--,delete g.tasks[a],0==g.numTasks&&delete b.sceneState.nodeStates[g.nodeId],null}};SceneJS._webgl={},SceneJS._webgl.ArrayBuffer=function(a,b,c,d,e,f){this.allocated=!1,this.gl=a,this.type=b, this.numItems=d,this.itemSize=e,this.usage=f,this._allocate(c,d)},SceneJS._webgl.ArrayBuffer.prototype._allocate=function(a,b){if(this.allocated=!1,this.handle=this.gl.createBuffer(),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to allocate WebGL ArrayBuffer");this.handle&&(this.gl.bindBuffer(this.type,this.handle),this.gl.bufferData(this.type,a,this.usage),this.gl.bindBuffer(this.type,null),this.numItems=b,this.length=a.length,this.allocated=!0)},SceneJS._webgl.ArrayBuffer.prototype.setData=function(a,b){this.allocated&&(a.length>this.length?(this.destroy(),this._allocate(a,a.length)):b||0===b?this.gl.bufferSubData(this.type,b,a):this.gl.bufferData(this.type,a))},SceneJS._webgl.ArrayBuffer.prototype.unbind=function(){this.allocated&&this.gl.bindBuffer(this.type,null)},SceneJS._webgl.ArrayBuffer.prototype.destroy=function(){this.allocated&&(this.gl.deleteBuffer(this.handle),this.handle=null,this.allocated=!1)},SceneJS._webgl.ArrayBuffer.prototype.bind=function(){this.allocated&&this.gl.bindBuffer(this.type,this.handle)},SceneJS._webgl.Attribute=function(a,b,c,d,e,f){this.gl=a,this.location=f,this.bindFloatArrayBuffer=function(b){b&&(b.bind(),a.enableVertexAttribArray(f),a.vertexAttribPointer(f,b.itemSize,a.FLOAT,!1,0,0))}},SceneJS._webgl.Attribute.prototype.bindInterleavedFloatArrayBuffer=function(a,b,c){this.gl.enableVertexAttribArray(this.location),this.gl.vertexAttribPointer(this.location,a,this.gl.FLOAT,!1,b,c)},SceneJS._webgl.enumMap={funcAdd:"FUNC_ADD",funcSubtract:"FUNC_SUBTRACT",funcReverseSubtract:"FUNC_REVERSE_SUBTRACT",zero:"ZERO",one:"ONE",srcColor:"SRC_COLOR",oneMinusSrcColor:"ONE_MINUS_SRC_COLOR",dstColor:"DST_COLOR",oneMinusDstColor:"ONE_MINUS_DST_COLOR",srcAlpha:"SRC_ALPHA",oneMinusSrcAlpha:"ONE_MINUS_SRC_ALPHA",dstAlpha:"DST_ALPHA",oneMinusDstAlpha:"ONE_MINUS_DST_ALPHA",contantColor:"CONSTANT_COLOR",oneMinusConstantColor:"ONE_MINUS_CONSTANT_COLOR",constantAlpha:"CONSTANT_ALPHA",oneMinusConstantAlpha:"ONE_MINUS_CONSTANT_ALPHA",srcAlphaSaturate:"SRC_ALPHA_SATURATE",front:"FRONT",back:"BACK",frontAndBack:"FRONT_AND_BACK",never:"NEVER",less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL",always:"ALWAYS",cw:"CW",ccw:"CCW",linear:"LINEAR",nearest:"NEAREST",linearMipMapNearest:"LINEAR_MIPMAP_NEAREST",nearestMipMapNearest:"NEAREST_MIPMAP_NEAREST",nearestMipMapLinear:"NEAREST_MIPMAP_LINEAR",linearMipMapLinear:"LINEAR_MIPMAP_LINEAR",repeat:"REPEAT",clampToEdge:"CLAMP_TO_EDGE",mirroredRepeat:"MIRRORED_REPEAT",alpha:"ALPHA",rgb:"RGB",rgba:"RGBA",luminance:"LUMINANCE",luminanceAlpha:"LUMINANCE_ALPHA",textureBinding2D:"TEXTURE_BINDING_2D",textureBindingCubeMap:"TEXTURE_BINDING_CUBE_MAP",compareRToTexture:"COMPARE_R_TO_TEXTURE",unsignedByte:"UNSIGNED_BYTE"},SceneJS._webgl.RenderBuffer=function(a){this.allocated=!1,this.canvas=a.canvas,this.gl=a.canvas.gl,this.buf=null,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.webglRestored=function(a){this.gl=a,this.buf=null,this.allocated=!1,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.bind=function(){this._touch(),this.bound||(this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.bound=!0)},SceneJS._webgl.RenderBuffer.prototype._touch=function(){var a=this.canvas.canvas.width,b=this.canvas.canvas.height;if(this.buf){if(this.buf.width==a&&this.buf.height==b)return;this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf)}this.buf={framebuf:this.gl.createFramebuffer(),renderbuf:this.gl.createRenderbuffer(),texture:this.gl.createTexture(),width:a,height:b},this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.gl.bindTexture(this.gl.TEXTURE_2D,this.buf.texture),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE);try{this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,null)}catch(c){var d=new WebGLUnsignedByteArray(a*b*3);this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,d)}if(this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.DEPTH_COMPONENT16,a,b),this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER,this.gl.COLOR_ATTACHMENT0,this.gl.TEXTURE_2D,this.buf.texture,0),this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER,this.gl.DEPTH_ATTACHMENT,this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.bindTexture(this.gl.TEXTURE_2D,null),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),!this.gl.isFramebuffer(this.buf.framebuf))throw SceneJS_error.fatalError(SceneJS.errors.INVALID_FRAMEBUFFER,"Invalid framebuffer");var e=this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);switch(e){case this.gl.FRAMEBUFFER_COMPLETE:break;case this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");case this.gl.FRAMEBUFFER_UNSUPPORTED:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");default:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: "+e)}this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.clear=function(){if(!this.bound)throw"Render buffer not bound";this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT),this.gl.disable(this.gl.BLEND)},SceneJS._webgl.RenderBuffer.prototype.read=function(a,b){var c=a,d=this.canvas.canvas.height-b,e=new Uint8Array(4);return this.gl.readPixels(c,d,1,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),e},SceneJS._webgl.RenderBuffer.prototype.unbind=function(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.getTexture=function(){var a=this;return{bind:function(b){return a.buf&&a.buf.texture?(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,a.buf.texture),!0):!1},unbind:function(b){a.buf&&a.buf.texture&&(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,null))}}},SceneJS._webgl.RenderBuffer.prototype.destroy=function(){this.buf&&(this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf),this.buf=null,this.bound=!1)},SceneJS._webgl.Program=function(a,b,c){this.allocated=!1,this.gl=a,this._uniforms={},this._samplers={},this._attributes={},this.uniformValues=[],this.materialSettings={specularColor:[0,0,0],specular:0,shine:0,emit:0,alpha:0},this._shaders=[];var d,e,f,g,h,i;for(e=0;ee;++e)f=a.getActiveUniform(this.handle,e),f&&(g=f.name,"\x00"==g[g.length-1]&&(g=g.substr(0,g.length-1)),h=a.getUniformLocation(this.handle,g),f.type==a.SAMPLER_2D||f.type==a.SAMPLER_CUBE||35682==f.type?this._samplers[g]=new SceneJS._webgl.Sampler(a,this.handle,g,f.type,f.size,h):(this._uniforms[g]=new SceneJS._webgl.Uniform(a,this.handle,g,f.type,f.size,h,k),this.uniformValues[k]=null,++k));var l=a.getProgramParameter(this.handle,a.ACTIVE_ATTRIBUTES);for(e=0;l>e;e++)d=a.getActiveAttrib(this.handle,e),d&&(h=a.getAttribLocation(this.handle,d.name),this._attributes[d.name]=new SceneJS._webgl.Attribute(a,this.handle,d.name,d.type,d.size,h));this.allocated=!0}},SceneJS._webgl.Program.prototype.bind=function(){this.allocated&&this.gl.useProgram(this.handle)},SceneJS._webgl.Program.prototype.getUniformLocation=function(a){if(this.allocated){var b=this._uniforms[a];return b?b.getLocation():void 0}},SceneJS._webgl.Program.prototype.getUniform=function(a){if(this.allocated){var b=this._uniforms[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.getAttribute=function(a){if(this.allocated){var b=this._attributes[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.bindFloatArrayBuffer=function(a,b){if(this.allocated){var c=this._attributes[a];c&&c.bindFloatArrayBuffer(b)}},SceneJS._webgl.Program.prototype.bindTexture=function(a,b,c){if(!this.allocated)return!1;var d=this._samplers[a];return d?d.bindTexture(b,c):!1},SceneJS._webgl.Program.prototype.destroy=function(){if(this.allocated){this.gl.deleteProgram(this.handle);for(var a in this._shaders)this.gl.deleteShader(this._shaders[a].handle);this.handle=null,this._attributes=null,this._uniforms=null,this._samplers=null,this.allocated=!1}},SceneJS._webgl.Program.prototype.setUniform=function(a,b){if(this.allocated){var c=this._uniforms[a];c&&(this.uniformValues[c.index]===b&&c.numberValue||(c.setValue(b),this.uniformValues[c.index]=b))}},SceneJS._webgl.Sampler=function(a,b,c,d,e,f){this.bindTexture=function(b,c){return b.bind(c)?(a.uniform1i(f,c),!0):!1}},SceneJS._webgl.Shader=function(a,b,c){if(this.allocated=!1,this.handle=a.createShader(b),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to create WebGL shader");if(a.shaderSource(this.handle,c),a.compileShader(this.handle),this.valid=0!=a.getShaderParameter(this.handle,a.COMPILE_STATUS),!this.valid&&!a.isContextLost()){SceneJS.log.error("Shader program failed to compile: "+a.getShaderInfoLog(this.handle)),SceneJS.log.error("Shader source:");for(var d=c.split("\n"),e=0;eb){var d=b/c,e=a.width*d,f=a.height*d,g=document.createElement("canvas");g.width=SceneJS._webgl.nextHighestPowerOfTwo(e),g.height=SceneJS._webgl.nextHighestPowerOfTwo(f);var h=g.getContext("2d");h.drawImage(a,0,0,a.width,a.height,0,0,g.width,g.height),a=g}return a},SceneJS._webgl.ensureImageSizePowerOfTwo=function(a){if(!SceneJS._webgl.isPowerOfTwo(a.width)||!SceneJS._webgl.isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=SceneJS._webgl.nextHighestPowerOfTwo(a.width),b.height=SceneJS._webgl.nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b}return a},SceneJS._webgl.isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS._webgl.nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS._webgl.Uniform=function(a,b,c,d,e,f,g,h){var i=null,j=null;if(d===a.BOOL)i=function(b){j!==b&&(j=b,a.uniform1i(f,b))};else if(d===a.BOOL_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.BOOL_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.BOOL_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.INT)i=function(b){j!==b&&(j=b,a.uniform1iv(f,b))};else if(d===a.INT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.INT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.INT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.FLOAT)i=function(b){j!==b&&(j=b,a.uniform1f(f,b))};else if(d===a.FLOAT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2fv(f,b))};else if(d===a.FLOAT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3fv(f,b))};else if(d===a.FLOAT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4fv(f,b))};else if(d===a.FLOAT_MAT2)i=function(b){a.uniformMatrix2fv(f,a.FALSE,b)};else if(d===a.FLOAT_MAT3)i=function(b){a.uniformMatrix3fv(f,a.FALSE,b)};else{if(d!==a.FLOAT_MAT4)throw"Unsupported shader uniform type: "+d;i=function(b){a.uniformMatrix4fv(f,a.FALSE,b)}}this.setValue=i,this.getLocation=function(){return f},this.index=g};var SceneJS_nodeEventsModule=new function(){var a,b=[],c=[],d=0,e={type:"listeners",stateId:SceneJS._baseStateId++,empty:!0,listeners:[]};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){d=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(d>0){var g={type:"listeners",stateId:b[d-1],listeners:c.slice(0,d)};f.display.renderListeners=g}else f.display.renderListeners=e;a=!1}}),this.preVisitNode=function(e){var f=e._topicSubs.rendered,g=e._topicSubs.worldPos,h=e._topicSubs.viewPos,i=e._topicSubs.cameraPos,j=e._topicSubs.projPos,k=e._topicSubs.canvasPos;(f||g||h||i||j||k)&&(b[d]=e.id,c[d]=function(a){f&&e.publish("rendered",a,!0),g&&e.publish("worldPos",a.getWorldPos()),h&&e.publish("viewPos",a.getViewPos()),i&&e.publish("cameraPos",a.getCameraPos()),j&&e.publish("projPos",a.getProjPos()),k&&e.publish("canvasPos",a.getCanvasPos())},d++,a=!0)},this.postVisitNode=function(c){c.id==b[d-1]&&(d--,a=!0)}},SceneJS_Core=function(a){this.type=a,this.coreId=null,this.stateId=null,this.useCount=0},SceneJS_CoreFactory=function(){this._stateMap=new SceneJS_Map(null,SceneJS._baseStateId),this._cores={}};SceneJS_CoreFactory.coreTypes={},SceneJS_CoreFactory.createCoreType=function(a,b){},SceneJS_CoreFactory.addCoreBuilder=function(a,b){},SceneJS_CoreFactory.coreAliases={rotate:"xform",translate:"xform",scale:"xform",matrix:"xform",xform:"xform"},SceneJS_CoreFactory.prototype.getCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];d||(d=this._cores[a]={});var e;return b&&(e=d[b])?(e.useCount++,e):(e=new SceneJS_Core(a),e.useCount=1,e.stateId=this._stateMap.addItem(e),e.coreId=void 0!=b&&null!=b?b:e.stateId,d[e.coreId]=e,e)},SceneJS_CoreFactory.prototype.hasCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];return d&&d[b]},SceneJS_CoreFactory.prototype.putCore=function(a){if(0!=a.useCount&&--a.useCount<=0){var b=this._cores[a.type];delete b[a.coreId],this._stateMap.removeItem(a.stateId)}},SceneJS_CoreFactory.prototype.webglRestored=function(){var a,b;for(var c in this._cores)if(this._cores.hasOwnProperty(c)&&(a=this._cores[c]))for(var d in a)a.hasOwnProperty(d)&&(b=a[d],b&&b.webglRestored&&b.webglRestored())},SceneJS.Node=function(){},SceneJS.Node.prototype.constructor=SceneJS.Node,SceneJS.Node.prototype._construct=function(a,b,c,d){this._engine=a,this._core=b,this.coreId=b.coreId,this.id=c.id||c.nodeId||d,this.type=c.type||"node",this.data=c.data,this.parent=null,this.nodes=[],this._handleMap=new SceneJS_Map,this._topicSubs={},this._handleTopics={},this._topicPubs={},this._listeners={},this._numListeners=0,this.dirty=!1,this.branchDirty=!1,this._init&&this._init(c)},SceneJS.Node.prototype.taskStarted=function(a){return SceneJS_sceneStatusModule.taskStarted(this,a||"Task")},SceneJS.Node.prototype.taskFinished=function(a){return SceneJS_sceneStatusModule.taskFinished(a)},SceneJS.Node.prototype.taskFailed=function(a){return SceneJS_sceneStatusModule.taskFailed(a)},SceneJS.Node.prototype.log=function(){var a,b;switch(1==arguments.length?(a="info",b=arguments[0]):2==arguments.length&&(a=arguments[0],b=arguments[1]),a){case"warn":b="WARN; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;case"error":b="ERROR; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;default:b="INFO; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b}console[a]?console[a](b):console.log(b)},SceneJS.Node.prototype.publish=function(a,b,c){if(c||(this._topicPubs[a]=b),this._topicSubs[a]){var d=this._topicSubs[a];for(var e in d)d.hasOwnProperty(e)&&d[e].call(this,b)}},SceneJS.Node.prototype.unpublish=function(a){var b=this._topicSubs[a];if(b)for(var c in b)b.hasOwnProperty(c)&&b[c].call(this,null);delete this._topicPubs[a]},SceneJS.Node.prototype.on=function(a,b){var c=this._topicSubs[a];c||(c={},this._topicSubs[a]=c);var d=this._handleMap.addItem();c[d]=b,this._handleTopics[d]=a;var e=this._topicPubs[a];return e&&b.call(this,e),"rendered"==a&&this._engine.branchDirty(this),d},SceneJS.Node.prototype.off=function(a){var b=this._handleTopics[a];if(b){delete this._handleTopics[a];var c=this._topicSubs[b];c&&delete c[a],this._handleMap.removeItem(a),"rendered"==b&&this._engine.branchDirty(this)}},SceneJS.Node.prototype.once=function(a,b){var c=this,d=this.on(a,function(a){c.off(d),b(a)})},SceneJS.Node.prototype.getScene=function(){return this._engine.scene},SceneJS.Node.prototype.getCoreId=function(){return this._core.coreId},SceneJS.Node.prototype.getID=function(){return this.id},SceneJS.Node.prototype.getId=function(){return this.id},SceneJS.Node.prototype.getNodeId=function(){return this.id},SceneJS.Node.prototype.getType=function(){return this.type},SceneJS.Node.prototype.getData=function(){return this.data},SceneJS.Node.prototype.setData=function(a){return this.data=a,this},SceneJS.Node.prototype.getNumNodes=function(){return this.nodes.length},SceneJS.Node.prototype.getNodes=function(){return this.nodes.slice(0)},SceneJS.Node.prototype.getNodeAt=function(a){return 0>a||a>=this.nodes.length?null:this.nodes[a]},SceneJS.Node.prototype.getFirstNode=function(){return 0==this.nodes.length?null:this.nodes[0]},SceneJS.Node.prototype.getLastNode=function(){return 0==this.nodes.length?null:this.nodes[this.nodes.length-1]},SceneJS.Node.prototype.getNode=function(a){for(var b=0;b0?(b[0].parent=null,this._engine.display.objectListDirty=!0,b[0]):null},SceneJS.Node.prototype.disconnect=function(){if(this.parent){for(var a=0;ab;b++)this.nodes[b].parent=null;var c=this.nodes;return this.nodes=[],this._engine.display.objectListDirty=!0,c},SceneJS.Node.prototype.removeNodes=function(){for(var a=this.disconnectNodes(),b=0;ba;a++)d[a].parent=this.parent;for(a=0,b=c.nodes.length;b>a;a++)if(c.nodes[a]===this)return c.nodes.splice.apply(c.nodes,[a,1].concat(d)),this.nodes=[],this.parent=null,this.destroy(),this._engine.branchDirty(c),c},SceneJS.Node.prototype.addNodes=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNodes - nodes argument is undefined");for(var c,d=[],e=a.length,f=a.length-1;f>=0;f--){var g=a[f];if("node"==g.type||this._engine.hasNodeType(g.type)){if(c=this.addNode(g),d[f]=c,0==--e)return b&&b(a),a}else{var h=this;!function(){var c=f;h.addNode(g,function(f){d[c]=f,0==--e&&b&&b(a)})}()}}return null},SceneJS.Node.prototype.addNode=function(a,b){if(a=a||{},a._compile){if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if("string"==typeof a){var c=this._engine.findNode(a);if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node not found: '"+a+"'");if(a=c,null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if(a.type=a.type||"node","node"==a.type||this._engine.hasNodeType(a.type))return a=this._engine.createNode(a),this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a;var d=this;return this._engine.createNode(a,function(a){d.nodes.push(a),a.parent=d,d._engine.branchDirty(a),b&&b(a)}),null},SceneJS.Node.prototype.insertNode=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is undefined");if(a._compile||(a=this._engine.createNode(a)),!a._compile)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is not a SceneJS.Node");if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is still attached to another parent");if(void 0===b||null===b)a.addNodes(this.disconnectNodes()),this.addNode(a);else{if(0>b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node index out of range: -1");b>=this.nodes.length?this.nodes.push(a):this.nodes.splice(b,0,a)}return a.parent=this,a},SceneJS.Node.prototype.mapNodes=function(a){if(a(this))return this;for(var b,c=0;cg;g++)e=d[g],e.options.scope?e.fn.call(e.options.scope,f):e.fn.call(this,f)}},SceneJS.Node.prototype.removeListener=function(a,b){var c=this._listeners[a];if(!c)return null;for(var d=0;d0},SceneJS.Node.prototype.removeListeners=function(){return this._listeners={},this._numListeners=0,this},SceneJS.Node.prototype.getParent=function(a){return this.parent},SceneJS.Node.prototype.getParentOfType=function(a){for(var b=this.parent;b&&b.type!=a;)b=b.parent;return b},SceneJS.Node.prototype.eachParent=function(a){if(!a)throw"SceneJS.Node.eachParent param 'fn' is null or undefined";for(var b=0,c=this;c.parent;){if(a.call(c.parent,b++)===!0)return c.parent;c=c.parent}return null},SceneJS.Node.prototype.hasNode=function(a){if(null===a||void 0===a)throw"SceneJS.Node.hasNode param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.hasNode param 'node' should be either an index number or an ID string";b=this.getNode(a)}return void 0!=b&&null!=b},SceneJS.Node.prototype.node=function(a){if(null===a||void 0===a)throw"SceneJS.Node.node param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.node param 'node' should be either an index number or an ID string";b=this.getNode(a)}if(!b)throw"SceneJS.Node.node - node not found: '"+a+"'";return b},SceneJS.Node.prototype.eachNode=function(a,b){if(!a)throw"SceneJS.Node.eachNode param 'fn' is null or undefined";if("function"!=typeof a)throw"SceneJS.Node.eachNode param 'fn' should be a function";var c;b=b||{};var d=0;return b.andSelf&&a.call(this,d++)===!0?this:(b.depthFirst||b.breadthFirst?b.depthFirst&&(c=this._iterateEachNodeDepthFirst(a,this,d,!1)):c=this._iterateEachNode(a,this,d),c?c:void 0)},SceneJS.Node.prototype.numNodes=function(){return this.nodes.length},SceneJS.Node.prototype._iterateEachNode=function(a,b,c){for(var d,e=b.nodes.length,f=0;e>f;f++)if(d=b.nodes[f],a.call(d,c++)===!0)return d;return null},SceneJS.Node.prototype._iterateEachNodeDepthFirst=function(a,b,c,d){if(d&&a.call(b,c++)===!0)return b;d=!0;for(var e,f=b.nodes.length,g=0;f>g;g++)if(e=this._iterateEachNodeDepthFirst(a,b.nodes[g],c,d))return e;return null},SceneJS.Node.prototype.findNodesByType=function(a,b){return this._findNodesByType(a,[],b)},SceneJS.Node.prototype._findNodesByType=function(a,b,c){var d;for(d=0;dd;d++)c=this.nodes[d],c.branchDirty=c.branchDirty||this.branchDirty,(c.dirty||c.branchDirty||this._engine.sceneDirty)&&(c._compile(a),c.dirty=!1,c.branchDirty=!1);b&&SceneJS_nodeEventsModule.postVisitNode(this)},SceneJS.Node.prototype.destroy=function(){if(!this.destroyed){if(this.parent)for(var a=0;aa;a++)this.nodes[a]._destroyTree()},SceneJS.Node.prototype._doDestroy=function(){return this._destroy&&this._destroy(),this},SceneJS_PubSubProxy=function(a,b){this.scene=a,this.proxy=b};var SceneJS_NodeFactory=function(){this.nodes=new SceneJS_Map({})};SceneJS_NodeFactory.nodeTypes={},SceneJS_NodeFactory._subs={},SceneJS_NodeFactory.createNodeType=function(a,b,c){if(SceneJS_NodeFactory.nodeTypes[a])throw"Node type already defined: "+a;var d=function(){SceneJS.Node.apply(this,arguments),this.type=a};d.prototype=new SceneJS.Node,d.prototype.constructor=d,SceneJS_NodeFactory.nodeTypes[a]=d;var e=SceneJS_NodeFactory.nodeTypes[a];if(!e)throw"Node type plugin did not install itself correctly";c&&c(d);var f=SceneJS_NodeFactory._subs[a];if(f){for(;f.length>0;)f.pop()(e);delete f[a]}return d},SceneJS_NodeFactory.prototype.getNode=function(a,b,c,d){b.type=b.type||"node";var e;if(e="node"==b.type?SceneJS.Node:SceneJS_NodeFactory.nodeTypes[b.type])return this._createNode(e,a,b,c,d);var f=this;this._getType(a,b.type,function(e){f._createNode(e,a,b,c,d)})},SceneJS_NodeFactory.prototype._createNode=function(a,b,c,d,e){var f=new a,g=c.id||c.nodeId;return g?this.nodes.addItem(g,f):g=this.nodes.addItem(f),f._construct(b,d,c,g),e&&e(f),f},SceneJS_NodeFactory.prototype._getType=function(a,b,c){var d=SceneJS_NodeFactory.nodeTypes[b];if(d)return void c(d);var e=SceneJS_NodeFactory._subs[b]||(SceneJS_NodeFactory._subs[b]=[]);if(e.push(c),!(e.length>1)){var f=SceneJS_sceneStatusModule.taskStarted(a.scene,"Loading plugin");e.push(function(){SceneJS_sceneStatusModule.taskFinished(f)});var g=SceneJS_configsModule.configs.pluginPath; -if(!g)throw"no typePath config";this._loadScript(g+"/node/"+b+".js",function(){SceneJS_sceneStatusModule.taskFailed(f)})}},SceneJS_NodeFactory.prototype._loadScript=function(a,b){var c=document.createElement("script");c.type="text/javascript",c.src=a,c.onerror=b,document.getElementsByTagName("head")[0].appendChild(c)},SceneJS_NodeFactory.prototype.putNode=function(a){this.nodes.removeItem(a.id)},function(){function a(a){var b=a.optics;if("ortho"==b.type?a.matrix=SceneJS_math_orthoMat4c(b.left,b.right,b.bottom,b.top,b.near,b.far):"frustum"==b.type?a.matrix=SceneJS_math_frustumMatrix4(b.left,b.right,b.bottom,b.top,b.near,b.far):"perspective"==b.type&&(a.matrix=SceneJS_math_perspectiveMatrix4(b.fovy*Math.PI/180,b.aspect,b.near,b.far)),a.pan){var c=a.pan,d=SceneJS_math_translationMat4v([c.x||0,c.y||0,c.z||0]);a.matrix=SceneJS_math_mulMat4(d,a.matrix,[])}a.mat?a.mat.set(a.matrix):a.mat=new Float32Array(a.matrix)}var b=SceneJS_math_perspectiveMatrix4(45,1,.1,1e4),c=new Float32Array(b),d={type:"camera",stateId:SceneJS._baseStateId++,matrix:b,mat:c,optics:{type:"perspective",fovy:45,aspect:1,near:.1,far:1e4},checkAspect:function(b,c){b.optics.aspect!=c&&(b.optics.aspect=c,a(this))}},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.projTransform=d,f=0}),SceneJS.Camera=SceneJS_NodeFactory.createNodeType("camera"),SceneJS.Camera.prototype._init=function(b){if(1==this._core.useCount){b.optics=b.optics||{};var c=this.getScene().getCanvas();b.optics.aspect=c.width/c.height,this.setOptics(b.optics),b.pan&&this.setPan(b.pan);var d=this;this._canvasSizeSub=this.getScene().on("canvasSize",function(b){d._core.optics.aspect=b.aspect,a(d._core),d._engine.display.imageDirty=!0})}},SceneJS.Camera.getDefaultMatrix=function(){return c},SceneJS.Camera.prototype.setOptics=function(b){var c=this._core;if(b){var d=b.type||c.optics.type||"perspective";if("ortho"==d)c.optics=SceneJS._applyIf(SceneJS_math_ORTHO_OBJ,{type:d,left:b.left,bottom:b.bottom,near:b.near,right:b.right,top:b.top,far:b.far});else if("frustum"==d)c.optics={type:d,left:b.left||-1,bottom:b.bottom||-1,near:b.near||.1,right:b.right||1,top:b.top||1,far:b.far||1e4};else{if("perspective"!=d)throw b.type?SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not supported - supported types are 'perspective', 'frustum' and 'ortho'"):SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not specified - supported types are 'perspective', 'frustum' and 'ortho'");c.optics={type:d,fovy:b.fovy||60,aspect:void 0==b.aspect?1:b.aspect,near:b.near||.1,far:b.far||1e4}}}else c.optics={type:"perspective",fovy:60,aspect:1,near:.1,far:1e4};this._core.optics.pan=b.pan,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.setPan=function(b){this._core.pan=b,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.getOptics=function(){var a={};for(var b in this._core.optics)this._core.optics.hasOwnProperty(b)&&(a[b]=this._core.optics[b]);return a},SceneJS.Camera.prototype.getMatrix=function(){return this._core.matrix.slice(0)},SceneJS.Camera.prototype._compile=function(a){this._engine.display.projTransform=e[f++]=this._core,this._compileNodes(a),this._engine.display.projTransform=--f>0?e[f-1]:d},SceneJS.Camera.prototype._destroy=function(){this.getScene().off(this._canvasSizeSub)}}(),function(){var a={type:"clips",stateId:SceneJS._baseStateId++,empty:!0,hash:"",clips:[]},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.clips=a,c=0}),SceneJS.Clips=SceneJS_NodeFactory.createNodeType("clips"),SceneJS.Clips.prototype._init=function(a){if(1==this._core.useCount){var b=a.clips;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"clips node attribute missing : 'clips'");this._core.clips=this._core.clips||[];for(var c=0,d=b.length;d>c;c++)this._setClip(c,b[c])}},SceneJS.Clips.prototype.setClips=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.clips.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'clips': index out of range ("+this._core.clips.length+" clips defined)");this._setClip(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Clips.prototype._setClip=function(a,b){var c=this._core.clips[a]||(this._core.clips[a]={});c.normalAndDist=[b.x||0,b.y||0,b.z||0,b.dist||0];var d=b.mode||c.mode||"disabled";if("inside"!=d&&"outside"!=d&&"disabled"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'");c.mode=d,this._core.hash=null},SceneJS.Clips.prototype._compile=function(d){this._core.hash||(this._core.hash=this._core.clips.length),this._engine.display.clips=b[c++]=this._core,this._compileNodes(d),this._engine.display.clips=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"enable",enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.enable=a,c=0}),SceneJS.Enable=SceneJS_NodeFactory.createNodeType("enable"),SceneJS.Enable.prototype._init=function(a){1==this._core.useCount&&(this._core.enabled=!0,void 0!=a.enabled&&this.setEnabled(a.enabled))},SceneJS.Enable.prototype.setEnabled=function(a){return a!==this._core.enabled&&(this._core.enabled=a,this._engine.display.drawListDirty=!0,this.publish("enabled",a)),this},SceneJS.Enable.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Enable.prototype._compile=function(d){this._engine.display.enable=b[c++]=this._core,this._compileNodes(d),this._engine.display.enable=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"flags",picking:!0,clipping:!0,enabled:!0,transparent:!1,backfaces:!0,frontface:"ccw",reflective:!0,solid:!0,hash:"refl;s;"},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.flags=a,c=0}),SceneJS.Flags=SceneJS_NodeFactory.createNodeType("flags"),SceneJS.Flags.prototype._init=function(a){1==this._core.useCount&&(this._core.picking=!0,this._core.clipping=!0,this._core.enabled=!0,this._core.transparent=!1,this._core.backfaces=!0,this._core.frontface="ccw",this._core.reflective=!0,this._core.solid=!0,a.flags&&this.setFlags(a.flags))},SceneJS.Flags.prototype.setFlags=function(a){var b=this._core;return void 0!=a.picking&&(b.picking=!!a.picking,this._engine.display.drawListDirty=!0),void 0!=a.clipping&&(b.clipping=!!a.clipping,this._engine.display.imageDirty=!0),void 0!=a.enabled&&(b.enabled=!!a.enabled,this._engine.display.drawListDirty=!0),void 0!=a.transparent&&(b.transparent=!!a.transparent,this._engine.display.stateSortDirty=!0),void 0!=a.backfaces&&(b.backfaces=!!a.backfaces,this._engine.display.imageDirty=!0),void 0!=a.frontface&&(b.frontface=a.frontface,this._engine.display.imageDirty=!0),void 0!=a.reflective&&(b.reflective=a.reflective,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),void 0!=a.solid&&(b.solid=a.solid,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.addFlags=function(a){return this.setFlags(a)},SceneJS.Flags.prototype.getFlags=function(){var a=this._core;return{picking:a.picking,clipping:a.clipping,enabled:a.enabled,transparent:a.transparent,backfaces:a.backfaces,frontface:a.frontface,reflective:a.reflective,solid:a.solid}},SceneJS.Flags.prototype.setPicking=function(a){return a=!!a,this._core.picking!=a&&(this._core.picking=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getPicking=function(){return this._core.picking},SceneJS.Flags.prototype.setClipping=function(a){return a=!!a,this._core.clipping!=a&&(this._core.clipping=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getClipping=function(){return this._core.clipping},SceneJS.Flags.prototype.setEnabled=function(a){return a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Flags.prototype.setTransparent=function(a){return a=!!a,this._core.transparent!=a&&(this._core.transparent=a,this._engine.display.stateOrderDirty=!0),this},SceneJS.Flags.prototype.getTransparent=function(){return this._core.transparent},SceneJS.Flags.prototype.setBackfaces=function(a){return a=!!a,this._core.backfaces!=a&&(this._core.backfaces=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getBackfaces=function(){return this._core.backfaces},SceneJS.Flags.prototype.setFrontface=function(a){return this._core.frontface!=a&&(this._core.frontface=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getFrontface=function(){return this._core.frontface},SceneJS.Flags.prototype.setReflective=function(a){return a=!!a,this._core.reflective!=a&&(this._core.reflective=a,this._core.hash=(a?"refl":"")+this._core.solid?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getReflective=function(){return this._core.reflective},SceneJS.Flags.prototype.setSolid=function(a){return a=!!a,this._core.solid!=a&&(this._core.solid=a,this._core.hash=(this._core.reflective?"refl":"")+a?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getSolid=function(){return this._core.solid},SceneJS.Flags.prototype._compile=function(d){this._engine.display.flags=b[c++]=this._core,this._compileNodes(d),this._engine.display.flags=--c>0?b[c-1]:a}}(),new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._core.renderBuf.webglRestored()}),SceneJS.ColorTarget=SceneJS_NodeFactory.createNodeType("colorTarget"),SceneJS.ColorTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="color",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.ColorTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.ColorTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._buildNodeCore()}),SceneJS.DepthTarget=SceneJS_NodeFactory.createNodeType("depthTarget"),SceneJS.DepthTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="depth",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.DepthTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.DepthTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a=[],b=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){b=0}),SceneJS.Geometry=SceneJS_NodeFactory.createNodeType("geometry"),SceneJS.Geometry.prototype._init=function(a){if(1==this._core.useCount){this._initNodeCore(a,{origin:a.origin,scale:a.scale,autoNormals:"auto"==a.normals}),this._buildNodeCore(this._engine.canvas.gl,this._core);var b=this;this._core.webglRestored=function(){b._buildNodeCore(b._engine.canvas.gl,b._core)}}},SceneJS.Geometry.prototype._initNodeCore=function(a,b){var c=this;b=b||{};var d=a.primitive||"triangles",e=this._core,f=this._engine.canvas.UINT_INDEX_ENABLED?Uint32Array:Uint16Array;e.primitive=this._getPrimitiveType(d),a.normals&&"triangles"==d&&("auto"===a.normals||a.normals===!0)&&a.positions&&a.indices&&this._buildNormals(a),e.arrays={positions:a.positions?new Float32Array(b.scale||b.origin?this._applyOptions(a.positions,b):a.positions):void 0,normals:a.normals?new Float32Array(a.normals):void 0,uv:a.uv?new Float32Array(a.uv):void 0,uv2:a.uv2?new Float32Array(a.uv2):void 0,colors:a.colors?new Float32Array(a.colors):void 0,indices:a.indices?new f(a.indices):void 0},delete a.positions,delete a.normals,delete a.uv,delete a.uv2,delete a.indices,delete a.colors,e.getTangentBuf=function(){if(e.tangentBuf)return e.tangentBuf;var a=e.arrays;if(a.positions&&a.indices&&a.uv){var b=c._engine.canvas.gl,d=new Float32Array(c._buildTangents(a));e.arrays.tangents=d;var f=b.STATIC_DRAW;return e.tangentBuf=new SceneJS._webgl.ArrayBuffer(b,b.ARRAY_BUFFER,d,d.length,3,f)}}},SceneJS.Geometry.prototype._getPrimitiveType=function(a){var b=this._engine.canvas.gl;switch(a){case"points":return b.POINTS;case"lines":return b.LINES;case"line-loop":return b.LINE_LOOP;case"line-strip":return b.LINE_STRIP;case"triangles":return b.TRIANGLES;case"triangle-strip":return b.TRIANGLE_STRIP;case"triangle-fan":return b.TRIANGLE_FAN;default:throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"geometry primitive unsupported: '"+a+"' - supported types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'")}},SceneJS.Geometry.prototype._applyOptions=function(a,b){var c=a.slice?a.slice(0):new Float32Array(a);if(b.scale)for(var d=void 0!=b.scale.x?b.scale.x:1,e=void 0!=b.scale.y?b.scale.y:1,f=void 0!=b.scale.z?b.scale.z:1,g=0,h=c.length;h>g;g+=3)c[g]*=d,c[g+1]*=e,c[g+2]*=f;if(b.origin)for(var i=void 0!=b.origin.x?b.origin.x:0,j=void 0!=b.origin.y?b.origin.y:0,k=void 0!=b.origin.z?b.origin.z:0,g=0,h=c.length;h>g;g+=3)c[g]-=i,c[g+1]-=j,c[g+2]-=k;return c};var c=function(a){a.vertexBuf&&(a.vertexBuf.destroy(),a.vertexBuf=null),a.normalBuf&&(a.normalBuf.destroy(),a.normalBuf=null),a.uvBuf&&(a.uvBuf.destroy(),a.uvBuf=null),a.uvBuf2&&(a.uvBuf2.destroy(),a.uvBuf2=null),a.colorBuf&&(a.colorBuf.destroy(),a.colorBuf=null),a.tangentBuf&&(a.tangentBuf.destroy(),a.tangentBuf=null),a.indexBuf&&(a.indexBuf.destroy(),a.indexBuf=null),a.interleavedBuf&&(a.interleavedBuf.destroy(),a.interleavedBuf=null)};SceneJS.Geometry.prototype._buildNodeCore=function(a,b){var d=a.STATIC_DRAW;try{var e=b.arrays,f=SceneJS.getConfigs("enableInterleaving")!==!1,g=0,h=0,i=[],j=[],k=function(a,b){return 0==g?g=a.length/b:a.length/b!=g&&(f=!1),i.push(a),j.push(b),h+=b,4*(h-b)};if(e.positions&&(f&&(b.interleavedPositionOffset=k(e.positions,3)),b.vertexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.positions,e.positions.length,3,d)),e.normals&&(f&&(b.interleavedNormalOffset=k(e.normals,3)),b.normalBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.normals,e.normals.length,3,d)),e.uv&&(f&&(b.interleavedUVOffset=k(e.uv,2)),b.uvBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv,e.uv.length,2,d)),e.uv2&&(f&&(b.interleavedUV2Offset=k(e.uv2,2)),b.uvBuf2=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv2,e.uv2.length,2,d)),e.colors&&(f&&(b.interleavedColorOffset=k(e.colors,4)),b.colorBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.colors,e.colors.length,4,d)),e.indices&&(b.indexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ELEMENT_ARRAY_BUFFER,e.indices,e.indices.length,1,d)),h>0&&f){for(var l=[],m=i.length,n=0;g>n;++n)for(var o=0;m>o;++o)for(var p=j[o],q=0;p>q;++q)l.push(i[o][n*p+q]);b.interleavedStride=4*h,b.interleavedBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,new Float32Array(l),l.length,h,d),b.interleavedBuf.dirty=!1}}catch(r){throw c(b),SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate geometry: "+r)}},SceneJS.Geometry.prototype._updateArray=function(a,b,c){var d=a.length,e=b.length;e+c>d&&(e-=e+c-d);for(var f=c,g=0;e>g;f++,g++)a[f]=b[g]},SceneJS.Geometry.prototype._buildNormals=function(a){for(var b,c,d,e,f,g,h=a.positions,i=a.indices,j=new Array(h.length/3),k=0,l=i.length-3;l>k;k+=3){b=i[k+0],c=i[k+1],d=i[k+2],e=[h[3*b+0],h[3*b+1],h[3*b+2]],f=[h[3*c+0],h[3*c+1],h[3*c+2]],g=[h[3*d+0],h[3*d+1],h[3*d+2]],f=SceneJS_math_subVec4(f,e,[0,0,0,0]),g=SceneJS_math_subVec4(g,e,[0,0,0,0]);var m=SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(f,g,[0,0,0,0]),[0,0,0,0]);j[b]||(j[b]=[]),j[c]||(j[c]=[]),j[d]||(j[d]=[]),j[b].push(m),j[c].push(m),j[d].push(m)}for(var n=new Array(h.length),k=0,l=j.length;l>k;k++){for(var o=j[k].length,p=0,q=0,r=0,s=0;o>s;s++)p+=j[k][s][0],q+=j[k][s][1],r+=j[k][s][2];n[3*k+0]=p/o,n[3*k+1]=q/o,n[3*k+2]=r/o}a.normals=n},SceneJS.Geometry.prototype._buildTangents=function(a){for(var b=a.positions,c=a.indices,d=a.uv,e=[],f=0;ft;t++){var u=c[f+t];"undefined"!=typeof e[u]?e[u]=SceneJS_math_addVec3(e[u],s,[]):e[u]=s}}for(var v=[],w=0;wf;f+=3)c=b[f],d=b[f+1],e=b[f+2],cthis._boundary.xmax&&(this._boundary.xmax=c),d>this._boundary.ymax&&(this._boundary.ymax=d),e>this._boundary.zmax&&(this._boundary.zmax=e);return this._boundary},SceneJS.Geometry.prototype._compile=function(c){if(this._core._loading)return void this._compileNodes(c);var d=this._core;d.vertexBuf||(d=this._inheritVBOs(d)),d.indexBuf?(d.hash=[d.normalBuf?"t":"f",d.arrays&&d.arrays.tangents?"t":"f",d.uvBuf?"t":"f",d.uvBuf2?"t":"f",d.colorBuf?"t":"f",d.primitive].join(""),d.stateId=this._core.stateId,d.type="geometry",this._engine.display.geometry=a[b++]=d,SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING,{display:this._engine.display}),this._engine.display.buildObject(this.id)):a[b++]=this._core,this._compileNodes(c),b--},SceneJS.Geometry.prototype._inheritVBOs=function(c){for(var d={primitive:c.primitive,boundary:c.boundary,normalBuf:c.normalBuf,uvBuf:c.uvBuf,uvBuf2:c.uvBuf2,colorBuf:c.colorBuf,interleavedBuf:c.interleavedBuf,indexBuf:c.indexBuf,interleavedStride:c.interleavedStride,interleavedPositionOffset:c.interleavedPositionOffset,interleavedNormalOffset:c.interleavedNormalOffset,interleavedUVOffset:c.interleavedUVOffset,interleavedUV2Offset:c.interleavedUV2Offset,interleavedColorOffset:c.interleavedColorOffset},e=b-1;e>=0;e--)if(a[e].vertexBuf)return d.vertexBuf=a[e].vertexBuf,d.boundary=a[e].boundary,d.normalBuf=a[e].normalBuf,d.uvBuf=a[e].uvBuf,d.uvBuf2=a[e].uvBuf2,d.colorBuf=a[e].colorBuf,d.interleavedBuf=a[e].interleavedBuf,d.interleavedStride=a[e].interleavedStride,d.interleavedPositionOffset=a[e].interleavedPositionOffset,d.interleavedNormalOffset=a[e].interleavedNormalOffset,d.interleavedUVOffset=a[e].interleavedUVOffset,d.interleavedUV2Offset=a[e].interleavedUV2Offset,d.interleavedColorOffset=a[e].interleavedColorOffset,d;return d},SceneJS.Geometry.prototype._destroy=function(){this._engine.display.removeObject(this.id),1==this._core.useCount&&(this._destroyNodeCore(),this._source&&this._source.destroy&&this._source.destroy())},SceneJS.Geometry.prototype._destroyNodeCore=function(){document.getElementById(this._engine.canvas.canvasId)&&c(this._core)}},function(){var a={type:"stage",stateId:SceneJS._baseStateId++,priority:0,pickable:!0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.stage=a,c=0}),SceneJS.Stage=SceneJS_NodeFactory.createNodeType("stage"),SceneJS.Stage.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1,this._core.pickable=!!a.pickable)},SceneJS.Stage.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Stage.prototype.getPriority=function(){return this._core.priority},SceneJS.Stage.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype._compile=function(d){this._engine.display.stage=b[c++]=this._core,this._compileNodes(d),this._engine.display.stage=--c>0?b[c-1]:a}}(),function(){var a={type:"layer",stateId:SceneJS._baseStateId++,priority:0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.layer=a,c=0}),SceneJS.Layer=SceneJS_NodeFactory.createNodeType("layer"),SceneJS.Layer.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1)},SceneJS.Layer.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Layer.prototype.getPriority=function(){return this._core.priority},SceneJS.Layer.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.setClearDepth=function(a){a=a||0,this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Layer.prototype._compile=function(d){this._engine.display.layer=b[c++]=this._core,this._compileNodes(d),this._engine.display.layer=--c>0?b[c-1]:a}}(),SceneJS.Library=SceneJS_NodeFactory.createNodeType("library"),SceneJS.Library.prototype._compile=function(a){},function(){function a(a){if(a.lights&&a.lights.length>0){for(var b,c=a.lights,d=[],e=0,f=c.length;f>e;e++)b=c[e],d.push(b.mode),b.specular&&d.push("s"),b.diffuse&&d.push("d"),d.push("world"==b.space?"w":"v");a.hash=d.join("")}else a.hash=""}var b={type:"lights",stateId:SceneJS._baseStateId++,hash:null,empty:!1,lights:[{mode:"ambient",color:[.7,.7,.8],diffuse:!0,specular:!1},{mode:"dir",color:[1,1,1],diffuse:!0,specular:!0,dir:[-.5,-.5,-1],space:"view"},{mode:"dir",color:[1,1,1],diffuse:!1,specular:!0,dir:[1,-.9,-.7],space:"view"}]};a(b);var c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.lights=b,d=0}),SceneJS.Lights=SceneJS_NodeFactory.createNodeType("lights"),SceneJS.Lights.prototype._init=function(a){if(1==this._core.useCount){var b=a.lights;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"lights node attribute missing : 'lights'");this._core.lights=this._core.lights||[];for(var c=0,d=b.length;d>c;c++)this._initLight(c,b[c])}},SceneJS.Lights.prototype._initLight=function(a,b){var c=[];this._core.lights[a]=c;var d=b.mode||"dir";if("dir"!=d&&"point"!=d&&"ambient"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");var e=b.pos,f=b.dir,g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],c.mode=d,c.diffuse="ambient"==d?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==d?!1:void 0!=b.specular?b.specular:!0,c.pos=b.pos?[e.x||0,e.y||0,e.z||0]:[0,0,0],c.dir=b.dir?[f.x||0,f.y||0,f.z||0]:[0,0,1],c.attenuation=[void 0!=b.constantAttenuation?b.constantAttenuation:0,b.linearAttenuation||0,b.quadraticAttenuation||0];var h=b.space;if(h){if("view"!=h&&"world"!=h)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+h+"' - should be 'view' or 'world'")}else h="world";c.space=h,this._core.hash=null},SceneJS.Lights.prototype.setLights=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.lights.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'lights': index out of range ("+this._core.lights.length+" lights defined)");this._setLight(b,a[c]||{})}this._engine.branchDirty(this)},SceneJS.Lights.prototype._setLight=function(a,b){var c=this._core.lights[a],d=!1,e=!1;if(b.mode&&b.mode!=c.mode){var f=b.mode;if("dir"!=f&&"point"!=f&&"ambient"!=f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");c.mode=f,c.diffuse="ambient"==f?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==f?!1:void 0!=b.specular?b.specular:!0,e=!0}if(b.color){var g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],d=!0}var h=b.pos;h&&(c.pos=[h.x||0,h.y||0,h.z||0],d=!0);var i=b.dir;if(i&&(c.dir=[i.x||0,i.y||0,i.z||0],d=!0),void 0!=b.constantAttenuation&&(c.attenuation[0]=b.constantAttenuation,d=!0),void 0!=b.linearAttenuation&&(c.attenuation[1]=b.linearAttenuation,d=!0),void 0!=b.quadraticAttenuation&&(c.attenuation[2]=b.quadraticAttenuation,d=!0),b.space&&b.space!=c.space){var j=b.space;if("view"!=j&&"world"!=j)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+j+"' - should be 'view' or 'world'");c.space=j,this._core.hash=null,e=!0}void 0!=b.specular&&b.specular!=c.specular&&(c.specular=b.specular,e=!0),void 0!=b.diffuse&&b.diffuse!=c.diffuse&&(c.diffuse=b.diffuse,e=!0),e?this._engine.branchDirty(this):d&&(this._engine.display.imageDirty=!0),this._core.hash=null},SceneJS.Lights.prototype._compile=function(e){this._core.hash||a(this._core),this._engine.display.lights=c[d++]=this._core,this._compileNodes(e),this._engine.display.lights=--d>0?c[d-1]:b}}(),function(){var a=SceneJS_math_lookAtMat4c(0,0,10,0,0,0,0,1,0),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4())),d=new Float32Array(c),e={type:"lookAt",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,lookAt:SceneJS_math_LOOKAT_ARRAYS},f=[],g=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.viewTransform=e,g=0}),SceneJS.Lookat=SceneJS_NodeFactory.createNodeType("lookAt"),SceneJS.Lookat.prototype._init=function(a){if(this._mat=null,this._xf={type:"lookat"},1==this._core.useCount){this._core.eyeX=0,this._core.eyeY=0,this._core.eyeZ=10,this._core.lookX=0,this._core.lookY=0,this._core.lookZ=0,this._core.upX=0,this._core.upY=1,this._core.upZ=0,a.eye||a.look||a.up?(this.setEye(a.eye),this.setLook(a.look),this.setUp(a.up)):(this.setEye({x:0,y:0,z:10}),this.setLook({x:0,y:0,z:0}),this.setUp({x:0,y:1,z:0}));var b=this._core,c=this;this._core.rebuild=function(){b.matrix=SceneJS_math_lookAtMat4c(b.eyeX,b.eyeY,b.eyeZ,b.lookX,b.lookY,b.lookZ,b.upX,b.upY,b.upZ),b.lookAt={eye:[b.eyeX,b.eyeY,b.eyeZ],look:[b.lookX,b.lookY,b.lookZ],up:[b.upX,b.upY,b.upZ]},b.mat?(b.mat.set(b.matrix),b.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))):(b.mat=new Float32Array(b.matrix),b.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))),c.publish("matrix",b.matrix),b.dirty=!1},this._core.dirty=!0,this._tick=this.getScene().on("tick",function(){c._core.dirty&&c._core.rebuild()})}},SceneJS.Lookat.getDefaultMatrix=function(){return b},SceneJS.Lookat.prototype.setEye=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.eyeX=a.x),void 0!=a.y&&null!=a.y&&(this._core.eyeY=a.y),void 0!=a.z&&null!=a.z&&(this._core.eyeZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEye=function(a){return a=a||{},this._core.eyeX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.eyeY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.eyeZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeX=function(a){return this._core.eyeX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeY=function(a){return this._core.eyeY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0, -this},SceneJS.Lookat.prototype.setEyeZ=function(a){return this._core.eyeZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeX=function(a){return this._core.eyeX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeY=function(a){return this._core.eyeY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeZ=function(a){return this._core.eyeZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getEye=function(){return{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ}},SceneJS.Lookat.prototype.setLook=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.lookX=a.x),void 0!=a.y&&null!=a.y&&(this._core.lookY=a.y),void 0!=a.z&&null!=a.z&&(this._core.lookZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLook=function(a){return a=a||{},this._core.lookX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.lookY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.lookZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookX=function(a){return this._core.lookX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookY=function(a){return this._core.lookY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookZ=function(a){return this._core.lookZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookX=function(a){return this._core.lookX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookY=function(a){return this._core.lookY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookZ=function(a){return this._core.lookZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getLook=function(){return{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ}},SceneJS.Lookat.prototype.setUp=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.upX=a.x),void 0!=a.y&&null!=a.y&&(this._core.upY=a.y),void 0!=a.z&&null!=a.z&&(this._core.upZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUp=function(a){return a=a||{},this._core.upX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.upY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.upZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpX=function(a){return this._core.upX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpY=function(a){return this._core.upY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpZ=function(a){return this._core.upZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpX=function(a){return this._core.upX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpY=function(a){return this._core.upY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpZ=function(a){return this._core.upZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getUp=function(){return{x:this._core.upX,y:this._core.upY,z:this._core.upZ}},SceneJS.Lookat.prototype.getMatrix=function(){return this._core.dirty&&this._core.rebuild(),this._core.matrix.slice(0)},SceneJS.Lookat.prototype.getAttributes=function(){return{look:{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ},eye:{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ},up:{x:this._core.upX,y:this._core.upY,z:this._core.upZ}}},SceneJS.Lookat.prototype._compile=function(a){this._engine.display.viewTransform=f[g++]=this._core,this._compileNodes(a),this._engine.display.viewTransform=--g>0?f[g-1]:e},SceneJS.Lookat.prototype._destroy=function(){this.getScene().off(this._tick)}}(),new function(){var a={type:"material",stateId:SceneJS._baseStateId++,baseColor:[1,1,1],specularColor:[1,1,1],specular:1,shine:70,alpha:1,emit:0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.material=a,c=0}),SceneJS.Material=SceneJS_NodeFactory.createNodeType("material"),SceneJS.Material.prototype._init=function(a){1==this._core.useCount&&(this.setBaseColor(a.color||a.baseColor),this.setSpecularColor(a.specularColor),this.setSpecular(a.specular),this.setShine(a.shine),this.setEmit(a.emit),this.setAlpha(a.alpha))},SceneJS.Material.prototype.setBaseColor=function(b){var c=a.baseColor;return this._core.baseColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.baseColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.setColor=SceneJS.Material.prototype.setBaseColor,SceneJS.Material.prototype.getBaseColor=function(){return{r:this._core.baseColor[0],g:this._core.baseColor[1],b:this._core.baseColor[2]}},SceneJS.Material.prototype.getColor=SceneJS.Material.prototype.getBaseColor,SceneJS.Material.prototype.setSpecularColor=function(b){var c=a.specularColor;return this._core.specularColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.specularColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecularColor=function(){return{r:this._core.specularColor[0],g:this._core.specularColor[1],b:this._core.specularColor[2]}},SceneJS.Material.prototype.setSpecular=function(b){return this._core.specular=void 0!=b&&null!=b?b:a.specular,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecular=function(){return this._core.specular},SceneJS.Material.prototype.setShine=function(b){return this._core.shine=void 0!=b&&null!=b?b:a.shine,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getShine=function(){return this._core.shine},SceneJS.Material.prototype.setEmit=function(b){return this._core.emit=void 0!=b&&null!=b?b:a.emit,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getEmit=function(){return this._core.emit},SceneJS.Material.prototype.setAlpha=function(b){return this._core.alpha=void 0!=b&&null!=b?b:a.alpha,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getAlpha=function(){return this._core.alpha},SceneJS.Material.prototype._compile=function(d){this._engine.display.material=b[c++]=this._core,this._compileNodes(d),this._engine.display.material=--c>0?b[c-1]:a}},new function(){var a={type:"morphGeometry",stateId:SceneJS._baseStateId++,hash:"",morph:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.morphGeometry=a,c=0}),SceneJS.MorphGeometry=SceneJS_NodeFactory.createNodeType("morphGeometry"),SceneJS.MorphGeometry.prototype._init=function(a){if(1==this._core.useCount){if(this._sourceConfigs=a.source,this._source=null,a.source){if(!a.source.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry config expected: source.type");var b=this;SceneJS.Plugins.getPlugin("morphGeometry",this._sourceConfigs.type,function(c){if(!c)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: no support for source type '"+b._sourceConfigs.type+"' - need to include plugin for self source type, or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '"+b._sourceConfigs.type+"', ).");if(!c.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)");if(b._source=c.getSource(),!b._source.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'subscribe' method not found on source provided by plugin type '"+a.source.type+"'");var d=!1;b._source.subscribe(function(a){if(d){if(a.targets)for(var c,e,f,g=a.targets,h=b._core.targets,i=0,j=g.length;j>i;i++)c=g[i],e=c.targetIndex,f=h[e],c.positions&&f.vertexBuf&&(f.vertexBuf.bind(),f.vertexBuf.setData(c.positions,0));b._display.imageDirty=!0}else b._buildNodeCore(a),b._core._loading=!1,b._fireEvent("loaded"),b._engine.branchDirty(b),d=!0}),b._core._loading=!0,b._fireEvent("loading"),b._source.configure(b._sourceConfigs)})}else a.create instanceof Function?this._buildNodeCore(a.create()):this._buildNodeCore(a);this._core.webglRestored=function(){},this.setFactor(a.factor)}this._core.factor=a.factor||0,this._core.clamp=!!a.clamp},SceneJS.MorphGeometry.prototype._buildNodeCore=function(a){var b=a.targets||[];if(b.length<2)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node should have at least two targets");var c=a.keys||[];if(c.length!=b.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node mismatch in number of keys and targets");var d=this._core,e=this._engine.canvas.gl,f=e.STATIC_DRAW;d.keys=c,d.targets=[],d.key1=0,d.key2=1;for(var g,h,i,j,k,l=0,m=b.length;m>l;l++)k=b[l],!g&&k.positions&&(g=k.positions),!h&&k.normals&&(h=k.normals),!i&&k.uv&&(i=k.uv),!j&&k.uv2&&(j=k.uv2);try{for(var n,o,l=0,m=b.length;m>l;l++)k=b[l],n={},o=k.positions||g,o&&(n.positions="Float32Array"==typeof o?o:new Float32Array(o),n.vertexBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.positions,o.length,3,f),g=o),o=k.normals||h,o&&(n.normals="Float32Array"==typeof o?o:new Float32Array(o),n.normalBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.normals,o.length,3,f),h=o),o=k.uv||i,o&&(n.uv="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv,o.length,2,f),i=o),o=k.uv2||j,o&&(n.uv2="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf2=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv2,o.length,2,f),j=o),d.targets.push(n)}catch(p){for(var l=0,m=d.targets.length;m>l;l++)n=d.targets[l],n.vertexBuf&&n.vertexBuf.destroy(),n.normalBuf&&n.normalBuf.destroy(),n.uvBuf&&n.uvBuf.destroy(),n.uvBuf2&&n.uvBuf2.destroy();throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate VBO(s) for morphGeometry: "+p)}},SceneJS.MorphGeometry.prototype.setSource=function(a){this._sourceConfigs=a;var b=this._source;b&&b.configure(a)},SceneJS.MorphGeometry.prototype.getSource=function(){return this._sourceConfigs},SceneJS.MorphGeometry.prototype.setFactor=function(a){a=a||0;var b=this._core,c=b.keys,d=b.key1,e=b.key2,f=b.factor;if(ac[c.length-1])d=c.length-2,e=d+1;else{for(;c[d]>a;)d--,e--;for(;c[e]0?b[c-1]:a},SceneJS.MorphGeometry.prototype._makeHash=function(){var a=this._core;if(a.targets.length>0){var b=a.targets[0],c="t",d="f";a.hash=[b.vertexBuf?c:d,b.normalBuf?c:d,b.uvBuf?c:d,b.uvBuf2?c:d].join("")}else a.hash=""},SceneJS.MorphGeometry.prototype._destroy=function(){if(1==this._core.useCount){if(document.getElementById(this._engine.canvas.canvasId))for(var a,b=this._core,c=0,d=b.targets.length;d>c;c++)a=b.targets[c],a.vertexBuf&&a.vertexBuf.destroy(),a.normalBuf&&a.normalBuf.destroy(),a.uvBuf&&a.uvBuf.destroy(),a.uvBuf2&&a.uvBuf2.destroy();this._source&&this._source.destroy&&this._source.destroy()}}},function(){var a={type:"name",stateId:SceneJS._baseStateId++,name:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.name=a,c=0}),SceneJS.Name=SceneJS_NodeFactory.createNodeType("name"),SceneJS.Name.prototype._init=function(a){this.setName(a.name),this._core.nodeId=this.id},SceneJS.Name.prototype.setName=function(a){this._core.name=a||"unnamed",this._engine.branchDirty(this)},SceneJS.Name.prototype.getName=function(){return this._core.name},SceneJS.Name.prototype._compile=function(d){this._engine.display.name=b[c++]=this._core;for(var e,f=[],g=0;c>g;g++)e=b[g].name,e&&f.push(e);this._core.path=f.join("."),this._compileNodes(d),this._engine.display.name=--c>0?b[c-1]:a}}(),new function(){function a(a){var c;if(f>0){c={};for(var d in a)a.hasOwnProperty(d)&&void 0!=a[d]&&(c[d]=g(d))}return b(a.props),{props:a,setProps:function(b){h(b,a)},restoreProps:function(a){c&&i(a,c)}}}function b(a){var b;for(var c in a)a.hasOwnProperty(c)&&(b=a[c],void 0!=b&&null!=b&&(k[c]?a[c]=k[c](null,b):l[c]&&(a[c]=l[c](null,b))))}var c,d={type:"renderer",stateId:SceneJS._baseStateId++,props:null},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){c=a.engine.canvas,f=0,a.engine.display.renderer=e[f++]=d});var g=function(a){for(var b,c,d=f-1;d>=0;d--)if(b=e[d].props,b&&(c=b[a],void 0!=c&&null!=c))return b[a];return null},h=function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=k[c];d&&d(a,b[c])}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor),b.clear&&l.clear(a,b.clear)},i=function(a,b){var c;for(var d in b)if(b.hasOwnProperty(d)&&(c=b[d],void 0!=c&&null!=c)){var e=k[d];e&&e(a,c)}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor)},j=function(a,b){if(!b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Null SceneJS.State node config: "'+b+'"');var c=SceneJS._webgl.enumMap[b];if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Unrecognised SceneJS.State node config value: "'+b+'"');var d=a[c];if(!d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"This browser's WebGL does not support renderer node config value: \""+b+'"');return d},k={enableBlend:function(a,b){return a?void(b?a.enable(a.BLEND):a.disable(a.BLEND)):((null==b||void 0==b)&&(b=!1),b)},blendColor:function(a,b){return a?void a.blendColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},blendEquation:function(a,b){return a?void a.blendEquation(a,j(a,b)):b||"funcAdd"},blendEquationSeparate:function(a,b){return a?void a.blendEquation(j(a,b.rgb),j(a,b.alpha)):(b=b||{},{rgb:b.rgb||"funcAdd",alpha:b.alpha||"funcAdd"})},blendFunc:function(a,b){return a?void a.blendFunc(j(a,b.sfactor||"srcAlpha"),j(a,b.dfactor||"oneMinusSrcAlpha")):(b=b||{},{sfactor:b.sfactor||"srcAlpha",dfactor:b.dfactor||"oneMinusSrcAlpha"})},blendFuncSeparate:function(a,b){return a?void a.blendFuncSeparate(j(a,b.srcRGB||"zero"),j(a,b.dstRGB||"zero"),j(a,b.srcAlpha||"zero"),j(a,b.dstAlpha||"zero")):(b=b||{},{srcRGB:b.srcRGB||"zero",dstRGB:b.dstRGB||"zero",srcAlpha:b.srcAlpha||"zero",dstAlpha:b.dstAlpha||"zero"})},clearColor:function(a,b){return a?void a.clearColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},clearDepth:function(a,b){return a?void a.clearDepth(b):null==b||void 0==b?1:b},clearStencil:function(a,b){return a?void a.clearStencil(b):b||0},colorMask:function(a,b){return a?void a.colorMask(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},enableCullFace:function(a,b){return a?void(b?a.enable(a.CULL_FACE):a.disable(a.CULL_FACE)):b},cullFace:function(a,b){return a?void a.cullFace(j(a,b)):b||"back"},enableDepthTest:function(a,b){return a?void(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST)):((null==b||void 0==b)&&(b=!0),b)},depthFunc:function(a,b){return a?void a.depthFunc(j(a,b)):b||"less"},enableDepthMask:function(a,b){return a?void a.depthMask(b):((null==b||void 0==b)&&(b=!0),b)},depthRange:function(a,b){return a?void a.depthRange(b.zNear,b.zFar):(b=b||{},{zNear:void 0==b.zNear||null==b.zNear?0:b.zNear,zFar:void 0==b.zFar||null==b.zFar?1:b.zFar})},frontFace:function(a,b){return a?void a.frontFace(j(a,b)):b||"ccw"},lineWidth:function(a,b){return a?void a.lineWidth(b):b||1},enableScissorTest:function(a,b){return a?void(b?a.enable(a.SCISSOR_TEST):(b=!1,a.disable(a.SCISSOR_TEST))):b}},l={viewport:function(a,b){return a?void a.viewport(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||1,y:b.y||1,width:b.width||c.canvas.width,height:b.height||c.canvas.height})},scissor:function(a,b){return a?void a.scissor(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||0,y:b.y||0,width:b.width||1,height:b.height||1})},clear:function(a,b){if(!a)return b=b||{};var c;b.color&&(c=a.COLOR_BUFFER_BIT),b.depth&&(c|=a.DEPTH_BUFFER_BIT),b.stencil&&(c|=a.STENCIL_BUFFER_BIT)}};SceneJS.Renderer=SceneJS_NodeFactory.createNodeType("renderer"),SceneJS.Renderer.prototype._init=function(a){if(1==this._core.useCount){for(var b in a)a.hasOwnProperty(b)&&(this._core[b]=a[b]);this._core.dirty=!0}},SceneJS.Renderer.prototype.setViewport=function(a){this._core.viewport=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getViewport=function(){return this._core.viewport?{x:this._core.viewport.x,y:this._core.viewport.y,width:this._core.viewport.width,height:this._core.viewport.height}:void 0},SceneJS.Renderer.prototype.setScissor=function(a){this._core.scissor=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getScissor=function(){return this._core.scissor?{x:this._core.scissor.x,y:this._core.scissor.y,width:this._core.scissor.width,height:this._core.scissor.height}:void 0},SceneJS.Renderer.prototype.setClear=function(a){this._core.clear=a?{r:a.r||0,g:a.g||0,b:a.b||0}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getClear=function(){return this._core.clear?{r:this._core.clear.r,g:this._core.clear.g,b:this._core.clear.b}:null},SceneJS.Renderer.prototype.setEnableBlend=function(a){this._core.enableBlend=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getEnableBlend=function(){return this._core.enableBlend},SceneJS.Renderer.prototype.setBlendColor=function(a){this._core.blendColor=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendColor=function(){return this._core.blendColor?{r:this._core.blendColor.r,g:this._core.blendColor.g,b:this._core.blendColor.b,a:this._core.blendColor.a}:void 0},SceneJS.Renderer.prototype.setBlendEquation=function(a){this._core.blendEquation=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquation=function(){return this._core.blendEquation},SceneJS.Renderer.prototype.setBlendEquationSeparate=function(a){this._core.blendEquationSeparate=a?{rgb:a.rgb||"funcAdd",alpha:a.alpha||"funcAdd"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquationSeparate=function(){return this._core.blendEquationSeparate?{rgb:this._core.rgb,alpha:this._core.alpha}:void 0},SceneJS.Renderer.prototype.setBlendFunc=function(a){this._core.blendFunc=a?{sfactor:a.sfactor||"srcAlpha",dfactor:a.dfactor||"one"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendFunc=function(){return this._core.blendFunc?{sfactor:this._core.sfactor,dfactor:this._core.dfactor}:void 0},SceneJS.Renderer.prototype.setBlendFuncSeparate=function(a){this._core.blendFuncSeparate=a?{srcRGB:a.srcRGB||"zero",dstRGB:a.dstRGB||"zero",srcAlpha:a.srcAlpha||"zero",dstAlpha:a.dstAlpha||"zero"}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getBlendFuncSeparate=function(){return this._core.blendFuncSeparate?{srcRGB:this._core.blendFuncSeparate.srcRGB,dstRGB:this._core.blendFuncSeparate.dstRGB,srcAlpha:this._core.blendFuncSeparate.srcAlpha,dstAlpha:this._core.blendFuncSeparate.dstAlpha}:void 0},SceneJS.Renderer.prototype.setEnableCullFace=function(a){this._core.enableCullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableCullFace=function(){return this._core.enableCullFace},SceneJS.Renderer.prototype.setCullFace=function(a){this._core.cullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getCullFace=function(){return this._core.cullFace},SceneJS.Renderer.prototype.setEnableDepthTest=function(a){this._core.enableDepthTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthTest=function(){return this._core.enableDepthTest},SceneJS.Renderer.prototype.setDepthFunc=function(a){this._core.depthFunc=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthFunc=function(){return this._core.depthFunc},SceneJS.Renderer.prototype.setEnableDepthMask=function(a){this._core.enableDepthMask=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthMask=function(){return this._core.enableDepthMask},SceneJS.Renderer.prototype.setClearDepth=function(a){this._core.clearDepth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Renderer.prototype.setDepthRange=function(a){this._core.depthRange=a?{zNear:void 0==a.zNear||null==a.zNear?0:a.zNear,zFar:void 0==a.zFar||null==a.zFar?1:a.zFar}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthRange=function(){return this._core.depthRange?{zNear:this._core.depthRange.zNear,zFar:this._core.depthRange.zFar}:void 0},SceneJS.Renderer.prototype.setFrontFace=function(a){this._core.frontFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getFrontFace=function(){return this._core.frontFace},SceneJS.Renderer.prototype.setLineWidth=function(a){this._core.lineWidth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Renderer.prototype.setEnableScissorTest=function(a){this._core.enableScissorTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableScissorTest=function(){return this._core.enableScissorTest},SceneJS.Renderer.prototype.setClearStencil=function(a){this._core.clearStencil=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearStencil=function(){return this._core.clearStencil},SceneJS.Renderer.prototype.setColorMask=function(a){this._core.colorMask=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getColorMask=function(){return this._core.colorMask?{r:this._core.colorMask.r,g:this._core.colorMask.g,b:this._core.colorMask.b,a:this._core.colorMask.a}:void 0},SceneJS.Renderer.prototype._compile=function(b){this._core.dirty&&(this._core.props=a(this._core),this._core.dirty=!1),this._engine.display.renderer=e[f++]=this._core,this._compileNodes(b),this._engine.display.renderer=--f>0?e[f-1]:d}},function(){var a={less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL"},b={type:"depthBuffer",stateId:SceneJS._baseStateId++,enabled:!0,clearDepth:1,depthFunc:null,_depthFuncName:"less"},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){null===b.depthFunc&&(b.depthFunc=a.engine.canvas.gl.LESS),a.engine.display.depthBuffer=b,d=0}),SceneJS.DepthBuf=SceneJS_NodeFactory.createNodeType("depthBuffer"),SceneJS.DepthBuf.prototype._init=function(a){void 0!=a.enabled?this.setEnabled(a.enabled):1==this._core.useCount&&this.setEnabled(!0),void 0!=a.clearDepth?this.setClearDepth(a.clearDepth):1==this._core.useCount&&this.setClearDepth(1),void 0!=a.depthFunc?this.setDepthFunc(a.depthFunc):1==this._core.useCount&&this.setDepthFunc("less"),void 0!=a.clear?this.setClear(a.clear):1==this._core.useCount&&this.setClear(!0)},SceneJS.DepthBuf.prototype.setEnabled=function(a){return this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getEnabled=function(){return this._core.enabled},SceneJS.DepthBuf.prototype.setClear=function(a){return this._core.clear!=a&&(this._core.clear=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClear=function(){return this._core.clear},SceneJS.DepthBuf.prototype.setClearDepth=function(a){return this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.DepthBuf.prototype.setDepthFunc=function(b){if(this._core._depthFuncName!=b){var c=a[b];if(void 0==c)throw"unsupported value for 'clearFunc' attribute on depthBuffer node: '"+b+"' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";this._core.depthFunc=this._engine.canvas.gl[c],this._core._depthFuncName=b,this._engine.display.imageDirty=!0}return this},SceneJS.DepthBuf.prototype.getDepthFunc=function(){return this._core._depthFuncName},SceneJS.DepthBuf.prototype._compile=function(a){this._engine.display.depthBuffer=c[d++]=this._core,this._compileNodes(a),this._engine.display.depthBuffer=--d>0?c[d-1]:b}}(),function(){var a={type:"colorBuffer",stateId:SceneJS._baseStateId++,blendEnabled:!1,colorMask:{r:!0,g:!0,b:!0,a:!0}},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.colorBuffer=a,c=0}),SceneJS.ColorBuffer=SceneJS_NodeFactory.createNodeType("colorBuffer"),SceneJS.ColorBuffer.prototype._init=function(a){void 0!=a.blendEnabled?this.setBlendEnabled(a.blendEnabled):1==this._core.useCount&&this.setBlendEnabled(!1),this.setColorMask(a)},SceneJS.ColorBuffer.prototype.setBlendEnabled=function(a){this._core.blendEnabled!=a&&(this._core.blendEnabled=a,this._engine.display.imageDirty=!0),this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getBlendEnabled=function(){return this._core.blendEnabled},SceneJS.ColorBuffer.prototype.setColorMask=function(a){this._core.colorMask={r:void 0!=a.r&&null!=a.r?a.r:!0,g:void 0!=a.g&&null!=a.g?a.g:!0,b:void 0!=a.b&&null!=a.b?a.b:!0,a:void 0!=a.a&&null!=a.a?a.a:!0},this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getColorMask=function(){return this._core.colorMask},SceneJS.ColorBuffer.prototype._compile=function(d){this._engine.display.colorBuffer=b[c++]=this._core,this._compileNodes(d),this._engine.display.colorBuffer=--c>0?b[c-1]:a,this._engine.display.imageDirty=!0}}(),function(){var a={type:"view",stateId:SceneJS._baseStateId++,scissorTestEnabled:!1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.view=a,c=0}),SceneJS.View=SceneJS_NodeFactory.createNodeType("view"),SceneJS.View.prototype._init=function(a){void 0!=a.scissorTestEnabled?this.setScissorTestEnabled(a.scissorTestEnabled):1==this._core.useCount&&this.setScissorTestEnabled(!1)},SceneJS.View.prototype.setScissorTestEnabled=function(a){return this._core.scissorTestEnabled!=a&&(this._core.scissorTestEnabled=a,this._engine.display.imageDirty=!0),this},SceneJS.View.prototype.getScissorTestEnabled=function(){return this._core.scissorTestEnabled},SceneJS.View.prototype._compile=function(d){this._engine.display.view=b[c++]=this._core,this._compileNodes(d),this._engine.display.view=--c>0?b[c-1]:a}}(),SceneJS.Scene=SceneJS_NodeFactory.createNodeType("scene"),SceneJS.Scene.prototype._init=function(a){a.tagMask&&this.setTagMask(a.tagMask),this._tagSelector=null,this.transparent=a.transparent===!0},SceneJS.Scene.prototype.loseWebGLContext=function(){this._engine.loseWebGLContext()},SceneJS.Scene.prototype.getCanvas=function(){return this._engine.canvas.canvas},SceneJS.Scene.prototype.getGL=function(){return this._engine.canvas.gl},SceneJS.Scene.prototype.getZBufferDepth=function(){var a=this._engine.canvas.gl;return a.getParameter(a.DEPTH_BITS)},SceneJS.Scene.prototype.setSSAAMultiplier=function(a){return this._engine.canvas.setSSAAMultiplier(a)},SceneJS.Scene.prototype.setTagMask=function(a){a=a||"XXXXXXXXXXXXXXXXXXXXXXXXXX",this._tagSelector||(this._tagSelector={}),this._tagSelector.mask=a,this._tagSelector.regex=a?new RegExp(a):null,this._engine.display.selectTags(this._tagSelector)},SceneJS.Scene.prototype.getTagMask=function(){return this._tagSelector?this._tagSelector.mask:null},SceneJS.Scene.prototype.setNumPasses=function(a){this._engine.setNumPasses(a)},SceneJS.Scene.prototype.renderFrame=function(a){return this._engine.renderFrame(a)},SceneJS.Scene.prototype.needFrame=function(){this._engine.display.imageDirty=!0},SceneJS.Scene.prototype.start=function(a){this._engine.start(a)},SceneJS.Scene.prototype.setFPS=function(a){this._engine.fps=a},SceneJS.Scene.prototype.pause=function(a){this._engine.pause(a)},SceneJS.Scene.prototype.isRunning=function(){return this._engine.running},SceneJS.Scene.prototype.pick=function(a,b,c){var d=this._engine.pick(a,b,c);return this.renderFrame({force:!0}),d?(this.publish("pick",d),d):void this.publish("nopick")},SceneJS.Scene.prototype.readPixels=function(a,b){return this._engine.readPixels(a,b)},SceneJS.Scene.prototype._destroy=function(){this.destroyed||(delete SceneJS._engines[this.id],SceneJS._engineIds.removeItem(this.id),this.destroyed=!0)},SceneJS.Scene.prototype.isActive=function(){return!this._engine.destroyed},SceneJS.Scene.prototype.stop=function(){this._engine.stop()},SceneJS.Scene.prototype.containsNode=function(a){return!!this._engine.findNode(a)},SceneJS.Scene.prototype.findNodes=function(a){return this._engine.findNodes(a)},SceneJS.Scene.prototype.findNode=function(a,b){return this.getNode(a,b)},SceneJS.Scene.prototype.getNode=function(a,b){var c=this._engine.findNode(a);return c?(b&&b(c),c):b?void this.once("nodes/"+a,b):null},SceneJS.Scene.prototype.hasCore=function(a,b){return this._engine.hasCore(a,b)},SceneJS.Scene.prototype.getStatus=function(){var a=SceneJS_sceneStatusModule.sceneStatus[this.id];return a?SceneJS._shallowClone(a):{destroyed:!0}},new function(){function a(a){for(var b,c,d={},e=0;i>e;e++){b=a[e];for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c])}return d}var b={type:"shader",stateId:SceneJS._baseStateId++,hash:"",empty:!0,shader:{}},c=[],d=[],e=[],f=[],g=[],h=[],i=0,j=!0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.shader=b,i=0,j=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(k){if(j){if(i>0){var l={type:"shader",stateId:c[i-1],hash:c.slice(0,i).join("."),shaders:{fragment:{code:f.slice(0,i).join(""),hooks:a(g)},vertex:{code:d.slice(0,i).join(""),hooks:a(e)}},paramsStack:h.slice(0,i)};k.display.shader=l}else k.display.shader=b;j=!1}}),SceneJS.Shader=SceneJS_NodeFactory.createNodeType("shader"),SceneJS.Shader.prototype._init=function(a){1==this._core.useCount&&(this._setShaders(a.shaders),this.setParams(a.params))},SceneJS.Shader.prototype._setShaders=function(a){a=a||[],this._core.shaders={};for(var b,c=0,d=a.length;d>c;c++){if(b=a[c],!b.stage)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"shader 'stage' attribute expected");var e;b.code&&(e=SceneJS._isArray(b.code)?b.code.join(""):b.code),this._core.shaders[b.stage]={code:e,hooks:b.hooks}}},SceneJS.Shader.prototype.setParams=function(a){a=a||{};var b=this._core.params;b||(b=this._core.params={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.Shader.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.Shader.prototype._compile=function(a){c[i]=this._core.coreId;var b=this._core.shaders,k=b.fragment||{},l=b.vertex||{};f[i]=k.code||"",g[i]=k.hooks||{},d[i]=l.code||"", -e[i]=l.hooks||{},h[i]=this._core.params||{},i++,j=!0,this._compileNodes(a),i--,j=!0}},new function(){var a,b={type:"shaderParams",stateId:SceneJS._baseStateId++,empty:!0},c=[],d=[],e=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(c){c.engine.display.shaderParams=b,e=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(e>0){var g={type:"shaderParams",stateId:c[e-1],paramsStack:d.slice(0,e)};f.display.shaderParams=g}else f.display.shaderParams=b;a=!1}}),SceneJS.ShaderParams=SceneJS_NodeFactory.createNodeType("shaderParams"),SceneJS.ShaderParams.prototype._init=function(a){1==this._core.useCount&&this.setParams(a.params)},SceneJS.ShaderParams.prototype.setParams=function(a){a=a||{};var b=this._core;b.params||(b.params={});for(var c in a)a.hasOwnProperty(c)&&(b.params[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.ShaderParams.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.ShaderParams.prototype._compile=function(b){c[e]=this._core.coreId,d[e]=this._core.params,e++,a=!0,this._compileNodes(b),e--,a=!0}},function(){var a={type:"style",stateId:SceneJS._baseStateId++,lineWidth:1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.style=a,c=0}),SceneJS.Style=SceneJS_NodeFactory.createNodeType("style"),SceneJS.Style.prototype._init=function(a){void 0!=a.lineWidth&&this.setLineWidth(a.lineWidth)},SceneJS.Style.prototype.setLineWidth=function(a){return this._core.lineWidth!=a&&(this._core.lineWidth=a,this._engine.display.imageDirty=!0),this},SceneJS.Style.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Style.prototype._compile=function(d){this._engine.display.style=b[c++]=this._core,this._compileNodes(d),this._engine.display.style=--c>0?b[c-1]:a}}(),function(){var a={type:"tag",stateId:SceneJS._baseStateId++,tag:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.tag=a,c=0}),SceneJS.Tag=SceneJS_NodeFactory.createNodeType("tag"),SceneJS.Tag.prototype._init=function(a){if(1==this._core.useCount){if(!a.tag)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"tag node attribute missing : 'tag'");this.setTag(a.tag)}},SceneJS.Tag.prototype.setTag=function(a){var b=this._core;b.tag=a,b.pattern=null,b.matched=!1,this._engine.display.drawListDirty=!0},SceneJS.Tag.prototype.getTag=function(){return this._core.tag},SceneJS.Tag.prototype._compile=function(d){this._engine.display.tag=b[c++]=this._core,this._compileNodes(d),this._engine.display.tag=--c>0?b[c-1]:a}}(),new function(){var a={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.texture=a,c=0}),SceneJS.Texture=SceneJS_NodeFactory.createNodeType("_texture"),SceneJS.Texture.prototype._init=function(a){if(1==this._core.useCount){this._core.layers=[],this._core.params={};var b=void 0==a.waitForLoad?!0:a.waitForLoad;if(!a.layers)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers missing");if(!SceneJS._isArray(a.layers))throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers should be an array");for(var c,d=this._engine.canvas.gl,e=0;ec;c++)h._loadLayerTexture(b,a[c])}}},SceneJS.Texture.prototype._loadLayerTexture=function(a,b){var c=this,d=b.source;if(d){if(!d.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"texture layer config expected: source.type");SceneJS.Plugins.getPlugin("texture",d.type,function(e){if(!e.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'getSource' method missing on plugin for texture source type '"+d.type+"'.");var f=e.getSource({gl:a});if(!f.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'subscribe' method missing on plugin for texture source type '"+d.type+"'");var g=SceneJS_sceneStatusModule.taskStarted(c,"Loading texture");f.subscribe(function(){var d=!1;return function(e){d?c._engine.display.imageDirty=!0:(d=!0,c._setLayerTexture(a,b,e),SceneJS_sceneStatusModule.taskFinished(g))}}()),f.configure&&f.configure(d),b._source=f})}else{var e=b.uri||b.src,f=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),g=new Image;g.onload=function(){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);var e=SceneJS_configsModule.configs.maxTextureSize;e&&(g=SceneJS._webgl.clampImageSize(g,e)),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c._ensureImageSizePowerOfTwo(g)),c._setLayerTexture(a,b,d),SceneJS_sceneStatusModule.taskFinished(f),c._engine.display.imageDirty=!0},g.onerror=function(){SceneJS_sceneStatusModule.taskFailed(f)},0==e.indexOf("data")?g.src=e:(g.crossOrigin="Anonymous",g.src=e)}},SceneJS.Texture.prototype._ensureImageSizePowerOfTwo=function(a){if(!this._isPowerOfTwo(a.width)||!this._isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=this._nextHighestPowerOfTwo(a.width),b.height=this._nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b,a.crossOrigin=""}return a},SceneJS.Texture.prototype._isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS.Texture.prototype._nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS.Texture.prototype._setLayerTexture=function(a,b,c){b.texture=new SceneJS._webgl.Texture2D(a,{texture:c,minFilter:this._getGLOption("minFilter",a,b,a.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",a,b,a.LINEAR),wrapS:this._getGLOption("wrapS",a,b,a.REPEAT),wrapT:this._getGLOption("wrapT",a,b,a.REPEAT),isDepth:this._getOption(b.isDepth,!1),depthMode:this._getGLOption("depthMode",a,b,a.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",a,b,a.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",a,b,a.LEQUAL),flipY:this._getOption(b.flipY,!0),width:this._getOption(b.width,1),height:this._getOption(b.height,1),internalFormat:this._getGLOption("internalFormat",a,b,a.LEQUAL),sourceFormat:this._getGLOption("sourceType",a,b,a.ALPHA),sourceType:this._getGLOption("sourceType",a,b,a.UNSIGNED_BYTE),update:null}),this.destroyed&&b.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._getGLOption=function(a,b,c,d){var e=c[a];if(void 0==e)return d;var f=SceneJS._webgl.enumMap[e];if(void 0==f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+e+"'");var g=b[f];return g},SceneJS.Texture.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.Texture.prototype.setLayer=function(a){if(void 0==a.index||null==a.index)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index null or undefined");if(a.index<0||a.index>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(parseInt(a.index),a),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype.setLayers=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._setLayer=function(a,b){b=b||{};var c=this._core.layers[a];if(void 0!=b.blendFactor&&null!=b.blendFactor&&(c.blendFactor=b.blendFactor),b.source){var d=c._source;d&&d.configure&&d.configure(b.source)}(b.translate||b.rotate||b.scale)&&this._setLayerTransform(b,c)},SceneJS.Texture.prototype._setLayerTransform=function(a,b){var c,d;if(a.translate){var e=a.translate;void 0!=e.x&&(b.translate.x=e.x),void 0!=e.y&&(b.translate.y=e.y),c=SceneJS_math_translationMat4v([e.x||0,e.y||0,0])}if(a.scale){var f=a.scale;void 0!=f.x&&(b.scale.x=f.x),void 0!=f.y&&(b.scale.y=f.y),d=SceneJS_math_scalingMat4v([f.x||1,f.y||1,1]),c=c?SceneJS_math_mulMat4(c,d):d}if(a.rotate){var g=a.rotate;void 0!=g.z&&(b.rotate.z=g.z||0),d=SceneJS_math_rotationMat4v(.0174532925*g.z,[0,0,1]),c=c?SceneJS_math_mulMat4(c,d):d}c&&(b.matrix=c,b.matrixAsArray?b.matrixAsArray.set(b.matrix):b.matrixAsArray=new Float32Array(b.matrix),b.matrixAsArray=new Float32Array(b.matrix))},SceneJS.Texture.prototype._compile=function(d){this._core.hash||this._makeHash(),this._engine.display.texture=b[c++]=this._core,this._compileNodes(d),this._engine.display.texture=--c>0?b[c-1]:a},SceneJS.Texture.prototype._makeHash=function(){var a,b=this._core;if(b.layers&&b.layers.length>0){for(var c,d=b.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");a=e.join("")}else a="";b.hash!=a&&(b.hash=a)},SceneJS.Texture.prototype._destroy=function(){if(1==this._core.useCount)for(var a,b,c=this._core.layers,d=0,e=c.length;e>d;d++)a=c[d],a.texture&&a.texture.destroy(),b=a._source,b&&b.destroy&&b.destroy()}},new function(){function a(){var a,b;(0!=this.translate.x||0!=this.translate.y)&&(a=SceneJS_math_translationMat4v([this.translate.x||0,this.translate.y||0,0])),(1!=this.scale.x||1!=this.scale.y)&&(b=SceneJS_math_scalingMat4v([this.scale.x||1,this.scale.y||1,1]),a=a?SceneJS_math_mulMat4(a,b):b),0!=this.rotate&&(b=SceneJS_math_rotationMat4v(.0174532925*this.rotate,[0,0,1]),a=a?SceneJS_math_mulMat4(a,b):b),a&&(this.matrix=a,this.matrixAsArray?this.matrixAsArray.set(this.matrix):this.matrixAsArray=new Float32Array(this.matrix)),this._matrixDirty=!1}var b={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.texture=b,d=0});var c=[],d=0;SceneJS.TextureMap=SceneJS_NodeFactory.createNodeType("texture"),SceneJS.TextureMap.prototype._init=function(b){var c=this;if(1==this._core.useCount){if(b.applyFrom&&"uv"!=b.applyFrom&&"uv2"!=b.applyFrom&&"normal"!=b.applyFrom&&"geometry"!=b.applyFrom)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyFrom value is unsupported - should be either 'uv', 'uv2', 'normal' or 'geometry'");if(b.applyTo&&"baseColor"!=b.applyTo&&"color"!=b.applyTo&&"specular"!=b.applyTo&&"emit"!=b.applyTo&&"alpha"!=b.applyTo&&"normals"!=b.applyTo&&"shine"!=b.applyTo)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyTo value is unsupported - should be either 'color', 'baseColor', 'specular' or 'normals'");if(b.blendMode&&"add"!=b.blendMode&&"multiply"!=b.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layer blendMode value is unsupported - should be either 'add' or 'multiply'");"color"==b.applyTo&&(b.applyTo="baseColor"),SceneJS._apply({waitForLoad:void 0==b.waitForLoad?!0:b.waitForLoad,texture:null,applyFrom:b.applyFrom?b.applyFrom:"uv",applyTo:b.applyTo?b.applyTo:"baseColor",blendMode:b.blendMode?b.blendMode:"multiply",blendFactor:void 0!=b.blendFactor&&null!=b.blendFactor?b.blendFactor:1,translate:b.translate?SceneJS._apply(b.translate,{x:0,y:0}):{x:0,y:0},scale:b.scale?SceneJS._apply(b.scale,{x:1,y:1}):{x:1,y:1},rotate:b.rotate||0,matrix:null,_matrixDirty:!0,buildMatrix:a},this._core),a.call(this._core),b.src?(this._core.src=b.src,this._loadTexture(b.src)):b.image?(this._core.image=b.image,this._initTexture(b.image)):b.target&&this.getScene().getNode(b.target,function(a){c.setTarget(a)}),this._core.webglRestored=function(){c._core.image?c._initTexture(c._core.image):c._core.src?c._loadTexture(c._core.src):c._core.target}}},SceneJS.TextureMap.prototype._loadTexture=function(a){var b=this,c=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),d=new Image;d.onload=function(){b._initTexture(d),SceneJS_sceneStatusModule.taskFinished(c),b._engine.display.imageDirty=!0},d.onerror=function(){SceneJS_sceneStatusModule.taskFailed(c)},0==a.indexOf("data")?d.src=a:(d.crossOrigin="Anonymous",d.src=a)},SceneJS.TextureMap.prototype._initTexture=function(a){var b=this._engine.canvas.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);var d=SceneJS_configsModule.configs.maxTextureSize;d&&(a=SceneJS._webgl.clampImageSize(a,d)),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(a)),this._core.image=a,this._core.texture=new SceneJS._webgl.Texture2D(b,{texture:c,minFilter:this._getGLOption("minFilter",b.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",b.LINEAR),wrapS:this._getGLOption("wrapS",b.REPEAT),wrapT:this._getGLOption("wrapT",b.REPEAT),isDepth:this._getOption(this._core.isDepth,!1),depthMode:this._getGLOption("depthMode",b.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",b.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",b.LEQUAL),flipY:this._getOption(this._core.flipY,!0),width:this._getOption(this._core.width,1),height:this._getOption(this._core.height,1),internalFormat:this._getGLOption("internalFormat",b.ALPHA),sourceFormat:this._getGLOption("sourceFormat",b.ALPHA),sourceType:this._getGLOption("sourceType",b.UNSIGNED_BYTE),update:null}),this.destroyed&&this._core.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype._getGLOption=function(a,b){var c=this._engine.canvas.gl,d=this._core[a];if(void 0==d)return b;var e=SceneJS._webgl.enumMap[d];if(void 0==e)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+d+"'");return c[e]},SceneJS.TextureMap.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.TextureMap.prototype.setSrc=function(a){this._core.image=null,this._core.src=a,this._core.target=null,this._loadTexture(a)},SceneJS.TextureMap.prototype.setImage=function(a){this._core.image=a,this._core.src=null,this._core.target=null,this._initTexture(a)},SceneJS.TextureMap.prototype.setTarget=function(a){return"colorTarget"!=a.type&&"depthTarget"!=a.type?void console.log("Target node type not compatible: "+a.type):(delete this._core.src,this._core.target=a,this._core.src=null,this._core.image=null,this._core.texture=a._core.renderBuf.getTexture(),this._core.texture.bufType=a._core.bufType,void(this._engine.display.imageDirty=!0))},SceneJS.TextureMap.prototype.setBlendFactor=function(a){this._core.blendFactor=a,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getBlendFactor=function(){return this._core.blendFactor},SceneJS.TextureMap.prototype.setTranslate=function(a){this._core.translate||(this._core.translate={x:0,y:0}),this._core.translate.x=a.x,this._core.translate.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getTranslate=function(){return this._core.translate},SceneJS.TextureMap.prototype.setScale=function(a){this._core.scale||(this._core.scale={x:0,y:0}),this._core.scale.x=a.x,this._core.scale.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getScale=function(){return this._core.scale},SceneJS.TextureMap.prototype.setRotate=function(a){this._core.rotate=a,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getRotate=function(){return this._core.rotate},SceneJS.TextureMap.prototype.getMatrix=function(){return this._core._matrixDirty&&this._core.buildMatrix.call(this.core)(),this.core.matrix},SceneJS.TextureMap.prototype._compile=function(a){this.__core||(this.__core=this._engine._coreFactory.getCore("texture"));var e=this._engine.display.texture;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),c[d++]=this.__core,this._engine.display.texture=this.__core,this._compileNodes(a),this._engine.display.texture=--d>0?c[d-1]:b},SceneJS.TextureMap.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.TextureMap.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&!this._core.target&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}},function(){var a={type:"cubemap",stateId:SceneJS._baseStateId++,empty:!0,texture:null,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.cubemap=a,c=0}),SceneJS.Reflect=SceneJS_NodeFactory.createNodeType("reflect"),SceneJS.Reflect.prototype._init=function(a){if(1==this._core.useCount){if(this._core.hash="y",a.blendMode&&"add"!=a.blendMode&&"multiply"!=a.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"reflection blendMode value is unsupported - should be either 'add' or 'multiply'");this._core.blendMode=a.blendMode||"multiply",this._core.intensity=void 0!=a.intensity&&null!=a.intensity?a.intensity:1,this._core.applyTo="reflect";for(var b=this,c=this._engine.canvas.gl,d=c.createTexture(),e=[c.TEXTURE_CUBE_MAP_POSITIVE_X,c.TEXTURE_CUBE_MAP_NEGATIVE_X,c.TEXTURE_CUBE_MAP_POSITIVE_Y,c.TEXTURE_CUBE_MAP_NEGATIVE_Y,c.TEXTURE_CUBE_MAP_POSITIVE_Z,c.TEXTURE_CUBE_MAP_NEGATIVE_Z],f=[],g=SceneJS_sceneStatusModule.taskStarted(this,"Loading reflection texture"),h=!1,i=0;ii;i++)c.texImage2D(e[i],0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(f[i]));b._core.texture=new SceneJS._webgl.Texture2D(c,{texture:d,target:c.TEXTURE_CUBE_MAP,minFilter:c.LINEAR,magFilter:c.LINEAR,wrapS:c.CLAMP_TO_EDGE,wrapT:c.CLAMP_TO_EDGE}),SceneJS_sceneStatusModule.taskFinished(g),b._engine.display.imageDirty=!0}}}(),j.onerror=function(){h=!0,SceneJS_sceneStatusModule.taskFailed(g)},j.src=a.src[i]}}},SceneJS.Reflect.prototype._compile=function(d){this.__core||(this.__core=this._engine._coreFactory.getCore("cubemap"));var e=this._engine.display.cubemap;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),b[c++]=this.__core,this._engine.display.cubemap=this.__core,this._compileNodes(d),this._engine.display.cubemap=--c>0?b[c-1]:a},SceneJS.Reflect.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode);b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.Reflect.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}}(),SceneJS.XForm=SceneJS_NodeFactory.createNodeType("xform"),SceneJS.XForm.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.XForm.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.XForm.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.XForm.prototype.setElements=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.XForm elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.XForm.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Matrix=SceneJS_NodeFactory.createNodeType("matrix"),SceneJS.Matrix.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.Matrix.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Matrix.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Matrix.prototype.setMatrix=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Matrix elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Matrix.prototype.setElements=SceneJS.Matrix.prototype.setMatrix,SceneJS.Matrix.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Rotate=SceneJS_NodeFactory.createNodeType("rotate"),SceneJS.Rotate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setAngle(a.angle),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_rotationMat4v(b.angle*Math.PI/180,[b.x,b.y,b.z])}}},SceneJS.Rotate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Rotate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Rotate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for rotate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.setAngle=function(a){this._core.angle=a||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getAngle=function(){return this._core.angle},SceneJS.Rotate.prototype.setXYZ=function(a){a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Rotate.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getX=function(){return this._core.x},SceneJS.Rotate.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getY=function(){return this._core.y},SceneJS.Rotate.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getZ=function(){return this._core.z},SceneJS.Rotate.prototype.incAngle=function(a){this._core.angle+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Translate=SceneJS_NodeFactory.createNodeType("translate"),SceneJS.Translate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_translationMat4v([b.x,b.y,b.z],b.matrix)}}},SceneJS.Translate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Translate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Translate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for translate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Translate.prototype.setXYZ=function(a){return a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Translate.prototype.setX=function(a){return this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setY=function(a){return this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setZ=function(a){return this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incX=function(a){return this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incY=function(a){return this._core.y+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incZ=function(a){return this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getX=function(){return this._core.x},SceneJS.Translate.prototype.getY=function(){return this._core.y},SceneJS.Translate.prototype.getZ=function(){return this._core.z},SceneJS.Translate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Scale=SceneJS_NodeFactory.createNodeType("scale"),SceneJS.Scale.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_scalingMat4v([b.x,b.y,b.z])}}},SceneJS.Scale.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Scale.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Scale.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for scale node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setXYZ=function(a){a=a||{},this._core.x=void 0==a.x?1:a.x,this._core.y=void 0==a.y?1:a.y,this._core.z=void 0==a.z?1:a.z,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Scale.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getX=function(){return this._core.x},SceneJS.Scale.prototype.getY=function(){return this._core.y},SceneJS.Scale.prototype.getZ=function(){return this._core.z},SceneJS.Scale.prototype.incX=function(a){this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.incY=function(a){this._core.y+=a,this._core.matrixDirty=!0},SceneJS.Scale.prototype.incZ=function(a){this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()};var SceneJS_modelXFormStack=new function(){var a=SceneJS_math_identityMat4(),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(SceneJS_math_identityMat4(),SceneJS_math_mat4())),d=new Float32Array(c),e={type:"xform",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,parent:null,cores:[],numCores:0,dirty:!1,matrixDirty:!1},f=[],g=0;this.top=e;var h,i=this;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){g=0,i.top=e,h=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(a){h&&(g>0?a.display.modelTransform=f[g-1]:a.display.modelTransform=e,h=!1)}),this.buildCore=function(a){function b(a){a.dirty=!0,a.matrixDirty=!0;for(var c=0,d=a.numCores;d>c;c++)b(a.cores[c])}a.parent=null,a.cores=[],a.numCores=0,a.matrixDirty=!1,a.matrix=SceneJS_math_identityMat4(),a.mat=new Float32Array(a.matrix),a.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(a.matrix,SceneJS_math_mat4()))),a.dirty=!1,a.setDirty=function(){a.matrixDirty=!0,a.dirty,b(a)},a.build=function(){a.matrixDirty&&(a.buildMatrix&&a.buildMatrix(),a.matrixDirty=!1);var b,c=a.parent;if(c)for(b=a.matrix.slice(0);c;)c.matrixDirty&&(c.buildMatrix&&c.buildMatrix(),c.mat.set(c.matrix),c.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(c.matrix,SceneJS_math_mat4()))),c.matrixDirty=!1),SceneJS_math_mulMat4(c.matrix,b,b),!c.dirty,c=c.parent;else b=a.matrix;a.mat.set(b),a.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4()))),a.dirty=!1}},this.push=function(a){f[g++]=a,a.parent=this.top,a.dirty=!0,this.top&&(this.top.cores[this.top.numCores++]=a),a.numCores=0,this.top=a,h=!0},this.pop=function(){this.top=--g>0?f[g-1]:e,h=!0}};SceneJS.Types=new function(){this.addType=function(a,b){SceneJS_NodeFactory.createNodeType(a,b,function(a){var c;for(var d in b)if(b.hasOwnProperty(d))switch(c=b[d],d){case"init":case"construct":!function(){var c=b[d];a.prototype._init=function(a){c.call(this,a)},a.prototype._fromPlugin=!0}();break;case"destroy":case"destruct":a.prototype._destroy=c;break;default:a.prototype[d]=c}})},this.hasType=function(a){return!!SceneJS_NodeFactory.nodeTypes[a]}};var SceneJS_Display=function(a){this._canvas=a.canvas,this._programFactory=new SceneJS_ProgramFactory({canvas:a.canvas}),this._chunkFactory=new SceneJS_ChunkFactory,this.transparent=a.transparent===!0, -this.enable=null,this.flags=null,this.layer=null,this.stage=null,this.renderer=null,this.depthBuffer=null,this.colorBuffer=null,this.view=null,this.lights=null,this.material=null,this.texture=null,this.cubemap=null,this.modelTransform=null,this.viewTransform=null,this.projTransform=null,this.renderTarget=null,this.clips=null,this.morphGeometry=null,this.name=null,this.tag=null,this.renderListeners=null,this.shader=null,this.shaderParams=null,this.style=null,this.geometry=null,this._objectFactory=new SceneJS_ObjectFactory,this._objects={},this._ambientColor=[0,0,0,1],this._objectList=[],this._objectListLen=0,this._drawList=[],this._drawListLen=0,this._pickDrawList=[],this._pickDrawListLen=0,this._targetList=[],this._targetListLen=0,this._frameCtx={pickNames:[],canvas:this._canvas,VAO:null},this._frameCtx.renderListenerCtx=new SceneJS.RenderContext(this._frameCtx),this.objectListDirty=!0,this.stateOrderDirty=!0,this.stateSortDirty=!0,this.drawListDirty=!0,this.imageDirty=!0,this.pickBufDirty=!0,this.rayPickBufDirty=!0};SceneJS_Display.prototype.webglRestored=function(){this._programFactory.webglRestored(),this._chunkFactory.webglRestored();var a=this._canvas.gl;this.pickBuf&&this.pickBuf.webglRestored(a),this.rayPickBuf&&this.rayPickBuf.webglRestored(a),this.imageDirty=!0},SceneJS_Display.prototype.buildObject=function(a){var b=this._objects[a];b||(b=this._objects[a]=this._objectFactory.getObject(a),this.objectListDirty=!0),b.stage=this.stage,b.layer=this.layer,b.renderTarget=this.renderTarget,b.texture=this.texture,b.cubemap=this.cubemap,b.geometry=this.geometry,b.enable=this.enable,b.flags=this.flags,b.tag=this.tag;var c=[this.geometry.hash,this.shader.hash,this.clips.hash,this.morphGeometry.hash,this.texture.hash,this.cubemap.hash,this.lights.hash,this.flags.hash].join(";");b.program&&c==b.hash||(b.program&&this._programFactory.putProgram(b.program),b.program=this._programFactory.getProgram(c,this),b.hash=c),this._setChunk(b,0,"program"),this._setChunk(b,1,"xform",this.modelTransform),this._setChunk(b,2,"lookAt",this.viewTransform),this._setChunk(b,3,"camera",this.projTransform),this._setChunk(b,4,"flags",this.flags),this._setChunk(b,5,"shader",this.shader),this._setChunk(b,6,"shaderParams",this.shaderParams),this._setChunk(b,7,"style",this.style),this._setChunk(b,8,"depthBuffer",this.depthBuffer),this._setChunk(b,9,"colorBuffer",this.colorBuffer),this._setChunk(b,10,"view",this.view),this._setChunk(b,11,"name",this.name),this._setChunk(b,12,"lights",this.lights),this._setChunk(b,13,"material",this.material),this._setChunk(b,14,"texture",this.texture),this._setChunk(b,15,"cubemap",this.cubemap),this._setChunk(b,16,"clips",this.clips),this._setChunk(b,17,"renderer",this.renderer),this._setChunk(b,18,"geometry",this.morphGeometry,this.geometry),this._setChunk(b,19,"listeners",this.renderListeners),this._setChunk(b,20,"draw",this.geometry)},SceneJS_Display.prototype._setChunk=function(a,b,c,d,e){var f,g=this._chunkFactory.chunkTypes[c];if(d){if(d.empty){var h=a.chunks[b];return h&&this._chunkFactory.putChunk(h),void(a.chunks[b]=null)}f=g.prototype.programGlobal?"_"+d.stateId:"p"+a.program.id+"_"+d.stateId,e&&(f+="__"+e.stateId)}else f="p"+a.program.id;f=b+"__"+f;var h=a.chunks[b];if(h){if(h.id==f)return;this._chunkFactory.putChunk(h)}a.chunks[b]=this._chunkFactory.getChunk(f,c,a.program,d,e),"lights"==c&&this._setAmbient(d)},SceneJS_Display.prototype._setAmbient=function(a){for(var b,c=a.lights,d=0,e=c.length;e>d;d++)b=c[d],"ambient"==b.mode&&(this._ambientColor[0]=b.color[0],this._ambientColor[1]=b.color[1],this._ambientColor[2]=b.color[2])},SceneJS_Display.prototype.removeObject=function(a){var b=this._objects[a];b&&(this._programFactory.putProgram(b.program),b.program=null,b.hash=null,this._objectFactory.putObject(b),delete this._objects[a],this.objectListDirty=!0)},SceneJS_Display.prototype.selectTags=function(a){this._tagSelector=a,this.drawListDirty=!0},SceneJS_Display.prototype.render=function(a){a=a||{},this.objectListDirty&&(this._buildObjectList(),this.objectListDirty=!1,this.stateOrderDirty=!0),this.stateOrderDirty&&(this._makeStateSortKeys(),this.stateOrderDirty=!1,this.stateSortDirty=!0),this.stateSortDirty&&(this._stateSort(),this.stateSortDirty=!1,this.drawListDirty=!0),this.drawListDirty&&(this._buildDrawList(),this.imageDirty=!0),(this.imageDirty||a.force)&&(this._doDrawList({clear:a.clear!==!1}),this.imageDirty=!1,this.pickBufDirty=!0)},SceneJS_Display.prototype._buildObjectList=function(){this._objectListLen=0;for(var a in this._objects)this._objects.hasOwnProperty(a)&&(this._objectList[this._objectListLen++]=this._objects[a])},SceneJS_Display.prototype._makeStateSortKeys=function(){for(var a,b=0,c=this._objectListLen;c>b;b++)a=this._objectList[b],a.program?a.sortKey=1e12*(a.stage.priority+1)+1e9*(a.flags.transparent?2:1)+1e6*(a.layer.priority+1)+1e3*(a.program.id+1)+a.texture.stateId:a.sortKey=-1},SceneJS_Display.prototype._stateSort=function(){this._objectList.length=this._objectListLen,this._objectList.sort(this._stateSortObjects)},SceneJS_Display.prototype._stateSortObjects=function(a,b){return a.sortKey-b.sortKey},SceneJS_Display.prototype._logObjectList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._objectListLen+" objects");for(var a=0,b=this._objectListLen;b>a;a++){var c=this._objectList[a];console.log("SceneJS_Display : object["+a+"] sortKey = "+c.sortKey)}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._buildDrawList=function(){this._lastStateId=this._lastStateId||[],this._lastPickStateId=this._lastPickStateId||[];for(var a=0;23>a;a++)this._lastStateId[a]=null,this._lastPickStateId[a]=null;this._drawListLen=0,this._pickDrawListLen=0;var b,c,d,e,f,g={},h=[],i=[];this._tagSelector&&(c=this._tagSelector.mask,d=this._tagSelector.regex),this._objectDrawList=this._objectDrawList||[],this._objectDrawListLen=0;for(var a=0,j=this._objectListLen;j>a;a++)if(b=this._objectList[a],b.enable.enabled!==!1&&(f=b.flags,f.enabled!==!1&&b.layer.enabled&&(!c||(e=b.tag,!e.tag||(e.mask!=c&&(e.mask=c,e.matches=d.test(e.tag)),e.matches)))))if(b.renderTarget.targets)for(var k,l,m,n=b.renderTarget.targets,o=0,p=n.length;p>o;o++)k=n[o],l=k.coreId,m=g[l],m||(m=[],g[l]=m,h.push(m),i.push(this._chunkFactory.getChunk(k.stateId,"renderTarget",b.program,k))),m.push(b);else this._objectDrawList[this._objectDrawListLen++]=b;for(var m,k,b,q,a=0,j=h.length;j>a;a++){m=h[a],k=i[a],this._appendRenderTargetChunk(k);for(var o=0,p=m.length;p>o;o++)b=m[o],q=b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q)}b&&this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1,"renderTarget",b.program,{}));for(var a=0,j=this._objectDrawListLen;j>a;a++)b=this._objectDrawList[a],q=!b.stage||b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q);this.drawListDirty=!1},SceneJS_Display.prototype._appendRenderTargetChunk=function(a){this._drawList[this._drawListLen++]=a},SceneJS_Display.prototype._appendObjectToDrawLists=function(a,b){for(var c,d=a.chunks,e=a.flags.picking,f=0,g=d.length;g>f;f++)c=d[f],c&&(c.draw&&(c.unique||this._lastStateId[f]!=c.id)&&(this._drawList[this._drawListLen++]=c,this._lastStateId[f]=c.id),c.pick&&b!==!1&&e&&(c.unique||this._lastPickStateId[f]!=c.id)&&(this._pickDrawList[this._pickDrawListLen++]=c,this._lastPickStateId[f]=c.id))},SceneJS_Display.prototype._logDrawList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._drawListLen+" draw list chunks");for(var a=0,b=this._drawListLen;b>a;a++){var c=this._drawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._logPickList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._pickDrawListLen+" pick list chunks");for(var a=0,b=this._pickDrawListLen;b>a;a++){var c=this._pickDrawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype.pick=function(a){var b=this._canvas.canvas,c=this._canvas.ssaaMultiplier,d=null,e=a.canvasX*c,f=a.canvasY*c,g=this.pickBuf;g||(g=this.pickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.pickBufDirty=!0),this.render(),g.bind(),this.pickBufDirty&&(g.clear(),this._doDrawList({pick:!0,clear:!0}),this._canvas.gl.finish(),this.pickBufDirty=!1,this.rayPickBufDirty=!0);var h=g.read(e,f),i=h[0]+256*h[1]+65536*h[2],j=i>=1?i-1:-1;g.unbind();var k=this._frameCtx.pickNames[j];if(k&&(d={name:k.name,path:k.path,nodeId:k.nodeId,canvasPos:[e,f]},a.rayPick)){var l=this.rayPickBuf;l||(l=this.rayPickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.rayPickBufDirty=!0),l.bind(),this.rayPickBufDirty&&(l.clear(),this._doDrawList({pick:!0,rayPick:!0,clear:!0}),this.rayPickBufDirty=!1),h=l.read(e,f),l.unbind();var m=this._unpackDepth(h),n=b.width,o=b.height,p=(e-n/2)/(n/2),q=-(f-o/2)/(o/2),r=this._frameCtx.cameraMat,s=this._frameCtx.viewMat,t=SceneJS_math_mulMat4(r,s,[]),u=SceneJS_math_inverseMat4(t,[]),v=SceneJS_math_transformVector4(u,[p,q,-1,1]);v=SceneJS_math_mulVec4Scalar(v,1/v[3]);var w=SceneJS_math_transformVector4(u,[p,q,1,1]);w=SceneJS_math_mulVec4Scalar(w,1/w[3]);var x=SceneJS_math_subVec3(w,v,[]),y=SceneJS_math_addVec3(v,SceneJS_math_mulVec4Scalar(x,m,[]),[]);d.worldPos=y}return d},SceneJS_Display.prototype.readPixels=function(a,b){this._readPixelBuf||(this._readPixelBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas})),this._readPixelBuf.bind(),this._readPixelBuf.clear(),this.render({force:!0});for(var c,d,e=0;b>e;e++)c=a[e]||(a[e]={}),d=this._readPixelBuf.read(c.x,c.y),c.r=d[0],c.g=d[1],c.b=d[2],c.a=d[3];this._readPixelBuf.unbind()},SceneJS_Display.prototype._unpackDepth=function(a){var b=[a[0]/256,a[1]/256,a[2]/256,a[3]/256],c=[1/16777216,1/65536,1/256,1];return SceneJS_math_dotVector4(b,c)},SceneJS_Display.prototype._doDrawList=function(a){var b=this._canvas.gl,c=this._frameCtx;c.renderTarget=null,c.targetIndex=0,c.renderBuf=null,c.viewMat=null,c.modelMat=null,c.cameraMat=null,c.renderer=null,c.depthbufEnabled=null,c.clearDepth=null,c.depthFunc=b.LESS,c.scissorTestEnabled=!1,c.blendEnabled=!1,c.backfaces=!0,c.frontface="ccw",c.pick=!!a.pick,c.rayPick=!!a.rayPick,c.pickIndex=0,c.textureUnit=0,c.lineWidth=1,c.transparent=!1,c.ambientColor=this._ambientColor,c.aspect=this._canvas.canvas.width/this._canvas.canvas.height,this._canvas.UINT_INDEX_ENABLED&&b.getExtension("OES_element_index_uint");var d=b.getExtension("OES_vertex_array_object");if(c.VAO=d?d:null,b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),this.transparent?b.clearColor(0,0,0,0):b.clearColor(this._ambientColor[0],this._ambientColor[1],this._ambientColor[2],1),a.clear&&b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),b.frontFace(b.CCW),b.disable(b.CULL_FACE),b.disable(b.BLEND),a.pick)for(var e=0,f=this._pickDrawListLen;f>e;e++)this._pickDrawList[e].pick(c);else for(var e=0,f=this._drawListLen;f>e;e++)this._drawList[e].draw(c);if(b.flush(),c.renderBuf&&c.renderBuf.unbind(),c.VAO){c.VAO.bindVertexArrayOES(null);for(var e=0;10>e;e++)b.disableVertexAttribArray(e)}},SceneJS_Display.prototype.destroy=function(){this._programFactory.destroy()};var SceneJS_ProgramSourceFactory=new function(){function a(a){if(a.renderTarget&&a.renderTarget.targets)for(var b=a.renderTarget.targets,c=0,d=b.length;d>c;c++)if("depth"===b[c].bufType)return!0;return!1}this._sourceCache={},this.getSource=function(a,b){var c=this._sourceCache[a];return c?(c.useCount++,c):this._sourceCache[a]=new SceneJS_ProgramSource(a,this._composePickingVertexShader(b),this._composePickingFragmentShader(b),this._composeRenderingVertexShader(b),this._composeRenderingFragmentShader(b))},this.putSource=function(a){var b=this._sourceCache[a];b&&0==--b.useCount&&(this._sourceCache[b.hash]=null)},this._composePickingVertexShader=function(a){var b=!!a.morphGeometry.targets,c=["precision mediump float;","attribute vec3 SCENEJS_aVertex;","uniform mat4 SCENEJS_uMMatrix;","uniform mat4 SCENEJS_uVMatrix;","uniform mat4 SCENEJS_uVNMatrix;","uniform mat4 SCENEJS_uPMatrix;"];return c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),b&&(c.push("uniform float SCENEJS_uMorphFactor;"),a.morphGeometry.targets[0].vertexBuf&&c.push("attribute vec3 SCENEJS_aMorphVertex;")),c.push("void main(void) {"),c.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "),b&&a.morphGeometry.targets[0].vertexBuf&&c.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "),c.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "),c.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"),c.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"),c.push("}"),c},this._composePickingFragmentShader=function(a){var b=a.clips.clips.length>0,c=["precision mediump float;"];if(c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),c.push("uniform bool SCENEJS_uRayPickMode;"),c.push("uniform vec3 SCENEJS_uPickColor;"),c.push("uniform float SCENEJS_uZNear;"),c.push("uniform float SCENEJS_uZFar;"),c.push("uniform bool SCENEJS_uClipping;"),b)for(var d=0;d 0.0) { discard; }"),c.push("}")}return c.push(" if (SCENEJS_uRayPickMode) {"),c.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"),c.push(" gl_FragColor = packDepth(zNormalizedDepth); "),c.push(" } else {"),c.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "),c.push(" }"),c.push("}"),c},this._isTexturing=function(a){if(a.texture.layers&&a.texture.layers.length>0){if(a.geometry.uvBuf||a.geometry.uvBuf2)return!0;if(a.morphGeometry.targets&&(a.morphGeometry.targets[0].uvBuf||a.morphGeometry.targets[0].uvBuf2))return!0}return!1},this._isCubeMapping=function(a){return a.flags.reflective&&a.cubemap.layers&&a.cubemap.layers.length>0&&a.geometry.normalBuf},this._hasNormals=function(a){return a.geometry.normalBuf?!0:a.morphGeometry.targets&&a.morphGeometry.targets[0].normalBuf?!0:!1},this._hasTangents=function(a){if(a.texture){var b=a.texture.layers;if(!b)return!1;for(var c=0,d=b.length;d>c;c++)if("normals"==b[c].applyTo)return!0}return!1},this._composeRenderingVertexShader=function(a){var b=a.shader.shaders||{};if(b.vertex&&b.vertex.code&&""!=b.vertex.code&&SceneJS._isEmpty(b.vertex.hooks))return[b.vertex.code];var c=b.vertex||{},d=c.hooks||{},e=b.fragment||{},f=e.hooks||{},g=this._isTexturing(a),h=this._hasNormals(a),i=this._hasTangents(a),j=a.clips.clips.length>0,k=!!a.morphGeometry.targets,l=["precision mediump float;"];if(l.push("uniform mat4 SCENEJS_uMMatrix;"),l.push("uniform mat4 SCENEJS_uVMatrix;"),l.push("uniform mat4 SCENEJS_uPMatrix;"),l.push("attribute vec3 SCENEJS_aVertex;"),l.push("uniform vec3 SCENEJS_uWorldEye;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("attribute vec3 SCENEJS_aNormal;"),l.push("uniform mat4 SCENEJS_uMNMatrix;"),l.push("uniform mat4 SCENEJS_uVNMatrix;"),l.push("varying vec3 SCENEJS_vViewNormal;"),i&&l.push("attribute vec4 SCENEJS_aTangent;");for(var m=0;m0,l=["\n"];if(l.push("precision mediump float;"),k&&l.push("varying vec4 SCENEJS_vWorldVertex;"),l.push("varying vec4 SCENEJS_vViewVertex;"),l.push("uniform float SCENEJS_uZNear;"),l.push("uniform float SCENEJS_uZFar;"),k)for(var m=0;mm;m++)n=b.texture.layers[m],l.push("uniform sampler2D SCENEJS_uSampler"+m+";"),n.matrix&&l.push("uniform mat4 SCENEJS_uLayer"+m+"Matrix;"),l.push("uniform float SCENEJS_uLayer"+m+"BlendFactor;")}if(h&&g)for(var n,m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("uniform samplerCube SCENEJS_uCubeMapSampler"+m+";"),l.push("uniform float SCENEJS_uCubeMapIntensity"+m+";");if(l.push("uniform bool SCENEJS_uClipping;"),l.push("uniform bool SCENEJS_uSolid;"),l.push("uniform bool SCENEJS_uDepthMode;"),l.push("uniform bool SCENEJS_uTransparent;"),b.geometry.colorBuf&&l.push("varying vec4 SCENEJS_vColor;"),l.push("uniform vec3 SCENEJS_uAmbientColor;"),l.push("uniform vec3 SCENEJS_uMaterialColor;"),l.push("uniform float SCENEJS_uMaterialAlpha;"),l.push("uniform float SCENEJS_uMaterialEmit;"),l.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"),l.push("uniform float SCENEJS_uMaterialSpecular;"),l.push("uniform float SCENEJS_uMaterialShine;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("varying vec3 SCENEJS_vViewNormal;");for(var p,m=0;m 0.0) { discard; }"),l.push("}")}h&&i&&(l.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"),l.push(" if (a < 0.0) {"),l.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"),l.push(" return;"),l.push(" }")),l.push(" vec3 ambient= SCENEJS_uAmbientColor;"),f&&b.geometry.uvBuf&&e.texturePos&&l.push(e.texturePos+"(SCENEJS_vUVCoord);"),e.viewPos&&l.push(e.viewPos+"(SCENEJS_vViewVertex);"),h&&e.viewNormal&&l.push(e.viewNormal+"(SCENEJS_vViewNormal);"),b.geometry.colorBuf?l.push(" vec3 color = SCENEJS_vColor.rgb;"):l.push(" vec3 color = SCENEJS_uMaterialColor;"),l.push(" float alpha = SCENEJS_uMaterialAlpha;"),l.push(" float emit = SCENEJS_uMaterialEmit;"),l.push(" float specular = SCENEJS_uMaterialSpecular;"),l.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"),l.push(" float shine = SCENEJS_uMaterialShine;"),e.materialBaseColor&&l.push("color="+e.materialBaseColor+"(color);"),e.materialAlpha&&l.push("alpha="+e.materialAlpha+"(alpha);"),e.materialEmit&&l.push("emit="+e.materialEmit+"(emit);"),e.materialSpecular&&l.push("specular="+e.materialSpecular+"(specular);"),e.materialSpecularColor&&l.push("specularColor="+e.materialSpecularColor+"(specularColor);"),e.materialShine&&l.push("shine="+e.materialShine+"(shine);"),h&&(l.push(" float attenuation = 1.0;"),j?l.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"):l.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"));var n;if(f){l.push(" vec4 texturePos;"),l.push(" vec2 textureCoord=vec2(0.0,0.0);");for(var m=0,o=b.texture.layers.length;o>m;m++){if(n=b.texture.layers[m],"normal"==n.applyFrom&&h){if(!b.geometry.normalBuf){SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors");continue}l.push("texturePos=vec4(viewNormalVec.xyz, 1.0);")}if("uv"==n.applyFrom){if(!b.geometry.uvBuf){SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);")}if("uv2"==n.applyFrom){if(!b.geometry.uvBuf2){SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);")}n.matrix?l.push("textureCoord=(SCENEJS_uLayer"+m+"Matrix * texturePos).xy;"):l.push("textureCoord=texturePos.xy;"),"alpha"==n.applyTo&&("multiply"==n.blendMode?l.push("alpha = alpha * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"):"add"==n.blendMode&&l.push("alpha = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * alpha) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);")),"baseColor"==n.applyTo&&("multiply"==n.blendMode?l.push("color = color * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"):l.push("color = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * color) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);")),"emit"==n.applyTo&&("multiply"==n.blendMode?l.push("emit = emit * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("emit = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * emit) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"specular"==n.applyTo&&h&&("multiply"==n.blendMode?l.push("specular = specular * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("specular = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * specular) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"shine"==n.applyTo&&("multiply"==n.blendMode?l.push("shine = shine * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("shine = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * shine) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"normals"==n.applyTo&&h&&l.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);")}}if(h&&g){l.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"),l.push("envLookup.y = envLookup.y * -1.0;"),l.push("vec4 envColor;");for(var m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("envColor = textureCube(SCENEJS_uCubeMapSampler"+m+", envLookup);"),l.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity"+m+");")}if(l.push(" vec4 fragColor;"),h){l.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 viewLightVec;"),l.push(" float dotN;"),l.push(" float lightDist;");for(var p,m=0,o=b.lights.lights.length;o>m;m++)p=b.lights.lights[m],"ambient"!=p.mode&&(l.push("viewLightVec = SCENEJS_vViewLightVecAndDist"+m+".xyz;"),"point"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),l.push("lightDist = SCENEJS_vViewLightVecAndDist"+m+".w;"),l.push("attenuation = 1.0 - ( SCENEJS_uLightAttenuation"+m+"[0] + SCENEJS_uLightAttenuation"+m+"[1] * lightDist + SCENEJS_uLightAttenuation"+m+"[2] * lightDist * lightDist);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+" * attenuation;"),p.specular&&l.push(" specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;")),"dir"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+";"),p.specular&&l.push("specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);")));l.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);")}else l.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);");return e.pixelColor&&l.push("fragColor="+e.pixelColor+"(fragColor);"),a(b)?(l.push(" if (SCENEJS_uDepthMode) {"),l.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"),l.push(" const vec4 bias = vec4(1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 0.0);"),l.push(" float r = depth;"),l.push(" float g = fract(r * 255.0);"),l.push(" float b = fract(g * 255.0);"),l.push(" float a = fract(b * 255.0);"),l.push(" vec4 colour = vec4(r, g, b, a);"),l.push(" gl_FragColor = colour - (colour.yzww * bias);"),l.push(" } else {"),l.push(" gl_FragColor = fragColor;"),l.push(" };")):l.push(" gl_FragColor = fragColor;"),l.push("}"),l}},SceneJS_ProgramSource=function(a,b,c,d,e){this.hash=a,this.pickVertexSrc=b,this.pickFragmentSrc=c,this.drawVertexSrc=d,this.drawFragmentSrc=e,this.useCount=0},SceneJS_ProgramFactory=function(a){this._canvas=a.canvas,this._programs={},this._nextProgramId=0};SceneJS_ProgramFactory.prototype.getProgram=function(a,b){var c=this._programs[a];if(!c){var d=SceneJS_ProgramSourceFactory.getSource(a,b);c=new SceneJS_Program(this._nextProgramId++,a,d,this._canvas.gl),this._programs[a]=c}return c.useCount++,c},SceneJS_ProgramFactory.prototype.putProgram=function(a){--a.useCount<=0&&(a.draw.destroy(),a.pick.destroy(),SceneJS_ProgramSourceFactory.putSource(a.hash),delete this._programs[a.hash])},SceneJS_ProgramFactory.prototype.webglRestored=function(){var a,b=this._canvas.gl;for(var c in this._programs)this._programs.hasOwnProperty(c)&&(a=this._programs[c],a&&a.build&&a.build(b))},SceneJS_ProgramFactory.prototype.destroy=function(){};var SceneJS_Program=function(a,b,c,d){this.id=a,this.hash=c.hash,this.source=c,this.gl=d,this.UINT_INDEX_ENABLED=!!d.getExtension("OES_element_index_uint"),this.draw=null,this.pick=null,this.useCount=0,this.build(d)};SceneJS_Program.prototype.build=function(a){this.gl=a,this.draw=new SceneJS._webgl.Program(a,[this.source.drawVertexSrc.join("\n")],[this.source.drawFragmentSrc.join("\n")]),this.pick=new SceneJS._webgl.Program(a,[this.source.pickVertexSrc.join("\n")],[this.source.pickFragmentSrc.join("\n")])};var SceneJS_ObjectFactory=function(){};SceneJS_ObjectFactory.prototype._freeObjects=[],SceneJS_ObjectFactory.prototype._numFreeObjects=0,SceneJS_ObjectFactory.prototype.getObject=function(a){ -var b;return this._numFreeObjects>0?(b=this._freeObjects[--this._numFreeObjects],b.id=a,b):new SceneJS_Object(a)},SceneJS_ObjectFactory.prototype.putObject=function(a){this._freeObjects[this._numFreeObjects++]=a};var SceneJS_Object=function(a){this.id=a,this.hash=null,this.sortKey=null,this.chunks=[],this.chunksLen=0,this.program=null,this.layer=null,this.texture=null,this.flags=null,this.tag=null};SceneJS.RenderContext=function(a){this._frameCtx=a},SceneJS.RenderContext.prototype.getCameraMatrix=function(){return this._frameCtx.cameraMat},SceneJS.RenderContext.prototype.getViewMatrix=function(){return this._frameCtx.viewMat},SceneJS.RenderContext.prototype.getModelMatrix=function(){return this._frameCtx.modelMat},SceneJS.RenderContext.prototype.getCanvasPos=function(a){this.getProjPos(a);var b=this._frameCtx.canvas.canvas,c=this._frameCtx.canvas.ssaaMultiplier,d=b.width/c,e=b.height/c,f=this._pc,g=f[0]/f[3]*d*.5,h=f[1]/f[3]*e*.5;return{x:g+.5*d,y:e-h-.5*e}},SceneJS.RenderContext.prototype.getCameraPos=function(a){return this.getProjPos(a),this._camPos=SceneJS_math_normalizeVec3(this._pc,[0,0,0]),{x:this._camPos[0],y:this._camPos[1],z:this._camPos[2]}},SceneJS.RenderContext.prototype.getProjPos=function(a){return this.getViewPos(a),this._pc=SceneJS_math_transformPoint3(this._frameCtx.cameraMat,this._vc),{x:this._pc[0],y:this._pc[1],z:this._pc[2],w:this._pc[3]}},SceneJS.RenderContext.prototype.getViewPos=function(a){return this.getWorldPos(a),this._vc=SceneJS_math_transformPoint3(this._frameCtx.viewMat,this._wc),{x:this._vc[0],y:this._vc[1],z:this._vc[2],w:this._vc[3]}},SceneJS.RenderContext.prototype.getWorldPos=function(a){return this._wc=SceneJS_math_transformPoint3(this._frameCtx.modelMat,a||[0,0,0]),{x:this._wc[0],y:this._wc[1],z:this._wc[2],w:this._wc[3]}};var SceneJS_Chunk=function(){};SceneJS_Chunk.prototype.init=function(a,b,c,d){this.id=a,this.program=b,this.core=c,this.core2=d,this.build&&this.build()};var SceneJS_ChunkFactory=function(){this._chunks={},this.chunkTypes=SceneJS_ChunkFactory.chunkTypes};SceneJS_ChunkFactory.chunkTypes={},SceneJS_ChunkFactory._freeChunks={},SceneJS_ChunkFactory.createChunkType=function(a){if(!a.type)throw"'type' expected in params";var b=SceneJS_Chunk,c=function(){this.useCount=0,this.init.apply(this,arguments)};return c.prototype=new b,c.prototype.constructor=c,a.drawAndPick&&(a.draw=a.pick=a.drawAndPick),SceneJS_ChunkFactory.chunkTypes[a.type]=c,SceneJS._apply(a,c.prototype),SceneJS_ChunkFactory._freeChunks[a.type]={chunks:[],chunksLen:0},c},SceneJS_ChunkFactory.prototype.getChunk=function(a,b,c,d,e){var f=SceneJS_ChunkFactory.chunkTypes[b];if(!f)throw"chunk type not supported: '"+b+"'";var g=this._chunks[a];if(g)return g.useCount++,g;var h=SceneJS_ChunkFactory._freeChunks[b];return h.chunksLen>0&&(g=h.chunks[--h.chunksLen]),g?g.init(a,c,d,e):g=new f(a,c,d,e),g.type=b,g.useCount=1,this._chunks[a]=g,g},SceneJS_ChunkFactory.prototype.putChunk=function(a){if(0!=a.useCount&&--a.useCount<=0){a.recycle&&a.recycle(),delete this._chunks[a.id];var b=SceneJS_ChunkFactory._freeChunks[a.type];b.chunks[b.chunksLen++]=a}},SceneJS_ChunkFactory.prototype.webglRestored=function(){var a;for(var b in this._chunks)this._chunks.hasOwnProperty(b)&&(a=this._chunks[b],a&&a.build&&a.build())},SceneJS_ChunkFactory.createChunkType({type:"camera",build:function(){this._uPMatrixDraw=this.program.draw.getUniform("SCENEJS_uPMatrix"),this._uZNearDraw=this.program.draw.getUniform("SCENEJS_uZNear"),this._uZFarDraw=this.program.draw.getUniform("SCENEJS_uZFar"),this._uPMatrixPick=this.program.pick.getUniform("SCENEJS_uPMatrix"),this._uZNearPick=this.program.pick.getUniform("SCENEJS_uZNear"),this._uZFarPick=this.program.pick.getUniform("SCENEJS_uZFar")},draw:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixDraw&&this._uPMatrixDraw.setValue(this.core.mat),this._uZNearDraw&&this._uZNearDraw.setValue(this.core.optics.near),this._uZFarDraw&&this._uZFarDraw.setValue(this.core.optics.far),a.cameraMat=this.core.mat},pick:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixPick&&this._uPMatrixPick.setValue(this.core.mat),a.rayPick&&(this._uZNearPick&&this._uZNearPick.setValue(this.core.optics.near),this._uZFarPick&&this._uZFarPick.setValue(this.core.optics.far)),a.cameraMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"clips",build:function(){this._draw=this._draw||[];for(var a=this.program.draw,b=0,c=this.core.clips.length;c>b;b++)this._draw[b]={uClipMode:a.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:a.getUniform("SCENEJS_uClipNormalAndDist"+b)};this._pick=this._pick||[];for(var d=this.program.pick,b=0,c=this.core.clips.length;c>b;b++)this._pick[b]={uClipMode:d.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:d.getUniform("SCENEJS_uClipNormalAndDist"+b)}},drawAndPick:function(a){for(var b,c,d,e=a.pick?this._pick:this._draw,f=this.core.clips,g=(this.program.gl,0),h=f.length;h>g;g++)a.pick?(b=e[g].uClipMode,c=e[g].uClipNormalAndDist):(b=e[g].uClipMode,c=e[g].uClipNormalAndDist),b&&c&&(d=f[g],"inside"==d.mode?(b.setValue(2),c.setValue(d.normalAndDist)):"outside"==d.mode?(b.setValue(1),c.setValue(d.normalAndDist)):b.setValue(0))}}),SceneJS_ChunkFactory.createChunkType({type:"draw",unique:!0,build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode")},drawAndPick:function(a){var b=this.program.gl,c=this.program.UINT_INDEX_ENABLED?b.UNSIGNED_INT:b.UNSIGNED_SHORT;a.pick?this._depthModePick&&this._depthModePick.setValue(a.depthMode):this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),b.drawElements(this.core.primitive,this.core.indexBuf.numItems,c,0)}}),SceneJS_ChunkFactory.createChunkType({type:"flags",build:function(){var a=this.program.draw;this._uClippingDraw=a.getUniform("SCENEJS_uClipping"),this._uSolidDraw=a.getUniform("SCENEJS_uSolid");var b=this.program.pick;this._uClippingPick=b.getUniform("SCENEJS_uClipping")},drawAndPick:function(a){var b=this.program.gl,c=this.core.backfaces;a.backfaces!=c&&(c?b.disable(b.CULL_FACE):b.enable(b.CULL_FACE),a.backfaces=c);var d=this.core.frontface;a.frontface!=d&&("ccw"==d?b.frontFace(b.CCW):b.frontFace(b.CW),a.frontface=d);var e=this.core.transparent;a.transparent!=e&&(a.pick||(e?(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA),a.blendEnabled=!0):(b.disable(b.BLEND),a.blendEnabled=!1)),a.transparent=e),a.pick?this._uClippingPick&&this._uClippingPick.setValue(this.core.clipping):(this._uClippingDraw&&this._uClippingDraw.setValue(this.core.clipping),this._uSolidDraw&&this._uSolidDraw.setValue(this.core.solid))}}),SceneJS_ChunkFactory.createChunkType({type:"renderTarget",programGlobal:!0,draw:function(a){var b=this.program.gl;a.renderBuf&&(b.flush(),a.renderBuf.unbind(),a.renderBuf=null);var c=this.core.renderBuf;return c?(c.bind(),a.depthMode="depth"===this.core.bufType,a.depthMode||a.blendEnabled&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA)),b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),b.clearColor(a.ambientColor[0],a.ambientColor[1],a.ambientColor[2],1),b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),void(a.renderBuf=c)):void(a.depthMode=!1)}}),SceneJS_ChunkFactory.createChunkType({type:"geometry",build:function(){var a=this.program.draw;this._aVertexDraw=a.getAttribute("SCENEJS_aVertex"),this._aNormalDraw=a.getAttribute("SCENEJS_aNormal"),this._aUVDraw=a.getAttribute("SCENEJS_aUVCoord"),this._aUV2Draw=a.getAttribute("SCENEJS_aUVCoord2"),this._aTangentDraw=a.getAttribute("SCENEJS_aTangent"),this._aColorDraw=a.getAttribute("SCENEJS_aVertexColor"),this._aMorphVertexDraw=a.getAttribute("SCENEJS_aMorphVertex"),this._aMorphNormalDraw=a.getAttribute("SCENEJS_aMorphNormal"),this._uMorphFactorDraw=a.getUniform("SCENEJS_uMorphFactor");var b=this.program.pick;this._aVertexPick=b.getAttribute("SCENEJS_aVertex"),this._aMorphVertexPick=b.getAttribute("SCENEJS_aMorphVertex"),this._uMorphFactorPick=b.getUniform("SCENEJS_uMorphFactor"),this.VAO=null,this.VAOMorphKey1=0,this.VAOMorphKey2=0,this.VAOHasInterleavedBuf=!1},recycle:function(){if(this.VAO){var a=this.program.gl.getExtension("OES_vertex_array_object");a.deleteVertexArrayOES(this.VAO),this.VAO=null}},morphDraw:function(){this.VAOMorphKey1=this.core.key1,this.VAOMorphKey2=this.core.key2;var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexDraw?(this._aVertexDraw.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexDraw.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aMorphNormalDraw?(this._aNormalDraw.bindFloatArrayBuffer(a.normalBuf),this._aMorphNormalDraw.bindFloatArrayBuffer(b.normalBuf)):this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this.setDrawMorphFactor()},setDrawMorphFactor:function(){this._uMorphFactorDraw&&this._uMorphFactorDraw.setValue*this.core.factor},draw:function(a){var b=this.core.targets&&this.core.targets.length,c=this.core2.interleavedBuf&&!this.core2.interleavedBuf.dirty;if(this.VAO){if(a.VAO.bindVertexArrayOES(this.VAO),b){if(this.VAOMorphKey1==this.core.key1&&this.VAOMorphKey2==this.core.key2)return void this.setDrawMorphFactor()}else if(c||!this.VAOHasInterleavedBuf)return}else if(a.VAO){a.VAO.bindVertexArrayOES(null),this.VAO=a.VAO.createVertexArrayOES(),a.VAO.bindVertexArrayOES(this.VAO);this.program.gl}b?this.morphDraw():c?(this.VAOHasInterleavedBuf=!0,this.core2.interleavedBuf.bind(),this._aVertexDraw&&this._aVertexDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedPositionOffset),this._aNormalDraw&&this._aNormalDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedNormalOffset),this._aUVDraw&&this._aUVDraw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUVOffset),this._aUV2Draw&&this._aUV2Draw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUV2Offset),this._aColorDraw&&this._aColorDraw.bindInterleavedFloatArrayBuffer(4,this.core2.interleavedStride,this.core2.interleavedColorOffset),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())):(this.VAOHasInterleavedBuf=!1,this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())),this.core2.indexBuf.bind()},morphPick:function(){var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexPick?(this._aVertexPick.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexPick.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this._uMorphFactorPick&&this._uMorphFactorPick.setValue(this.core.factor)},pick:function(a){this.core.targets&&this.core.targets.length?this.morphPick():this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this.core2.indexBuf.bind()}}),SceneJS_ChunkFactory.createChunkType({type:"lights",build:function(){this._uAmbientColor=this._uAmbientColor||[],this._uLightColor=this._uLightColor||[],this._uLightDir=this._uLightDir||[],this._uLightPos=this._uLightPos||[],this._uLightCutOff=this._uLightCutOff||[],this._uLightSpotExp=this._uLightSpotExp||[],this._uLightAttenuation=this._uLightAttenuation||[];for(var a=this.core.lights,b=this.program,c=0,d=a.length;d>c;c++)switch(a[c].mode){case"ambient":this._uAmbientColor[c]=b.draw.getUniform("SCENEJS_uAmbientColor");break;case"dir":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=null,this._uLightDir[c]=b.draw.getUniform("SCENEJS_uLightDir"+c);break;case"point":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=b.draw.getUniform("SCENEJS_uLightPos"+c),this._uLightDir[c]=null,this._uLightAttenuation[c]=b.draw.getUniform("SCENEJS_uLightAttenuation"+c)}},draw:function(a){a.dirty&&this.build();for(var b,c=this.core.lights,d=(this.program.gl,0),e=c.length;e>d;d++)b=c[d],this._uAmbientColor[d]?this._uAmbientColor[d].setValue(b.color):(this._uLightColor[d]&&this._uLightColor[d].setValue(b.color),this._uLightPos[d]&&(this._uLightPos[d].setValue(b.pos),this._uLightAttenuation[d]&&this._uLightAttenuation[d].setValue(b.attenuation)),this._uLightDir[d]&&this._uLightDir[d].setValue(b.dir))}}),SceneJS_ChunkFactory.createChunkType({type:"listeners",programGlobal:!0,build:function(){},draw:function(a){for(var b=this.core.listeners,c=a.renderListenerCtx,d=b.length-1;d>=0;d--)if(b[d](c)===!0)return!0}}),SceneJS_ChunkFactory.createChunkType({type:"lookAt",build:function(){this._uvMatrixDraw=this.program.draw.getUniform("SCENEJS_uVMatrix"),this._uVNMatrixDraw=this.program.draw.getUniform("SCENEJS_uVNMatrix"),this._uWorldEyeDraw=this.program.draw.getUniform("SCENEJS_uWorldEye"),this._uvMatrixPick=this.program.pick.getUniform("SCENEJS_uVMatrix")},draw:function(a){this.core.dirty&&this.core.rebuild();this.program.gl;this._uvMatrixDraw&&this._uvMatrixDraw.setValue(this.core.mat),this._uVNMatrixDraw&&this._uVNMatrixDraw.setValue(this.core.normalMat),this._uWorldEyeDraw&&this._uWorldEyeDraw.setValue(this.core.lookAt.eye),a.viewMat=this.core.mat},pick:function(a){this.program.gl;this._uvMatrixPick&&this._uvMatrixPick.setValue(this.core.mat),a.viewMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"material",build:function(){var a=this.program.draw;this._uMaterialBaseColor=a.getUniform("SCENEJS_uMaterialColor"),this._uMaterialSpecularColor=a.getUniform("SCENEJS_uMaterialSpecularColor"),this._uMaterialSpecular=a.getUniform("SCENEJS_uMaterialSpecular"),this._uMaterialShine=a.getUniform("SCENEJS_uMaterialShine"),this._uMaterialEmit=a.getUniform("SCENEJS_uMaterialEmit"),this._uMaterialAlpha=a.getUniform("SCENEJS_uMaterialAlpha")},draw:function(){this.program.gl;this._uMaterialBaseColor&&this._uMaterialBaseColor.setValue(this.core.baseColor),this._uMaterialSpecularColor&&this._uMaterialSpecularColor.setValue(this.core.specularColor),this._uMaterialSpecular&&this._uMaterialSpecular.setValue(this.core.specular),this._uMaterialShine&&this._uMaterialShine.setValue(this.core.shine),this._uMaterialEmit&&this._uMaterialEmit.setValue(this.core.emit),this._uMaterialAlpha&&this._uMaterialAlpha.setValue(this.core.alpha)}}),SceneJS_ChunkFactory.createChunkType({type:"name",build:function(){this._uPickColor=this.program.pick.getUniform("SCENEJS_uPickColor")},pick:function(a){if(this._uPickColor&&this.core.name){a.pickNames[a.pickIndex++]=this.core;var b=a.pickIndex>>16&255,c=a.pickIndex>>8&255,d=255&a.pickIndex;this._uPickColor.setValue([d/255,c/255,b/255])}}}),SceneJS_ChunkFactory.createChunkType({type:"program",build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode"),this._rayPickMode=this.program.pick.getUniform("SCENEJS_uRayPickMode")},draw:function(a){var b=this.program.draw;b.bind(),a.textureUnit=0;var c=this.program.gl;if(this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),!a.VAO)for(var d=0;10>d;d++)c.disableVertexAttribArray(d);a.drawProgram=this.program.draw},pick:function(a){var b=this.program.pick;b.bind();var c=this.program.gl;this._rayPickMode&&this._rayPickMode.setValue(a.rayPick),this._depthModePick&&this._depthModePick.setValue(a.depthMode),a.textureUnit=0;for(var d=0;10>d;d++)c.disableVertexAttribArray(d)}}),SceneJS_ChunkFactory.createChunkType({type:"renderer",build:function(){},drawAndPick:function(a){if(this.core.props){var b=this.program.gl;a.renderer&&(a.renderer.props.restoreProps(b),a.renderer=this.core),this.core.props.setProps(b)}}}),SceneJS_ChunkFactory.createChunkType({type:"depthBuffer",programGlobal:!0,drawAndPick:function(a){var b=this.program.gl,c=this.core.enabled;a.depthbufEnabled!=c&&(c?b.enable(b.DEPTH_TEST):b.disable(b.DEPTH_TEST),a.depthbufEnabled=c);var d=this.core.clearDepth;a.clearDepth!=d&&(b.clearDepth(d),a.clearDepth=d);var e=this.core.depthFunc;a.depthFunc!=e&&(b.depthFunc(e),a.depthFunc=e),this.core.clear&&b.clear(b.DEPTH_BUFFER_BIT)}}),SceneJS_ChunkFactory.createChunkType({type:"colorBuffer",programGlobal:!0,build:function(){},drawAndPick:function(a){if(!a.transparent){var b=this.core.blendEnabled,c=this.program.gl;a.blendEnabled!=b&&(b?c.enable(c.BLEND):c.disable(c.BLEND),a.blendEnabled=b);var d=this.core.colorMask;c.colorMask(d.r,d.g,d.b,d.a)}}}),SceneJS_ChunkFactory.createChunkType({type:"view",programGlobal:!0,build:function(){},drawAndPick:function(a){var b=this.core.scissorTestEnabled;if(a.scissorTestEnabled!=b){var c=this.program.gl;b?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST),a.scissorTestEnabled=b}}}),SceneJS_ChunkFactory.createChunkType({type:"shader",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"shaderParams",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"style",programGlobal:!0,drawAndPick:function(a){var b=this.core.lineWidth;if(a.lineWidth!=b){var c=this.program.gl;c.lineWidth(b),a.lineWidth=b}}}),SceneJS_ChunkFactory.createChunkType({type:"texture",build:function(){this._uTexSampler=this._uTexSampler||[],this._uTexMatrix=this._uTexMatrix||[],this._uTexBlendFactor=this._uTexBlendFactor||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uTexSampler[d]="SCENEJS_uSampler"+d,this._uTexMatrix[d]=c.getUniform("SCENEJS_uLayer"+d+"Matrix"),this._uTexBlendFactor[d]=c.getUniform("SCENEJS_uLayer"+d+"BlendFactor")},draw:function(a){a.textureUnit=0;var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uTexSampler[e]&&c.texture&&(d.bindTexture(this._uTexSampler[e],c.texture,a.textureUnit++),c._matrixDirty&&c.buildMatrix&&c.buildMatrix.call(c),this._uTexMatrix[e]&&this._uTexMatrix[e].setValue(c.matrixAsArray),this._uTexBlendFactor[e]&&this._uTexBlendFactor[e].setValue(c.blendFactor));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"cubemap",build:function(){this._uCubeMapSampler=this._uCubeMapSampler||[],this._uCubeMapIntensity=this._uCubeMapIntensity||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uCubeMapSampler[d]="SCENEJS_uCubeMapSampler"+d,this._uCubeMapIntensity[d]=c.getUniform("SCENEJS_uCubeMapIntensity"+d)},draw:function(a){var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uCubeMapSampler[e]&&c.texture&&(d.bindTexture(this._uCubeMapSampler[e],c.texture,a.textureUnit++),this._uCubeMapIntensity[e]&&this._uCubeMapIntensity[e].setValue(c.intensity));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"xform",build:function(){var a=this.program.draw;this._uMatLocationDraw=a.getUniform("SCENEJS_uMMatrix"),this._uNormalMatLocationDraw=a.getUniform("SCENEJS_uMNMatrix");var b=this.program.pick;this._uMatLocationPick=b.getUniform("SCENEJS_uMMatrix")},draw:function(a){(SceneJS_configsModule.configs.forceXFormCoreRebuild===!0||this.core.dirty&&this.core.build)&&this.core.build();this.program.gl;this._uMatLocationDraw&&this._uMatLocationDraw.setValue(this.core.mat),this._uNormalMatLocationDraw&&this._uNormalMatLocationDraw.setValue(this.core.normalMat),a.modelMat=this.core.mat},pick:function(a){this.core.dirty&&this.core.build();this.program.gl;this._uMatLocationPick&&this._uMatLocationPick.setValue(this.core.mat),a.modelMat=this.core.mat}}); \ No newline at end of file +if(!g)throw"no typePath config";this._loadScript(g+"/node/"+b+".js",function(){SceneJS_sceneStatusModule.taskFailed(f)})}},SceneJS_NodeFactory.prototype._loadScript=function(a,b){var c=document.createElement("script");c.type="text/javascript",c.src=a,c.onerror=b,document.getElementsByTagName("head")[0].appendChild(c)},SceneJS_NodeFactory.prototype.putNode=function(a){this.nodes.removeItem(a.id)},function(){function a(a){var b=a.optics;if("ortho"==b.type?a.matrix=SceneJS_math_orthoMat4c(b.left,b.right,b.bottom,b.top,b.near,b.far):"frustum"==b.type?a.matrix=SceneJS_math_frustumMatrix4(b.left,b.right,b.bottom,b.top,b.near,b.far):"perspective"==b.type&&(a.matrix=SceneJS_math_perspectiveMatrix4(b.fovy*Math.PI/180,b.aspect,b.near,b.far)),a.pan){var c=a.pan,d=SceneJS_math_translationMat4v([c.x||0,c.y||0,c.z||0]);a.matrix=SceneJS_math_mulMat4(d,a.matrix,[])}a.mat?a.mat.set(a.matrix):a.mat=new Float32Array(a.matrix)}var b=SceneJS_math_perspectiveMatrix4(45,1,.1,1e4),c=new Float32Array(b),d={type:"camera",stateId:SceneJS._baseStateId++,matrix:b,mat:c,optics:{type:"perspective",fovy:45,aspect:1,near:.1,far:1e4},checkAspect:function(b,c){b.optics.aspect!=c&&(b.optics.aspect=c,a(this))}},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.projTransform=d,f=0}),SceneJS.Camera=SceneJS_NodeFactory.createNodeType("camera"),SceneJS.Camera.prototype._init=function(b){if(1==this._core.useCount){b.optics=b.optics||{};var c=this.getScene().getCanvas();b.optics.aspect=c.width/c.height,this.setOptics(b.optics),b.pan&&this.setPan(b.pan);var d=this;this._canvasSizeSub=this.getScene().on("canvasSize",function(b){d._core.optics.aspect=b.aspect,a(d._core),d._engine.display.imageDirty=!0})}},SceneJS.Camera.getDefaultMatrix=function(){return c},SceneJS.Camera.prototype.setOptics=function(b){var c=this._core;if(b){var d=b.type||c.optics.type||"perspective";if("ortho"==d)c.optics=SceneJS._applyIf(SceneJS_math_ORTHO_OBJ,{type:d,left:b.left,bottom:b.bottom,near:b.near,right:b.right,top:b.top,far:b.far});else if("frustum"==d)c.optics={type:d,left:b.left||-1,bottom:b.bottom||-1,near:b.near||.1,right:b.right||1,top:b.top||1,far:b.far||1e4};else{if("perspective"!=d)throw b.type?SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not supported - supported types are 'perspective', 'frustum' and 'ortho'"):SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not specified - supported types are 'perspective', 'frustum' and 'ortho'");c.optics={type:d,fovy:b.fovy||60,aspect:void 0==b.aspect?1:b.aspect,near:b.near||.1,far:b.far||1e4}}}else c.optics={type:"perspective",fovy:60,aspect:1,near:.1,far:1e4};this._core.optics.pan=b.pan,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.setPan=function(b){this._core.pan=b,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.getOptics=function(){var a={};for(var b in this._core.optics)this._core.optics.hasOwnProperty(b)&&(a[b]=this._core.optics[b]);return a},SceneJS.Camera.prototype.getMatrix=function(){return this._core.matrix.slice(0)},SceneJS.Camera.prototype._compile=function(a){this._engine.display.projTransform=e[f++]=this._core,this._compileNodes(a),this._engine.display.projTransform=--f>0?e[f-1]:d},SceneJS.Camera.prototype._destroy=function(){this.getScene().off(this._canvasSizeSub)}}(),function(){var a={type:"clips",stateId:SceneJS._baseStateId++,empty:!0,hash:"",clips:[]},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.clips=a,c=0}),SceneJS.Clips=SceneJS_NodeFactory.createNodeType("clips"),SceneJS.Clips.prototype._init=function(a){if(1==this._core.useCount){var b=a.clips;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"clips node attribute missing : 'clips'");this._core.clips=this._core.clips||[];for(var c=0,d=b.length;d>c;c++)this._setClip(c,b[c])}},SceneJS.Clips.prototype.setClips=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.clips.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'clips': index out of range ("+this._core.clips.length+" clips defined)");this._setClip(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Clips.prototype._setClip=function(a,b){var c=this._core.clips[a]||(this._core.clips[a]={});c.normalAndDist=[b.x||0,b.y||0,b.z||0,b.dist||0];var d=b.mode||c.mode||"disabled";if("inside"!=d&&"outside"!=d&&"disabled"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'");c.mode=d,this._core.hash=null},SceneJS.Clips.prototype._compile=function(d){this._core.hash||(this._core.hash=this._core.clips.length),this._engine.display.clips=b[c++]=this._core,this._compileNodes(d),this._engine.display.clips=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"enable",enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.enable=a,c=0}),SceneJS.Enable=SceneJS_NodeFactory.createNodeType("enable"),SceneJS.Enable.prototype._init=function(a){1==this._core.useCount&&(this._core.enabled=!0,void 0!=a.enabled&&this.setEnabled(a.enabled))},SceneJS.Enable.prototype.setEnabled=function(a){return a!==this._core.enabled&&(this._core.enabled=a,this._engine.display.drawListDirty=!0,this.publish("enabled",a)),this},SceneJS.Enable.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Enable.prototype._compile=function(d){this._engine.display.enable=b[c++]=this._core,this._compileNodes(d),this._engine.display.enable=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"flags",picking:!0,clipping:!0,enabled:!0,transparent:!1,backfaces:!0,frontface:"ccw",reflective:!0,solid:!1,hash:"refl;;"},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.flags=a,c=0}),SceneJS.Flags=SceneJS_NodeFactory.createNodeType("flags"),SceneJS.Flags.prototype._init=function(a){1==this._core.useCount&&(this._core.picking=!0,this._core.clipping=!0,this._core.enabled=!0,this._core.transparent=!1,this._core.backfaces=!0,this._core.frontface="ccw",this._core.reflective=!0,this._core.solid=!1,a.flags&&this.setFlags(a.flags))},SceneJS.Flags.prototype.setFlags=function(a){var b=this._core;return void 0!=a.picking&&(b.picking=!!a.picking,this._engine.display.drawListDirty=!0),void 0!=a.clipping&&(b.clipping=!!a.clipping,this._engine.display.imageDirty=!0),void 0!=a.enabled&&(b.enabled=!!a.enabled,this._engine.display.drawListDirty=!0),void 0!=a.transparent&&(b.transparent=!!a.transparent,this._engine.display.stateSortDirty=!0),void 0!=a.backfaces&&(b.backfaces=!!a.backfaces,this._engine.display.imageDirty=!0),void 0!=a.frontface&&(b.frontface=a.frontface,this._engine.display.imageDirty=!0),void 0!=a.reflective&&(b.reflective=a.reflective,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),void 0!=a.solid&&(b.solid=a.solid,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.addFlags=function(a){return this.setFlags(a)},SceneJS.Flags.prototype.getFlags=function(){var a=this._core;return{picking:a.picking,clipping:a.clipping,enabled:a.enabled,transparent:a.transparent,backfaces:a.backfaces,frontface:a.frontface,reflective:a.reflective,solid:a.solid}},SceneJS.Flags.prototype.setPicking=function(a){return a=!!a,this._core.picking!=a&&(this._core.picking=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getPicking=function(){return this._core.picking},SceneJS.Flags.prototype.setClipping=function(a){return a=!!a,this._core.clipping!=a&&(this._core.clipping=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getClipping=function(){return this._core.clipping},SceneJS.Flags.prototype.setEnabled=function(a){return a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Flags.prototype.setTransparent=function(a){return a=!!a,this._core.transparent!=a&&(this._core.transparent=a,this._engine.display.stateOrderDirty=!0),this},SceneJS.Flags.prototype.getTransparent=function(){return this._core.transparent},SceneJS.Flags.prototype.setBackfaces=function(a){return a=!!a,this._core.backfaces!=a&&(this._core.backfaces=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getBackfaces=function(){return this._core.backfaces},SceneJS.Flags.prototype.setFrontface=function(a){return this._core.frontface!=a&&(this._core.frontface=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getFrontface=function(){return this._core.frontface},SceneJS.Flags.prototype.setReflective=function(a){return a=!!a,this._core.reflective!=a&&(this._core.reflective=a,this._core.hash=(a?"refl":"")+this._core.solid?";s":";;",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getReflective=function(){return this._core.reflective},SceneJS.Flags.prototype.setSolid=function(a){return a=!!a,this._core.solid!=a&&(this._core.solid=a,this._core.hash=(this._core.reflective?"refl":"")+a?";s;":";;",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getSolid=function(){return this._core.solid},SceneJS.Flags.prototype._compile=function(d){this._engine.display.flags=b[c++]=this._core,this._compileNodes(d),this._engine.display.flags=--c>0?b[c-1]:a}}(),new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._core.renderBuf.webglRestored()}),SceneJS.ColorTarget=SceneJS_NodeFactory.createNodeType("colorTarget"),SceneJS.ColorTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="color",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.ColorTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.ColorTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._buildNodeCore()}),SceneJS.DepthTarget=SceneJS_NodeFactory.createNodeType("depthTarget"),SceneJS.DepthTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="depth",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.DepthTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.DepthTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a=[],b=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){b=0}),SceneJS.Geometry=SceneJS_NodeFactory.createNodeType("geometry"),SceneJS.Geometry.prototype._init=function(a){if(1==this._core.useCount){this._initNodeCore(a,{origin:a.origin,scale:a.scale,autoNormals:"auto"==a.normals}),this._buildNodeCore(this._engine.canvas.gl,this._core);var b=this;this._core.webglRestored=function(){b._buildNodeCore(b._engine.canvas.gl,b._core)}}},SceneJS.Geometry.prototype._initNodeCore=function(a,b){var c=this;b=b||{};var d=a.primitive||"triangles",e=this._core,f=this._engine.canvas.UINT_INDEX_ENABLED?Uint32Array:Uint16Array;e.primitive=this._getPrimitiveType(d),a.normals&&"triangles"==d&&("auto"===a.normals||a.normals===!0)&&a.positions&&a.indices&&this._buildNormals(a),e.arrays={positions:a.positions?new Float32Array(b.scale||b.origin?this._applyOptions(a.positions,b):a.positions):void 0,normals:a.normals?new Float32Array(a.normals):void 0,uv:a.uv?new Float32Array(a.uv):void 0,uv2:a.uv2?new Float32Array(a.uv2):void 0,colors:a.colors?new Float32Array(a.colors):void 0,indices:a.indices?new f(a.indices):void 0},delete a.positions,delete a.normals,delete a.uv,delete a.uv2,delete a.indices,delete a.colors,e.getTangentBuf=function(){if(e.tangentBuf)return e.tangentBuf;var a=e.arrays;if(a.positions&&a.indices&&a.uv){var b=c._engine.canvas.gl,d=new Float32Array(c._buildTangents(a));e.arrays.tangents=d;var f=b.STATIC_DRAW;return e.tangentBuf=new SceneJS._webgl.ArrayBuffer(b,b.ARRAY_BUFFER,d,d.length,3,f)}}},SceneJS.Geometry.prototype._getPrimitiveType=function(a){var b=this._engine.canvas.gl;switch(a){case"points":return b.POINTS;case"lines":return b.LINES;case"line-loop":return b.LINE_LOOP;case"line-strip":return b.LINE_STRIP;case"triangles":return b.TRIANGLES;case"triangle-strip":return b.TRIANGLE_STRIP;case"triangle-fan":return b.TRIANGLE_FAN;default:throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"geometry primitive unsupported: '"+a+"' - supported types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'")}},SceneJS.Geometry.prototype._applyOptions=function(a,b){var c=a.slice?a.slice(0):new Float32Array(a);if(b.scale)for(var d=void 0!=b.scale.x?b.scale.x:1,e=void 0!=b.scale.y?b.scale.y:1,f=void 0!=b.scale.z?b.scale.z:1,g=0,h=c.length;h>g;g+=3)c[g]*=d,c[g+1]*=e,c[g+2]*=f;if(b.origin)for(var i=void 0!=b.origin.x?b.origin.x:0,j=void 0!=b.origin.y?b.origin.y:0,k=void 0!=b.origin.z?b.origin.z:0,g=0,h=c.length;h>g;g+=3)c[g]-=i,c[g+1]-=j,c[g+2]-=k;return c};var c=function(a){a.vertexBuf&&(a.vertexBuf.destroy(),a.vertexBuf=null),a.normalBuf&&(a.normalBuf.destroy(),a.normalBuf=null),a.uvBuf&&(a.uvBuf.destroy(),a.uvBuf=null),a.uvBuf2&&(a.uvBuf2.destroy(),a.uvBuf2=null),a.colorBuf&&(a.colorBuf.destroy(),a.colorBuf=null),a.tangentBuf&&(a.tangentBuf.destroy(),a.tangentBuf=null),a.indexBuf&&(a.indexBuf.destroy(),a.indexBuf=null),a.interleavedBuf&&(a.interleavedBuf.destroy(),a.interleavedBuf=null)};SceneJS.Geometry.prototype._buildNodeCore=function(a,b){var d=a.STATIC_DRAW;try{var e=b.arrays,f=SceneJS.getConfigs("enableInterleaving")!==!1,g=0,h=0,i=[],j=[],k=function(a,b){return 0==g?g=a.length/b:a.length/b!=g&&(f=!1),i.push(a),j.push(b),h+=b,4*(h-b)};if(e.positions&&(f&&(b.interleavedPositionOffset=k(e.positions,3)),b.vertexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.positions,e.positions.length,3,d)),e.normals&&(f&&(b.interleavedNormalOffset=k(e.normals,3)),b.normalBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.normals,e.normals.length,3,d)),e.uv&&(f&&(b.interleavedUVOffset=k(e.uv,2)),b.uvBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv,e.uv.length,2,d)),e.uv2&&(f&&(b.interleavedUV2Offset=k(e.uv2,2)),b.uvBuf2=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv2,e.uv2.length,2,d)),e.colors&&(f&&(b.interleavedColorOffset=k(e.colors,4)),b.colorBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.colors,e.colors.length,4,d)),e.indices&&(b.indexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ELEMENT_ARRAY_BUFFER,e.indices,e.indices.length,1,d)),h>0&&f){for(var l=[],m=i.length,n=0;g>n;++n)for(var o=0;m>o;++o)for(var p=j[o],q=0;p>q;++q)l.push(i[o][n*p+q]);b.interleavedStride=4*h,b.interleavedBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,new Float32Array(l),l.length,h,d),b.interleavedBuf.dirty=!1}}catch(r){throw c(b),SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate geometry: "+r)}},SceneJS.Geometry.prototype._updateArray=function(a,b,c){var d=a.length,e=b.length;e+c>d&&(e-=e+c-d);for(var f=c,g=0;e>g;f++,g++)a[f]=b[g]},SceneJS.Geometry.prototype._buildNormals=function(a){for(var b,c,d,e,f,g,h=a.positions,i=a.indices,j=new Array(h.length/3),k=0,l=i.length-3;l>k;k+=3){b=i[k+0],c=i[k+1],d=i[k+2],e=[h[3*b+0],h[3*b+1],h[3*b+2]],f=[h[3*c+0],h[3*c+1],h[3*c+2]],g=[h[3*d+0],h[3*d+1],h[3*d+2]],f=SceneJS_math_subVec4(f,e,[0,0,0,0]),g=SceneJS_math_subVec4(g,e,[0,0,0,0]);var m=SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(f,g,[0,0,0,0]),[0,0,0,0]);j[b]||(j[b]=[]),j[c]||(j[c]=[]),j[d]||(j[d]=[]),j[b].push(m),j[c].push(m),j[d].push(m)}for(var n=new Array(h.length),k=0,l=j.length;l>k;k++){for(var o=j[k].length,p=0,q=0,r=0,s=0;o>s;s++)p+=j[k][s][0],q+=j[k][s][1],r+=j[k][s][2];n[3*k+0]=p/o,n[3*k+1]=q/o,n[3*k+2]=r/o}a.normals=n},SceneJS.Geometry.prototype._buildTangents=function(a){for(var b=a.positions,c=a.indices,d=a.uv,e=[],f=0;ft;t++){var u=c[f+t];"undefined"!=typeof e[u]?e[u]=SceneJS_math_addVec3(e[u],s,[]):e[u]=s}}for(var v=[],w=0;wf;f+=3)c=b[f],d=b[f+1],e=b[f+2],cthis._boundary.xmax&&(this._boundary.xmax=c),d>this._boundary.ymax&&(this._boundary.ymax=d),e>this._boundary.zmax&&(this._boundary.zmax=e);return this._boundary},SceneJS.Geometry.prototype._compile=function(c){if(this._core._loading)return void this._compileNodes(c);var d=this._core;d.vertexBuf||(d=this._inheritVBOs(d)),d.indexBuf?(d.hash=[d.normalBuf?"t":"f",d.arrays&&d.arrays.tangents?"t":"f",d.uvBuf?"t":"f",d.uvBuf2?"t":"f",d.colorBuf?"t":"f",d.primitive].join(""),d.stateId=this._core.stateId,d.type="geometry",this._engine.display.geometry=a[b++]=d,SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING,{display:this._engine.display}),this._engine.display.buildObject(this.id)):a[b++]=this._core,this._compileNodes(c),b--},SceneJS.Geometry.prototype._inheritVBOs=function(c){for(var d={primitive:c.primitive,boundary:c.boundary,normalBuf:c.normalBuf,uvBuf:c.uvBuf,uvBuf2:c.uvBuf2,colorBuf:c.colorBuf,interleavedBuf:c.interleavedBuf,indexBuf:c.indexBuf,interleavedStride:c.interleavedStride,interleavedPositionOffset:c.interleavedPositionOffset,interleavedNormalOffset:c.interleavedNormalOffset,interleavedUVOffset:c.interleavedUVOffset,interleavedUV2Offset:c.interleavedUV2Offset,interleavedColorOffset:c.interleavedColorOffset},e=b-1;e>=0;e--)if(a[e].vertexBuf)return d.vertexBuf=a[e].vertexBuf,d.boundary=a[e].boundary,d.normalBuf=a[e].normalBuf,d.uvBuf=a[e].uvBuf,d.uvBuf2=a[e].uvBuf2,d.colorBuf=a[e].colorBuf,d.interleavedBuf=a[e].interleavedBuf,d.interleavedStride=a[e].interleavedStride,d.interleavedPositionOffset=a[e].interleavedPositionOffset,d.interleavedNormalOffset=a[e].interleavedNormalOffset,d.interleavedUVOffset=a[e].interleavedUVOffset,d.interleavedUV2Offset=a[e].interleavedUV2Offset,d.interleavedColorOffset=a[e].interleavedColorOffset,d;return d},SceneJS.Geometry.prototype._destroy=function(){this._engine.display.removeObject(this.id),1==this._core.useCount&&(this._destroyNodeCore(),this._source&&this._source.destroy&&this._source.destroy())},SceneJS.Geometry.prototype._destroyNodeCore=function(){document.getElementById(this._engine.canvas.canvasId)&&c(this._core)}},function(){var a={type:"stage",stateId:SceneJS._baseStateId++,priority:0,pickable:!0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.stage=a,c=0}),SceneJS.Stage=SceneJS_NodeFactory.createNodeType("stage"),SceneJS.Stage.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1,this._core.pickable=!!a.pickable)},SceneJS.Stage.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Stage.prototype.getPriority=function(){return this._core.priority},SceneJS.Stage.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype._compile=function(d){this._engine.display.stage=b[c++]=this._core,this._compileNodes(d),this._engine.display.stage=--c>0?b[c-1]:a}}(),function(){var a={type:"layer",stateId:SceneJS._baseStateId++,priority:0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.layer=a,c=0}),SceneJS.Layer=SceneJS_NodeFactory.createNodeType("layer"),SceneJS.Layer.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1)},SceneJS.Layer.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Layer.prototype.getPriority=function(){return this._core.priority},SceneJS.Layer.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.setClearDepth=function(a){a=a||0,this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Layer.prototype._compile=function(d){this._engine.display.layer=b[c++]=this._core,this._compileNodes(d),this._engine.display.layer=--c>0?b[c-1]:a}}(),SceneJS.Library=SceneJS_NodeFactory.createNodeType("library"),SceneJS.Library.prototype._compile=function(a){},function(){function a(a){if(a.lights&&a.lights.length>0){for(var b,c=a.lights,d=[],e=0,f=c.length;f>e;e++)b=c[e],d.push(b.mode),b.specular&&d.push("s"),b.diffuse&&d.push("d"),d.push("world"==b.space?"w":"v");a.hash=d.join("")}else a.hash=""}var b={type:"lights",stateId:SceneJS._baseStateId++,hash:null,empty:!1,lights:[{mode:"ambient",color:[.7,.7,.8],diffuse:!0,specular:!1},{mode:"dir",color:[1,1,1],diffuse:!0,specular:!0,dir:[-.5,-.5,-1],space:"view"},{mode:"dir",color:[1,1,1],diffuse:!1,specular:!0,dir:[1,-.9,-.7],space:"view"}]};a(b);var c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.lights=b,d=0}),SceneJS.Lights=SceneJS_NodeFactory.createNodeType("lights"),SceneJS.Lights.prototype._init=function(a){if(1==this._core.useCount){var b=a.lights;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"lights node attribute missing : 'lights'");this._core.lights=this._core.lights||[];for(var c=0,d=b.length;d>c;c++)this._initLight(c,b[c])}},SceneJS.Lights.prototype._initLight=function(a,b){var c=[];this._core.lights[a]=c;var d=b.mode||"dir";if("dir"!=d&&"point"!=d&&"ambient"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");var e=b.pos,f=b.dir,g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],c.mode=d,c.diffuse="ambient"==d?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==d?!1:void 0!=b.specular?b.specular:!0,c.pos=b.pos?[e.x||0,e.y||0,e.z||0]:[0,0,0],c.dir=b.dir?[f.x||0,f.y||0,f.z||0]:[0,0,1],c.attenuation=[void 0!=b.constantAttenuation?b.constantAttenuation:0,b.linearAttenuation||0,b.quadraticAttenuation||0];var h=b.space;if(h){if("view"!=h&&"world"!=h)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+h+"' - should be 'view' or 'world'")}else h="world";c.space=h,this._core.hash=null},SceneJS.Lights.prototype.setLights=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.lights.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'lights': index out of range ("+this._core.lights.length+" lights defined)");this._setLight(b,a[c]||{})}this._engine.branchDirty(this)},SceneJS.Lights.prototype._setLight=function(a,b){var c=this._core.lights[a],d=!1,e=!1;if(b.mode&&b.mode!=c.mode){var f=b.mode;if("dir"!=f&&"point"!=f&&"ambient"!=f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");c.mode=f,c.diffuse="ambient"==f?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==f?!1:void 0!=b.specular?b.specular:!0,e=!0}if(b.color){var g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],d=!0}var h=b.pos;h&&(c.pos=[h.x||0,h.y||0,h.z||0],d=!0);var i=b.dir;if(i&&(c.dir=[i.x||0,i.y||0,i.z||0],d=!0),void 0!=b.constantAttenuation&&(c.attenuation[0]=b.constantAttenuation,d=!0),void 0!=b.linearAttenuation&&(c.attenuation[1]=b.linearAttenuation,d=!0),void 0!=b.quadraticAttenuation&&(c.attenuation[2]=b.quadraticAttenuation,d=!0),b.space&&b.space!=c.space){var j=b.space;if("view"!=j&&"world"!=j)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+j+"' - should be 'view' or 'world'");c.space=j,this._core.hash=null,e=!0}void 0!=b.specular&&b.specular!=c.specular&&(c.specular=b.specular,e=!0),void 0!=b.diffuse&&b.diffuse!=c.diffuse&&(c.diffuse=b.diffuse,e=!0),e?this._engine.branchDirty(this):d&&(this._engine.display.imageDirty=!0),this._core.hash=null},SceneJS.Lights.prototype._compile=function(e){this._core.hash||a(this._core),this._engine.display.lights=c[d++]=this._core,this._compileNodes(e),this._engine.display.lights=--d>0?c[d-1]:b}}(),function(){var a=SceneJS_math_lookAtMat4c(0,0,10,0,0,0,0,1,0),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4())),d=new Float32Array(c),e={type:"lookAt",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,lookAt:SceneJS_math_LOOKAT_ARRAYS},f=[],g=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.viewTransform=e,g=0}),SceneJS.Lookat=SceneJS_NodeFactory.createNodeType("lookAt"),SceneJS.Lookat.prototype._init=function(a){if(this._mat=null,this._xf={type:"lookat"},1==this._core.useCount){this._core.eyeX=0,this._core.eyeY=0,this._core.eyeZ=10,this._core.lookX=0,this._core.lookY=0,this._core.lookZ=0,this._core.upX=0,this._core.upY=1,this._core.upZ=0,a.eye||a.look||a.up?(this.setEye(a.eye),this.setLook(a.look),this.setUp(a.up)):(this.setEye({x:0,y:0,z:10}),this.setLook({x:0,y:0,z:0}),this.setUp({x:0,y:1,z:0}));var b=this._core,c=this;this._core.rebuild=function(){b.matrix=SceneJS_math_lookAtMat4c(b.eyeX,b.eyeY,b.eyeZ,b.lookX,b.lookY,b.lookZ,b.upX,b.upY,b.upZ),b.lookAt={eye:[b.eyeX,b.eyeY,b.eyeZ],look:[b.lookX,b.lookY,b.lookZ],up:[b.upX,b.upY,b.upZ]},b.mat?(b.mat.set(b.matrix),b.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))):(b.mat=new Float32Array(b.matrix),b.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))),c.publish("matrix",b.matrix),b.dirty=!1},this._core.dirty=!0,this._tick=this.getScene().on("tick",function(){c._core.dirty&&c._core.rebuild()})}},SceneJS.Lookat.getDefaultMatrix=function(){return b},SceneJS.Lookat.prototype.setEye=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.eyeX=a.x),void 0!=a.y&&null!=a.y&&(this._core.eyeY=a.y),void 0!=a.z&&null!=a.z&&(this._core.eyeZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEye=function(a){return a=a||{},this._core.eyeX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.eyeY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.eyeZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeX=function(a){return this._core.eyeX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0, +this},SceneJS.Lookat.prototype.setEyeY=function(a){return this._core.eyeY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeZ=function(a){return this._core.eyeZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeX=function(a){return this._core.eyeX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeY=function(a){return this._core.eyeY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeZ=function(a){return this._core.eyeZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getEye=function(){return{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ}},SceneJS.Lookat.prototype.setLook=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.lookX=a.x),void 0!=a.y&&null!=a.y&&(this._core.lookY=a.y),void 0!=a.z&&null!=a.z&&(this._core.lookZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLook=function(a){return a=a||{},this._core.lookX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.lookY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.lookZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookX=function(a){return this._core.lookX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookY=function(a){return this._core.lookY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookZ=function(a){return this._core.lookZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookX=function(a){return this._core.lookX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookY=function(a){return this._core.lookY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookZ=function(a){return this._core.lookZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getLook=function(){return{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ}},SceneJS.Lookat.prototype.setUp=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.upX=a.x),void 0!=a.y&&null!=a.y&&(this._core.upY=a.y),void 0!=a.z&&null!=a.z&&(this._core.upZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUp=function(a){return a=a||{},this._core.upX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.upY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.upZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpX=function(a){return this._core.upX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpY=function(a){return this._core.upY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpZ=function(a){return this._core.upZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpX=function(a){return this._core.upX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpY=function(a){return this._core.upY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpZ=function(a){return this._core.upZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getUp=function(){return{x:this._core.upX,y:this._core.upY,z:this._core.upZ}},SceneJS.Lookat.prototype.getMatrix=function(){return this._core.dirty&&this._core.rebuild(),this._core.matrix.slice(0)},SceneJS.Lookat.prototype.getAttributes=function(){return{look:{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ},eye:{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ},up:{x:this._core.upX,y:this._core.upY,z:this._core.upZ}}},SceneJS.Lookat.prototype._compile=function(a){this._engine.display.viewTransform=f[g++]=this._core,this._compileNodes(a),this._engine.display.viewTransform=--g>0?f[g-1]:e},SceneJS.Lookat.prototype._destroy=function(){this.getScene().off(this._tick)}}(),new function(){var a={type:"material",stateId:SceneJS._baseStateId++,baseColor:[1,1,1],specularColor:[1,1,1],specular:1,shine:70,alpha:1,emit:0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.material=a,c=0}),SceneJS.Material=SceneJS_NodeFactory.createNodeType("material"),SceneJS.Material.prototype._init=function(a){1==this._core.useCount&&(this.setBaseColor(a.color||a.baseColor),this.setSpecularColor(a.specularColor),this.setSpecular(a.specular),this.setShine(a.shine),this.setEmit(a.emit),this.setAlpha(a.alpha))},SceneJS.Material.prototype.setBaseColor=function(b){var c=a.baseColor;return this._core.baseColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.baseColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.setColor=SceneJS.Material.prototype.setBaseColor,SceneJS.Material.prototype.getBaseColor=function(){return{r:this._core.baseColor[0],g:this._core.baseColor[1],b:this._core.baseColor[2]}},SceneJS.Material.prototype.getColor=SceneJS.Material.prototype.getBaseColor,SceneJS.Material.prototype.setSpecularColor=function(b){var c=a.specularColor;return this._core.specularColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.specularColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecularColor=function(){return{r:this._core.specularColor[0],g:this._core.specularColor[1],b:this._core.specularColor[2]}},SceneJS.Material.prototype.setSpecular=function(b){return this._core.specular=void 0!=b&&null!=b?b:a.specular,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecular=function(){return this._core.specular},SceneJS.Material.prototype.setShine=function(b){return this._core.shine=void 0!=b&&null!=b?b:a.shine,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getShine=function(){return this._core.shine},SceneJS.Material.prototype.setEmit=function(b){return this._core.emit=void 0!=b&&null!=b?b:a.emit,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getEmit=function(){return this._core.emit},SceneJS.Material.prototype.setAlpha=function(b){return this._core.alpha=void 0!=b&&null!=b?b:a.alpha,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getAlpha=function(){return this._core.alpha},SceneJS.Material.prototype._compile=function(d){this._engine.display.material=b[c++]=this._core,this._compileNodes(d),this._engine.display.material=--c>0?b[c-1]:a}},new function(){var a={type:"morphGeometry",stateId:SceneJS._baseStateId++,hash:"",morph:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.morphGeometry=a,c=0}),SceneJS.MorphGeometry=SceneJS_NodeFactory.createNodeType("morphGeometry"),SceneJS.MorphGeometry.prototype._init=function(a){if(1==this._core.useCount){if(this._sourceConfigs=a.source,this._source=null,a.source){if(!a.source.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry config expected: source.type");var b=this;SceneJS.Plugins.getPlugin("morphGeometry",this._sourceConfigs.type,function(c){if(!c)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: no support for source type '"+b._sourceConfigs.type+"' - need to include plugin for self source type, or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '"+b._sourceConfigs.type+"', ).");if(!c.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)");if(b._source=c.getSource(),!b._source.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'subscribe' method not found on source provided by plugin type '"+a.source.type+"'");var d=!1;b._source.subscribe(function(a){if(d){if(a.targets)for(var c,e,f,g=a.targets,h=b._core.targets,i=0,j=g.length;j>i;i++)c=g[i],e=c.targetIndex,f=h[e],c.positions&&f.vertexBuf&&(f.vertexBuf.bind(),f.vertexBuf.setData(c.positions,0));b._display.imageDirty=!0}else b._buildNodeCore(a),b._core._loading=!1,b._fireEvent("loaded"),b._engine.branchDirty(b),d=!0}),b._core._loading=!0,b._fireEvent("loading"),b._source.configure(b._sourceConfigs)})}else a.create instanceof Function?this._buildNodeCore(a.create()):this._buildNodeCore(a);this._core.webglRestored=function(){},this.setFactor(a.factor)}this._core.factor=a.factor||0,this._core.clamp=!!a.clamp},SceneJS.MorphGeometry.prototype._buildNodeCore=function(a){var b=a.targets||[];if(b.length<2)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node should have at least two targets");var c=a.keys||[];if(c.length!=b.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node mismatch in number of keys and targets");var d=this._core,e=this._engine.canvas.gl,f=e.STATIC_DRAW;d.keys=c,d.targets=[],d.key1=0,d.key2=1;for(var g,h,i,j,k,l=0,m=b.length;m>l;l++)k=b[l],!g&&k.positions&&(g=k.positions),!h&&k.normals&&(h=k.normals),!i&&k.uv&&(i=k.uv),!j&&k.uv2&&(j=k.uv2);try{for(var n,o,l=0,m=b.length;m>l;l++)k=b[l],n={},o=k.positions||g,o&&(n.positions="Float32Array"==typeof o?o:new Float32Array(o),n.vertexBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.positions,o.length,3,f),g=o),o=k.normals||h,o&&(n.normals="Float32Array"==typeof o?o:new Float32Array(o),n.normalBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.normals,o.length,3,f),h=o),o=k.uv||i,o&&(n.uv="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv,o.length,2,f),i=o),o=k.uv2||j,o&&(n.uv2="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf2=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv2,o.length,2,f),j=o),d.targets.push(n)}catch(p){for(var l=0,m=d.targets.length;m>l;l++)n=d.targets[l],n.vertexBuf&&n.vertexBuf.destroy(),n.normalBuf&&n.normalBuf.destroy(),n.uvBuf&&n.uvBuf.destroy(),n.uvBuf2&&n.uvBuf2.destroy();throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate VBO(s) for morphGeometry: "+p)}},SceneJS.MorphGeometry.prototype.setSource=function(a){this._sourceConfigs=a;var b=this._source;b&&b.configure(a)},SceneJS.MorphGeometry.prototype.getSource=function(){return this._sourceConfigs},SceneJS.MorphGeometry.prototype.setFactor=function(a){a=a||0;var b=this._core,c=b.keys,d=b.key1,e=b.key2,f=b.factor;if(ac[c.length-1])d=c.length-2,e=d+1;else{for(;c[d]>a;)d--,e--;for(;c[e]0?b[c-1]:a},SceneJS.MorphGeometry.prototype._makeHash=function(){var a=this._core;if(a.targets.length>0){var b=a.targets[0],c="t",d="f";a.hash=[b.vertexBuf?c:d,b.normalBuf?c:d,b.uvBuf?c:d,b.uvBuf2?c:d].join("")}else a.hash=""},SceneJS.MorphGeometry.prototype._destroy=function(){if(1==this._core.useCount){if(document.getElementById(this._engine.canvas.canvasId))for(var a,b=this._core,c=0,d=b.targets.length;d>c;c++)a=b.targets[c],a.vertexBuf&&a.vertexBuf.destroy(),a.normalBuf&&a.normalBuf.destroy(),a.uvBuf&&a.uvBuf.destroy(),a.uvBuf2&&a.uvBuf2.destroy();this._source&&this._source.destroy&&this._source.destroy()}}},function(){var a={type:"name",stateId:SceneJS._baseStateId++,name:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.name=a,c=0}),SceneJS.Name=SceneJS_NodeFactory.createNodeType("name"),SceneJS.Name.prototype._init=function(a){this.setName(a.name),this._core.nodeId=this.id},SceneJS.Name.prototype.setName=function(a){this._core.name=a||"unnamed",this._engine.branchDirty(this)},SceneJS.Name.prototype.getName=function(){return this._core.name},SceneJS.Name.prototype._compile=function(d){this._engine.display.name=b[c++]=this._core;for(var e,f=[],g=0;c>g;g++)e=b[g].name,e&&f.push(e);this._core.path=f.join("."),this._compileNodes(d),this._engine.display.name=--c>0?b[c-1]:a}}(),new function(){function a(a){var c;if(f>0){c={};for(var d in a)a.hasOwnProperty(d)&&void 0!=a[d]&&(c[d]=g(d))}return b(a.props),{props:a,setProps:function(b){h(b,a)},restoreProps:function(a){c&&i(a,c)}}}function b(a){var b;for(var c in a)a.hasOwnProperty(c)&&(b=a[c],void 0!=b&&null!=b&&(k[c]?a[c]=k[c](null,b):l[c]&&(a[c]=l[c](null,b))))}var c,d={type:"renderer",stateId:SceneJS._baseStateId++,props:null},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){c=a.engine.canvas,f=0,a.engine.display.renderer=e[f++]=d});var g=function(a){for(var b,c,d=f-1;d>=0;d--)if(b=e[d].props,b&&(c=b[a],void 0!=c&&null!=c))return b[a];return null},h=function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=k[c];d&&d(a,b[c])}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor),b.clear&&l.clear(a,b.clear)},i=function(a,b){var c;for(var d in b)if(b.hasOwnProperty(d)&&(c=b[d],void 0!=c&&null!=c)){var e=k[d];e&&e(a,c)}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor)},j=function(a,b){if(!b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Null SceneJS.State node config: "'+b+'"');var c=SceneJS._webgl.enumMap[b];if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Unrecognised SceneJS.State node config value: "'+b+'"');var d=a[c];if(!d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"This browser's WebGL does not support renderer node config value: \""+b+'"');return d},k={enableBlend:function(a,b){return a?void(b?a.enable(a.BLEND):a.disable(a.BLEND)):((null==b||void 0==b)&&(b=!1),b)},blendColor:function(a,b){return a?void a.blendColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},blendEquation:function(a,b){return a?void a.blendEquation(a,j(a,b)):b||"funcAdd"},blendEquationSeparate:function(a,b){return a?void a.blendEquation(j(a,b.rgb),j(a,b.alpha)):(b=b||{},{rgb:b.rgb||"funcAdd",alpha:b.alpha||"funcAdd"})},blendFunc:function(a,b){return a?void a.blendFunc(j(a,b.sfactor||"srcAlpha"),j(a,b.dfactor||"oneMinusSrcAlpha")):(b=b||{},{sfactor:b.sfactor||"srcAlpha",dfactor:b.dfactor||"oneMinusSrcAlpha"})},blendFuncSeparate:function(a,b){return a?void a.blendFuncSeparate(j(a,b.srcRGB||"zero"),j(a,b.dstRGB||"zero"),j(a,b.srcAlpha||"zero"),j(a,b.dstAlpha||"zero")):(b=b||{},{srcRGB:b.srcRGB||"zero",dstRGB:b.dstRGB||"zero",srcAlpha:b.srcAlpha||"zero",dstAlpha:b.dstAlpha||"zero"})},clearColor:function(a,b){return a?void a.clearColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},clearDepth:function(a,b){return a?void a.clearDepth(b):null==b||void 0==b?1:b},clearStencil:function(a,b){return a?void a.clearStencil(b):b||0},colorMask:function(a,b){return a?void a.colorMask(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},enableCullFace:function(a,b){return a?void(b?a.enable(a.CULL_FACE):a.disable(a.CULL_FACE)):b},cullFace:function(a,b){return a?void a.cullFace(j(a,b)):b||"back"},enableDepthTest:function(a,b){return a?void(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST)):((null==b||void 0==b)&&(b=!0),b)},depthFunc:function(a,b){return a?void a.depthFunc(j(a,b)):b||"less"},enableDepthMask:function(a,b){return a?void a.depthMask(b):((null==b||void 0==b)&&(b=!0),b)},depthRange:function(a,b){return a?void a.depthRange(b.zNear,b.zFar):(b=b||{},{zNear:void 0==b.zNear||null==b.zNear?0:b.zNear,zFar:void 0==b.zFar||null==b.zFar?1:b.zFar})},frontFace:function(a,b){return a?void a.frontFace(j(a,b)):b||"ccw"},lineWidth:function(a,b){return a?void a.lineWidth(b):b||1},enableScissorTest:function(a,b){return a?void(b?a.enable(a.SCISSOR_TEST):(b=!1,a.disable(a.SCISSOR_TEST))):b}},l={viewport:function(a,b){return a?void a.viewport(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||1,y:b.y||1,width:b.width||c.canvas.width,height:b.height||c.canvas.height})},scissor:function(a,b){return a?void a.scissor(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||0,y:b.y||0,width:b.width||1,height:b.height||1})},clear:function(a,b){if(!a)return b=b||{};var c;b.color&&(c=a.COLOR_BUFFER_BIT),b.depth&&(c|=a.DEPTH_BUFFER_BIT),b.stencil&&(c|=a.STENCIL_BUFFER_BIT)}};SceneJS.Renderer=SceneJS_NodeFactory.createNodeType("renderer"),SceneJS.Renderer.prototype._init=function(a){if(1==this._core.useCount){for(var b in a)a.hasOwnProperty(b)&&(this._core[b]=a[b]);this._core.dirty=!0}},SceneJS.Renderer.prototype.setViewport=function(a){this._core.viewport=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getViewport=function(){return this._core.viewport?{x:this._core.viewport.x,y:this._core.viewport.y,width:this._core.viewport.width,height:this._core.viewport.height}:void 0},SceneJS.Renderer.prototype.setScissor=function(a){this._core.scissor=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getScissor=function(){return this._core.scissor?{x:this._core.scissor.x,y:this._core.scissor.y,width:this._core.scissor.width,height:this._core.scissor.height}:void 0},SceneJS.Renderer.prototype.setClear=function(a){this._core.clear=a?{r:a.r||0,g:a.g||0,b:a.b||0}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getClear=function(){return this._core.clear?{r:this._core.clear.r,g:this._core.clear.g,b:this._core.clear.b}:null},SceneJS.Renderer.prototype.setEnableBlend=function(a){this._core.enableBlend=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getEnableBlend=function(){return this._core.enableBlend},SceneJS.Renderer.prototype.setBlendColor=function(a){this._core.blendColor=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendColor=function(){return this._core.blendColor?{r:this._core.blendColor.r,g:this._core.blendColor.g,b:this._core.blendColor.b,a:this._core.blendColor.a}:void 0},SceneJS.Renderer.prototype.setBlendEquation=function(a){this._core.blendEquation=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquation=function(){return this._core.blendEquation},SceneJS.Renderer.prototype.setBlendEquationSeparate=function(a){this._core.blendEquationSeparate=a?{rgb:a.rgb||"funcAdd",alpha:a.alpha||"funcAdd"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquationSeparate=function(){return this._core.blendEquationSeparate?{rgb:this._core.rgb,alpha:this._core.alpha}:void 0},SceneJS.Renderer.prototype.setBlendFunc=function(a){this._core.blendFunc=a?{sfactor:a.sfactor||"srcAlpha",dfactor:a.dfactor||"one"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendFunc=function(){return this._core.blendFunc?{sfactor:this._core.sfactor,dfactor:this._core.dfactor}:void 0},SceneJS.Renderer.prototype.setBlendFuncSeparate=function(a){this._core.blendFuncSeparate=a?{srcRGB:a.srcRGB||"zero",dstRGB:a.dstRGB||"zero",srcAlpha:a.srcAlpha||"zero",dstAlpha:a.dstAlpha||"zero"}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getBlendFuncSeparate=function(){return this._core.blendFuncSeparate?{srcRGB:this._core.blendFuncSeparate.srcRGB,dstRGB:this._core.blendFuncSeparate.dstRGB,srcAlpha:this._core.blendFuncSeparate.srcAlpha,dstAlpha:this._core.blendFuncSeparate.dstAlpha}:void 0},SceneJS.Renderer.prototype.setEnableCullFace=function(a){this._core.enableCullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableCullFace=function(){return this._core.enableCullFace},SceneJS.Renderer.prototype.setCullFace=function(a){this._core.cullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getCullFace=function(){return this._core.cullFace},SceneJS.Renderer.prototype.setEnableDepthTest=function(a){this._core.enableDepthTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthTest=function(){return this._core.enableDepthTest},SceneJS.Renderer.prototype.setDepthFunc=function(a){this._core.depthFunc=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthFunc=function(){return this._core.depthFunc},SceneJS.Renderer.prototype.setEnableDepthMask=function(a){this._core.enableDepthMask=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthMask=function(){return this._core.enableDepthMask},SceneJS.Renderer.prototype.setClearDepth=function(a){this._core.clearDepth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Renderer.prototype.setDepthRange=function(a){this._core.depthRange=a?{zNear:void 0==a.zNear||null==a.zNear?0:a.zNear,zFar:void 0==a.zFar||null==a.zFar?1:a.zFar}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthRange=function(){return this._core.depthRange?{zNear:this._core.depthRange.zNear,zFar:this._core.depthRange.zFar}:void 0},SceneJS.Renderer.prototype.setFrontFace=function(a){this._core.frontFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getFrontFace=function(){return this._core.frontFace},SceneJS.Renderer.prototype.setLineWidth=function(a){this._core.lineWidth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Renderer.prototype.setEnableScissorTest=function(a){this._core.enableScissorTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableScissorTest=function(){return this._core.enableScissorTest},SceneJS.Renderer.prototype.setClearStencil=function(a){this._core.clearStencil=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearStencil=function(){return this._core.clearStencil},SceneJS.Renderer.prototype.setColorMask=function(a){this._core.colorMask=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getColorMask=function(){return this._core.colorMask?{r:this._core.colorMask.r,g:this._core.colorMask.g,b:this._core.colorMask.b,a:this._core.colorMask.a}:void 0},SceneJS.Renderer.prototype._compile=function(b){this._core.dirty&&(this._core.props=a(this._core),this._core.dirty=!1),this._engine.display.renderer=e[f++]=this._core,this._compileNodes(b),this._engine.display.renderer=--f>0?e[f-1]:d}},function(){var a={less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL"},b={type:"depthBuffer",stateId:SceneJS._baseStateId++,enabled:!0,clearDepth:1,depthFunc:null,_depthFuncName:"less"},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){null===b.depthFunc&&(b.depthFunc=a.engine.canvas.gl.LESS),a.engine.display.depthBuffer=b,d=0}),SceneJS.DepthBuf=SceneJS_NodeFactory.createNodeType("depthBuffer"),SceneJS.DepthBuf.prototype._init=function(a){void 0!=a.enabled?this.setEnabled(a.enabled):1==this._core.useCount&&this.setEnabled(!0),void 0!=a.clearDepth?this.setClearDepth(a.clearDepth):1==this._core.useCount&&this.setClearDepth(1),void 0!=a.depthFunc?this.setDepthFunc(a.depthFunc):1==this._core.useCount&&this.setDepthFunc("less"),void 0!=a.clear?this.setClear(a.clear):1==this._core.useCount&&this.setClear(!0)},SceneJS.DepthBuf.prototype.setEnabled=function(a){return this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getEnabled=function(){return this._core.enabled},SceneJS.DepthBuf.prototype.setClear=function(a){return this._core.clear!=a&&(this._core.clear=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClear=function(){return this._core.clear},SceneJS.DepthBuf.prototype.setClearDepth=function(a){return this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.DepthBuf.prototype.setDepthFunc=function(b){if(this._core._depthFuncName!=b){var c=a[b];if(void 0==c)throw"unsupported value for 'clearFunc' attribute on depthBuffer node: '"+b+"' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";this._core.depthFunc=this._engine.canvas.gl[c],this._core._depthFuncName=b,this._engine.display.imageDirty=!0}return this},SceneJS.DepthBuf.prototype.getDepthFunc=function(){return this._core._depthFuncName},SceneJS.DepthBuf.prototype._compile=function(a){this._engine.display.depthBuffer=c[d++]=this._core,this._compileNodes(a),this._engine.display.depthBuffer=--d>0?c[d-1]:b}}(),function(){var a={type:"colorBuffer",stateId:SceneJS._baseStateId++,blendEnabled:!1,colorMask:{r:!0,g:!0,b:!0,a:!0}},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.colorBuffer=a,c=0}),SceneJS.ColorBuffer=SceneJS_NodeFactory.createNodeType("colorBuffer"),SceneJS.ColorBuffer.prototype._init=function(a){void 0!=a.blendEnabled?this.setBlendEnabled(a.blendEnabled):1==this._core.useCount&&this.setBlendEnabled(!1),this.setColorMask(a)},SceneJS.ColorBuffer.prototype.setBlendEnabled=function(a){this._core.blendEnabled!=a&&(this._core.blendEnabled=a,this._engine.display.imageDirty=!0),this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getBlendEnabled=function(){return this._core.blendEnabled},SceneJS.ColorBuffer.prototype.setColorMask=function(a){this._core.colorMask={r:void 0!=a.r&&null!=a.r?a.r:!0,g:void 0!=a.g&&null!=a.g?a.g:!0,b:void 0!=a.b&&null!=a.b?a.b:!0,a:void 0!=a.a&&null!=a.a?a.a:!0},this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getColorMask=function(){return this._core.colorMask},SceneJS.ColorBuffer.prototype._compile=function(d){this._engine.display.colorBuffer=b[c++]=this._core,this._compileNodes(d),this._engine.display.colorBuffer=--c>0?b[c-1]:a,this._engine.display.imageDirty=!0}}(),function(){var a={type:"view",stateId:SceneJS._baseStateId++,scissorTestEnabled:!1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.view=a,c=0}),SceneJS.View=SceneJS_NodeFactory.createNodeType("view"),SceneJS.View.prototype._init=function(a){void 0!=a.scissorTestEnabled?this.setScissorTestEnabled(a.scissorTestEnabled):1==this._core.useCount&&this.setScissorTestEnabled(!1)},SceneJS.View.prototype.setScissorTestEnabled=function(a){return this._core.scissorTestEnabled!=a&&(this._core.scissorTestEnabled=a,this._engine.display.imageDirty=!0),this},SceneJS.View.prototype.getScissorTestEnabled=function(){return this._core.scissorTestEnabled},SceneJS.View.prototype._compile=function(d){this._engine.display.view=b[c++]=this._core,this._compileNodes(d),this._engine.display.view=--c>0?b[c-1]:a}}(),SceneJS.Scene=SceneJS_NodeFactory.createNodeType("scene"),SceneJS.Scene.prototype._init=function(a){a.tagMask&&this.setTagMask(a.tagMask),this._tagSelector=null,this.transparent=a.transparent===!0},SceneJS.Scene.prototype.loseWebGLContext=function(){this._engine.loseWebGLContext()},SceneJS.Scene.prototype.getCanvas=function(){return this._engine.canvas.canvas},SceneJS.Scene.prototype.getGL=function(){return this._engine.canvas.gl},SceneJS.Scene.prototype.getZBufferDepth=function(){var a=this._engine.canvas.gl;return a.getParameter(a.DEPTH_BITS)},SceneJS.Scene.prototype.setSSAAMultiplier=function(a){return this._engine.canvas.setSSAAMultiplier(a)},SceneJS.Scene.prototype.setTagMask=function(a){a=a||"XXXXXXXXXXXXXXXXXXXXXXXXXX",this._tagSelector||(this._tagSelector={}),this._tagSelector.mask=a,this._tagSelector.regex=a?new RegExp(a):null,this._engine.display.selectTags(this._tagSelector)},SceneJS.Scene.prototype.getTagMask=function(){return this._tagSelector?this._tagSelector.mask:null},SceneJS.Scene.prototype.setNumPasses=function(a){this._engine.setNumPasses(a)},SceneJS.Scene.prototype.renderFrame=function(a){return this._engine.renderFrame(a)},SceneJS.Scene.prototype.needFrame=function(){this._engine.display.imageDirty=!0},SceneJS.Scene.prototype.start=function(a){this._engine.start(a)},SceneJS.Scene.prototype.setFPS=function(a){this._engine.fps=a},SceneJS.Scene.prototype.pause=function(a){this._engine.pause(a)},SceneJS.Scene.prototype.isRunning=function(){return this._engine.running},SceneJS.Scene.prototype.pick=function(a,b,c){var d=this._engine.pick(a,b,c);return this.renderFrame({force:!0}),d?(this.publish("pick",d),d):void this.publish("nopick")},SceneJS.Scene.prototype.readPixels=function(a,b){return this._engine.readPixels(a,b)},SceneJS.Scene.prototype._destroy=function(){this.destroyed||(delete SceneJS._engines[this.id],SceneJS._engineIds.removeItem(this.id),this.destroyed=!0)},SceneJS.Scene.prototype.isActive=function(){return!this._engine.destroyed},SceneJS.Scene.prototype.stop=function(){this._engine.stop()},SceneJS.Scene.prototype.containsNode=function(a){return!!this._engine.findNode(a)},SceneJS.Scene.prototype.findNodes=function(a){return this._engine.findNodes(a)},SceneJS.Scene.prototype.findNode=function(a,b){return this.getNode(a,b)},SceneJS.Scene.prototype.getNode=function(a,b){var c=this._engine.findNode(a);return c?(b&&b(c),c):b?void this.once("nodes/"+a,b):null},SceneJS.Scene.prototype.hasCore=function(a,b){return this._engine.hasCore(a,b)},SceneJS.Scene.prototype.getStatus=function(){var a=SceneJS_sceneStatusModule.sceneStatus[this.id];return a?SceneJS._shallowClone(a):{destroyed:!0}},new function(){function a(a){for(var b,c,d={},e=0;i>e;e++){b=a[e];for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c])}return d}var b={type:"shader",stateId:SceneJS._baseStateId++,hash:"",empty:!0,shader:{}},c=[],d=[],e=[],f=[],g=[],h=[],i=0,j=!0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.shader=b,i=0,j=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(k){if(j){if(i>0){var l={type:"shader",stateId:c[i-1],hash:c.slice(0,i).join("."),shaders:{fragment:{code:f.slice(0,i).join(""),hooks:a(g)},vertex:{code:d.slice(0,i).join(""),hooks:a(e)}},paramsStack:h.slice(0,i)};k.display.shader=l}else k.display.shader=b;j=!1}}),SceneJS.Shader=SceneJS_NodeFactory.createNodeType("shader"),SceneJS.Shader.prototype._init=function(a){1==this._core.useCount&&(this._setShaders(a.shaders),this.setParams(a.params))},SceneJS.Shader.prototype._setShaders=function(a){a=a||[],this._core.shaders={};for(var b,c=0,d=a.length;d>c;c++){if(b=a[c],!b.stage)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"shader 'stage' attribute expected");var e;b.code&&(e=SceneJS._isArray(b.code)?b.code.join(""):b.code),this._core.shaders[b.stage]={code:e,hooks:b.hooks}}},SceneJS.Shader.prototype.setParams=function(a){a=a||{};var b=this._core.params;b||(b=this._core.params={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.Shader.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.Shader.prototype._compile=function(a){ +c[i]=this._core.coreId;var b=this._core.shaders,k=b.fragment||{},l=b.vertex||{};f[i]=k.code||"",g[i]=k.hooks||{},d[i]=l.code||"",e[i]=l.hooks||{},h[i]=this._core.params||{},i++,j=!0,this._compileNodes(a),i--,j=!0}},new function(){var a,b={type:"shaderParams",stateId:SceneJS._baseStateId++,empty:!0},c=[],d=[],e=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(c){c.engine.display.shaderParams=b,e=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(e>0){var g={type:"shaderParams",stateId:c[e-1],paramsStack:d.slice(0,e)};f.display.shaderParams=g}else f.display.shaderParams=b;a=!1}}),SceneJS.ShaderParams=SceneJS_NodeFactory.createNodeType("shaderParams"),SceneJS.ShaderParams.prototype._init=function(a){1==this._core.useCount&&this.setParams(a.params)},SceneJS.ShaderParams.prototype.setParams=function(a){a=a||{};var b=this._core;b.params||(b.params={});for(var c in a)a.hasOwnProperty(c)&&(b.params[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.ShaderParams.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.ShaderParams.prototype._compile=function(b){c[e]=this._core.coreId,d[e]=this._core.params,e++,a=!0,this._compileNodes(b),e--,a=!0}},function(){var a={type:"style",stateId:SceneJS._baseStateId++,lineWidth:1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.style=a,c=0}),SceneJS.Style=SceneJS_NodeFactory.createNodeType("style"),SceneJS.Style.prototype._init=function(a){void 0!=a.lineWidth&&this.setLineWidth(a.lineWidth)},SceneJS.Style.prototype.setLineWidth=function(a){return this._core.lineWidth!=a&&(this._core.lineWidth=a,this._engine.display.imageDirty=!0),this},SceneJS.Style.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Style.prototype._compile=function(d){this._engine.display.style=b[c++]=this._core,this._compileNodes(d),this._engine.display.style=--c>0?b[c-1]:a}}(),function(){var a={type:"tag",stateId:SceneJS._baseStateId++,tag:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.tag=a,c=0}),SceneJS.Tag=SceneJS_NodeFactory.createNodeType("tag"),SceneJS.Tag.prototype._init=function(a){if(1==this._core.useCount){if(!a.tag)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"tag node attribute missing : 'tag'");this.setTag(a.tag)}},SceneJS.Tag.prototype.setTag=function(a){var b=this._core;b.tag=a,b.pattern=null,b.matched=!1,this._engine.display.drawListDirty=!0},SceneJS.Tag.prototype.getTag=function(){return this._core.tag},SceneJS.Tag.prototype._compile=function(d){this._engine.display.tag=b[c++]=this._core,this._compileNodes(d),this._engine.display.tag=--c>0?b[c-1]:a}}(),new function(){var a={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.texture=a,c=0}),SceneJS.Texture=SceneJS_NodeFactory.createNodeType("_texture"),SceneJS.Texture.prototype._init=function(a){if(1==this._core.useCount){this._core.layers=[],this._core.params={};var b=void 0==a.waitForLoad?!0:a.waitForLoad;if(!a.layers)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers missing");if(!SceneJS._isArray(a.layers))throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers should be an array");for(var c,d=this._engine.canvas.gl,e=0;ec;c++)h._loadLayerTexture(b,a[c])}}},SceneJS.Texture.prototype._loadLayerTexture=function(a,b){var c=this,d=b.source;if(d){if(!d.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"texture layer config expected: source.type");SceneJS.Plugins.getPlugin("texture",d.type,function(e){if(!e.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'getSource' method missing on plugin for texture source type '"+d.type+"'.");var f=e.getSource({gl:a});if(!f.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'subscribe' method missing on plugin for texture source type '"+d.type+"'");var g=SceneJS_sceneStatusModule.taskStarted(c,"Loading texture");f.subscribe(function(){var d=!1;return function(e){d?c._engine.display.imageDirty=!0:(d=!0,c._setLayerTexture(a,b,e),SceneJS_sceneStatusModule.taskFinished(g))}}()),f.configure&&f.configure(d),b._source=f})}else{var e=b.uri||b.src,f=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),g=new Image;g.onload=function(){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);var e=SceneJS_configsModule.configs.maxTextureSize;e&&(g=SceneJS._webgl.clampImageSize(g,e)),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c._ensureImageSizePowerOfTwo(g)),c._setLayerTexture(a,b,d),SceneJS_sceneStatusModule.taskFinished(f),c._engine.display.imageDirty=!0},g.onerror=function(){SceneJS_sceneStatusModule.taskFailed(f)},0==e.indexOf("data")?g.src=e:(g.crossOrigin="Anonymous",g.src=e)}},SceneJS.Texture.prototype._ensureImageSizePowerOfTwo=function(a){if(!this._isPowerOfTwo(a.width)||!this._isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=this._nextHighestPowerOfTwo(a.width),b.height=this._nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b,a.crossOrigin=""}return a},SceneJS.Texture.prototype._isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS.Texture.prototype._nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS.Texture.prototype._setLayerTexture=function(a,b,c){b.texture=new SceneJS._webgl.Texture2D(a,{texture:c,minFilter:this._getGLOption("minFilter",a,b,a.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",a,b,a.LINEAR),wrapS:this._getGLOption("wrapS",a,b,a.REPEAT),wrapT:this._getGLOption("wrapT",a,b,a.REPEAT),isDepth:this._getOption(b.isDepth,!1),depthMode:this._getGLOption("depthMode",a,b,a.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",a,b,a.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",a,b,a.LEQUAL),flipY:this._getOption(b.flipY,!0),width:this._getOption(b.width,1),height:this._getOption(b.height,1),internalFormat:this._getGLOption("internalFormat",a,b,a.LEQUAL),sourceFormat:this._getGLOption("sourceType",a,b,a.ALPHA),sourceType:this._getGLOption("sourceType",a,b,a.UNSIGNED_BYTE),update:null}),this.destroyed&&b.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._getGLOption=function(a,b,c,d){var e=c[a];if(void 0==e)return d;var f=SceneJS._webgl.enumMap[e];if(void 0==f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+e+"'");var g=b[f];return g},SceneJS.Texture.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.Texture.prototype.setLayer=function(a){if(void 0==a.index||null==a.index)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index null or undefined");if(a.index<0||a.index>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(parseInt(a.index),a),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype.setLayers=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._setLayer=function(a,b){b=b||{};var c=this._core.layers[a];if(void 0!=b.blendFactor&&null!=b.blendFactor&&(c.blendFactor=b.blendFactor),b.source){var d=c._source;d&&d.configure&&d.configure(b.source)}(b.translate||b.rotate||b.scale)&&this._setLayerTransform(b,c)},SceneJS.Texture.prototype._setLayerTransform=function(a,b){var c,d;if(a.translate){var e=a.translate;void 0!=e.x&&(b.translate.x=e.x),void 0!=e.y&&(b.translate.y=e.y),c=SceneJS_math_translationMat4v([e.x||0,e.y||0,0])}if(a.scale){var f=a.scale;void 0!=f.x&&(b.scale.x=f.x),void 0!=f.y&&(b.scale.y=f.y),d=SceneJS_math_scalingMat4v([f.x||1,f.y||1,1]),c=c?SceneJS_math_mulMat4(c,d):d}if(a.rotate){var g=a.rotate;void 0!=g.z&&(b.rotate.z=g.z||0),d=SceneJS_math_rotationMat4v(.0174532925*g.z,[0,0,1]),c=c?SceneJS_math_mulMat4(c,d):d}c&&(b.matrix=c,b.matrixAsArray?b.matrixAsArray.set(b.matrix):b.matrixAsArray=new Float32Array(b.matrix),b.matrixAsArray=new Float32Array(b.matrix))},SceneJS.Texture.prototype._compile=function(d){this._core.hash||this._makeHash(),this._engine.display.texture=b[c++]=this._core,this._compileNodes(d),this._engine.display.texture=--c>0?b[c-1]:a},SceneJS.Texture.prototype._makeHash=function(){var a,b=this._core;if(b.layers&&b.layers.length>0){for(var c,d=b.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");a=e.join("")}else a="";b.hash!=a&&(b.hash=a)},SceneJS.Texture.prototype._destroy=function(){if(1==this._core.useCount)for(var a,b,c=this._core.layers,d=0,e=c.length;e>d;d++)a=c[d],a.texture&&a.texture.destroy(),b=a._source,b&&b.destroy&&b.destroy()}},new function(){function a(){var a,b;(0!=this.translate.x||0!=this.translate.y)&&(a=SceneJS_math_translationMat4v([this.translate.x||0,this.translate.y||0,0])),(1!=this.scale.x||1!=this.scale.y)&&(b=SceneJS_math_scalingMat4v([this.scale.x||1,this.scale.y||1,1]),a=a?SceneJS_math_mulMat4(a,b):b),0!=this.rotate&&(b=SceneJS_math_rotationMat4v(.0174532925*this.rotate,[0,0,1]),a=a?SceneJS_math_mulMat4(a,b):b),a&&(this.matrix=a,this.matrixAsArray?this.matrixAsArray.set(this.matrix):this.matrixAsArray=new Float32Array(this.matrix)),this._matrixDirty=!1}var b={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.texture=b,d=0});var c=[],d=0;SceneJS.TextureMap=SceneJS_NodeFactory.createNodeType("texture"),SceneJS.TextureMap.prototype._init=function(b){var c=this;if(1==this._core.useCount){if(b.applyFrom&&"uv"!=b.applyFrom&&"uv2"!=b.applyFrom&&"normal"!=b.applyFrom&&"geometry"!=b.applyFrom)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyFrom value is unsupported - should be either 'uv', 'uv2', 'normal' or 'geometry'");if(b.applyTo&&"baseColor"!=b.applyTo&&"color"!=b.applyTo&&"specular"!=b.applyTo&&"emit"!=b.applyTo&&"alpha"!=b.applyTo&&"normals"!=b.applyTo&&"shine"!=b.applyTo)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyTo value is unsupported - should be either 'color', 'baseColor', 'specular' or 'normals'");if(b.blendMode&&"add"!=b.blendMode&&"multiply"!=b.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layer blendMode value is unsupported - should be either 'add' or 'multiply'");"color"==b.applyTo&&(b.applyTo="baseColor"),SceneJS._apply({waitForLoad:void 0==b.waitForLoad?!0:b.waitForLoad,texture:null,applyFrom:b.applyFrom?b.applyFrom:"uv",applyTo:b.applyTo?b.applyTo:"baseColor",blendMode:b.blendMode?b.blendMode:"multiply",blendFactor:void 0!=b.blendFactor&&null!=b.blendFactor?b.blendFactor:1,translate:b.translate?SceneJS._apply(b.translate,{x:0,y:0}):{x:0,y:0},scale:b.scale?SceneJS._apply(b.scale,{x:1,y:1}):{x:1,y:1},rotate:b.rotate||0,matrix:null,_matrixDirty:!0,buildMatrix:a},this._core),a.call(this._core),b.src?(this._core.src=b.src,this._loadTexture(b.src)):b.image?(this._core.image=b.image,this._initTexture(b.image)):b.target&&this.getScene().getNode(b.target,function(a){c.setTarget(a)}),this._core.webglRestored=function(){c._core.image?c._initTexture(c._core.image):c._core.src?c._loadTexture(c._core.src):c._core.target}}},SceneJS.TextureMap.prototype._loadTexture=function(a){var b=this,c=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),d=new Image;d.onload=function(){b._initTexture(d),SceneJS_sceneStatusModule.taskFinished(c),b._engine.display.imageDirty=!0},d.onerror=function(){SceneJS_sceneStatusModule.taskFailed(c)},0==a.indexOf("data")?d.src=a:(d.crossOrigin="Anonymous",d.src=a)},SceneJS.TextureMap.prototype._initTexture=function(a){var b=this._engine.canvas.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);var d=SceneJS_configsModule.configs.maxTextureSize;d&&(a=SceneJS._webgl.clampImageSize(a,d)),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(a)),this._core.image=a,this._core.texture=new SceneJS._webgl.Texture2D(b,{texture:c,minFilter:this._getGLOption("minFilter",b.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",b.LINEAR),wrapS:this._getGLOption("wrapS",b.REPEAT),wrapT:this._getGLOption("wrapT",b.REPEAT),isDepth:this._getOption(this._core.isDepth,!1),depthMode:this._getGLOption("depthMode",b.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",b.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",b.LEQUAL),flipY:this._getOption(this._core.flipY,!0),width:this._getOption(this._core.width,1),height:this._getOption(this._core.height,1),internalFormat:this._getGLOption("internalFormat",b.ALPHA),sourceFormat:this._getGLOption("sourceFormat",b.ALPHA),sourceType:this._getGLOption("sourceType",b.UNSIGNED_BYTE),update:null}),this.destroyed&&this._core.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype._getGLOption=function(a,b){var c=this._engine.canvas.gl,d=this._core[a];if(void 0==d)return b;var e=SceneJS._webgl.enumMap[d];if(void 0==e)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+d+"'");return c[e]},SceneJS.TextureMap.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.TextureMap.prototype.setSrc=function(a){this._core.image=null,this._core.src=a,this._core.target=null,this._loadTexture(a)},SceneJS.TextureMap.prototype.setImage=function(a){this._core.image=a,this._core.src=null,this._core.target=null,this._initTexture(a)},SceneJS.TextureMap.prototype.setTarget=function(a){return"colorTarget"!=a.type&&"depthTarget"!=a.type?void console.log("Target node type not compatible: "+a.type):(delete this._core.src,this._core.target=a,this._core.src=null,this._core.image=null,this._core.texture=a._core.renderBuf.getTexture(),this._core.texture.bufType=a._core.bufType,void(this._engine.display.imageDirty=!0))},SceneJS.TextureMap.prototype.setBlendFactor=function(a){this._core.blendFactor=a,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getBlendFactor=function(){return this._core.blendFactor},SceneJS.TextureMap.prototype.setTranslate=function(a){this._core.translate||(this._core.translate={x:0,y:0}),this._core.translate.x=a.x,this._core.translate.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getTranslate=function(){return this._core.translate},SceneJS.TextureMap.prototype.setScale=function(a){this._core.scale||(this._core.scale={x:0,y:0}),this._core.scale.x=a.x,this._core.scale.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getScale=function(){return this._core.scale},SceneJS.TextureMap.prototype.setRotate=function(a){this._core.rotate=a,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getRotate=function(){return this._core.rotate},SceneJS.TextureMap.prototype.getMatrix=function(){return this._core._matrixDirty&&this._core.buildMatrix.call(this.core)(),this.core.matrix},SceneJS.TextureMap.prototype._compile=function(a){this.__core||(this.__core=this._engine._coreFactory.getCore("texture"));var e=this._engine.display.texture;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),c[d++]=this.__core,this._engine.display.texture=this.__core,this._compileNodes(a),this._engine.display.texture=--d>0?c[d-1]:b},SceneJS.TextureMap.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.TextureMap.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&!this._core.target&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}},function(){var a={type:"cubemap",stateId:SceneJS._baseStateId++,empty:!0,texture:null,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.cubemap=a,c=0}),SceneJS.Reflect=SceneJS_NodeFactory.createNodeType("reflect"),SceneJS.Reflect.prototype._init=function(a){if(1==this._core.useCount){if(this._core.hash="y",a.blendMode&&"add"!=a.blendMode&&"multiply"!=a.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"reflection blendMode value is unsupported - should be either 'add' or 'multiply'");this._core.blendMode=a.blendMode||"multiply",this._core.intensity=void 0!=a.intensity&&null!=a.intensity?a.intensity:1,this._core.applyTo="reflect";for(var b=this,c=this._engine.canvas.gl,d=c.createTexture(),e=[c.TEXTURE_CUBE_MAP_POSITIVE_X,c.TEXTURE_CUBE_MAP_NEGATIVE_X,c.TEXTURE_CUBE_MAP_POSITIVE_Y,c.TEXTURE_CUBE_MAP_NEGATIVE_Y,c.TEXTURE_CUBE_MAP_POSITIVE_Z,c.TEXTURE_CUBE_MAP_NEGATIVE_Z],f=[],g=SceneJS_sceneStatusModule.taskStarted(this,"Loading reflection texture"),h=!1,i=0;ii;i++)c.texImage2D(e[i],0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(f[i]));b._core.texture=new SceneJS._webgl.Texture2D(c,{texture:d,target:c.TEXTURE_CUBE_MAP,minFilter:c.LINEAR,magFilter:c.LINEAR,wrapS:c.CLAMP_TO_EDGE,wrapT:c.CLAMP_TO_EDGE}),SceneJS_sceneStatusModule.taskFinished(g),b._engine.display.imageDirty=!0}}}(),j.onerror=function(){h=!0,SceneJS_sceneStatusModule.taskFailed(g)},j.src=a.src[i]}}},SceneJS.Reflect.prototype._compile=function(d){this.__core||(this.__core=this._engine._coreFactory.getCore("cubemap"));var e=this._engine.display.cubemap;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),b[c++]=this.__core,this._engine.display.cubemap=this.__core,this._compileNodes(d),this._engine.display.cubemap=--c>0?b[c-1]:a},SceneJS.Reflect.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode);b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.Reflect.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}}(),SceneJS.XForm=SceneJS_NodeFactory.createNodeType("xform"),SceneJS.XForm.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.XForm.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.XForm.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.XForm.prototype.setElements=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.XForm elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.XForm.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Matrix=SceneJS_NodeFactory.createNodeType("matrix"),SceneJS.Matrix.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.Matrix.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Matrix.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Matrix.prototype.setMatrix=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Matrix elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Matrix.prototype.setElements=SceneJS.Matrix.prototype.setMatrix,SceneJS.Matrix.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Rotate=SceneJS_NodeFactory.createNodeType("rotate"),SceneJS.Rotate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setAngle(a.angle),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_rotationMat4v(b.angle*Math.PI/180,[b.x,b.y,b.z])}}},SceneJS.Rotate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Rotate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Rotate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for rotate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.setAngle=function(a){this._core.angle=a||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getAngle=function(){return this._core.angle},SceneJS.Rotate.prototype.setXYZ=function(a){a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Rotate.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getX=function(){return this._core.x},SceneJS.Rotate.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getY=function(){return this._core.y},SceneJS.Rotate.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getZ=function(){return this._core.z},SceneJS.Rotate.prototype.incAngle=function(a){this._core.angle+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Translate=SceneJS_NodeFactory.createNodeType("translate"),SceneJS.Translate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_translationMat4v([b.x,b.y,b.z],b.matrix)}}},SceneJS.Translate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Translate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Translate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for translate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Translate.prototype.setXYZ=function(a){return a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Translate.prototype.setX=function(a){return this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setY=function(a){return this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setZ=function(a){return this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incX=function(a){return this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incY=function(a){return this._core.y+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incZ=function(a){return this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getX=function(){return this._core.x},SceneJS.Translate.prototype.getY=function(){return this._core.y},SceneJS.Translate.prototype.getZ=function(){return this._core.z},SceneJS.Translate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Scale=SceneJS_NodeFactory.createNodeType("scale"),SceneJS.Scale.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_scalingMat4v([b.x,b.y,b.z])}}},SceneJS.Scale.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Scale.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Scale.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for scale node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setXYZ=function(a){a=a||{},this._core.x=void 0==a.x?1:a.x,this._core.y=void 0==a.y?1:a.y,this._core.z=void 0==a.z?1:a.z,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Scale.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getX=function(){return this._core.x},SceneJS.Scale.prototype.getY=function(){return this._core.y},SceneJS.Scale.prototype.getZ=function(){return this._core.z},SceneJS.Scale.prototype.incX=function(a){this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.incY=function(a){this._core.y+=a,this._core.matrixDirty=!0},SceneJS.Scale.prototype.incZ=function(a){this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()};var SceneJS_modelXFormStack=new function(){var a=SceneJS_math_identityMat4(),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(SceneJS_math_identityMat4(),SceneJS_math_mat4())),d=new Float32Array(c),e={type:"xform",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,parent:null,cores:[],numCores:0,dirty:!1,matrixDirty:!1},f=[],g=0;this.top=e;var h,i=this;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){g=0,i.top=e,h=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(a){h&&(g>0?a.display.modelTransform=f[g-1]:a.display.modelTransform=e,h=!1)}),this.buildCore=function(a){function b(a){a.dirty=!0,a.matrixDirty=!0;for(var c=0,d=a.numCores;d>c;c++)b(a.cores[c])}a.parent=null,a.cores=[],a.numCores=0,a.matrixDirty=!1,a.matrix=SceneJS_math_identityMat4(),a.mat=new Float32Array(a.matrix),a.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(a.matrix,SceneJS_math_mat4()))),a.dirty=!1,a.setDirty=function(){a.matrixDirty=!0,a.dirty,b(a)},a.build=function(){a.matrixDirty&&(a.buildMatrix&&a.buildMatrix(),a.matrixDirty=!1);var b,c=a.parent;if(c)for(b=a.matrix.slice(0);c;)c.matrixDirty&&(c.buildMatrix&&c.buildMatrix(),c.mat.set(c.matrix),c.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(c.matrix,SceneJS_math_mat4()))),c.matrixDirty=!1),SceneJS_math_mulMat4(c.matrix,b,b),!c.dirty,c=c.parent;else b=a.matrix;a.mat.set(b),a.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4()))),a.dirty=!1}},this.push=function(a){f[g++]=a,a.parent=this.top,a.dirty=!0,this.top&&(this.top.cores[this.top.numCores++]=a),a.numCores=0,this.top=a,h=!0},this.pop=function(){this.top=--g>0?f[g-1]:e,h=!0}};SceneJS.Types=new function(){this.addType=function(a,b){SceneJS_NodeFactory.createNodeType(a,b,function(a){var c;for(var d in b)if(b.hasOwnProperty(d))switch(c=b[d],d){case"init":case"construct":!function(){var c=b[d];a.prototype._init=function(a){c.call(this,a)},a.prototype._fromPlugin=!0}();break;case"destroy":case"destruct":a.prototype._destroy=c;break;default:a.prototype[d]=c}})},this.hasType=function(a){return!!SceneJS_NodeFactory.nodeTypes[a]}};var SceneJS_Display=function(a){this._canvas=a.canvas, +this._programFactory=new SceneJS_ProgramFactory({canvas:a.canvas}),this._chunkFactory=new SceneJS_ChunkFactory,this.transparent=a.transparent===!0,this.enable=null,this.flags=null,this.layer=null,this.stage=null,this.renderer=null,this.depthBuffer=null,this.colorBuffer=null,this.view=null,this.lights=null,this.material=null,this.texture=null,this.cubemap=null,this.modelTransform=null,this.viewTransform=null,this.projTransform=null,this.renderTarget=null,this.clips=null,this.morphGeometry=null,this.name=null,this.tag=null,this.renderListeners=null,this.shader=null,this.shaderParams=null,this.style=null,this.geometry=null,this._objectFactory=new SceneJS_ObjectFactory,this._objects={},this._ambientColor=[0,0,0,1],this._objectList=[],this._objectListLen=0,this._drawList=[],this._drawListLen=0,this._pickDrawList=[],this._pickDrawListLen=0,this._targetList=[],this._targetListLen=0,this._frameCtx={pickNames:[],canvas:this._canvas,VAO:null},this._frameCtx.renderListenerCtx=new SceneJS.RenderContext(this._frameCtx),this.objectListDirty=!0,this.stateOrderDirty=!0,this.stateSortDirty=!0,this.drawListDirty=!0,this.imageDirty=!0,this.pickBufDirty=!0,this.rayPickBufDirty=!0};SceneJS_Display.prototype.webglRestored=function(){this._programFactory.webglRestored(),this._chunkFactory.webglRestored();var a=this._canvas.gl;this.pickBuf&&this.pickBuf.webglRestored(a),this.rayPickBuf&&this.rayPickBuf.webglRestored(a),this.imageDirty=!0},SceneJS_Display.prototype.buildObject=function(a){var b=this._objects[a];b||(b=this._objects[a]=this._objectFactory.getObject(a),this.objectListDirty=!0),b.stage=this.stage,b.layer=this.layer,b.renderTarget=this.renderTarget,b.texture=this.texture,b.cubemap=this.cubemap,b.geometry=this.geometry,b.enable=this.enable,b.flags=this.flags,b.tag=this.tag;var c=[this.geometry.hash,this.shader.hash,this.clips.hash,this.morphGeometry.hash,this.texture.hash,this.cubemap.hash,this.lights.hash,this.flags.hash].join(";");b.program&&c==b.hash||(b.program&&this._programFactory.putProgram(b.program),b.program=this._programFactory.getProgram(c,this),b.hash=c),this._setChunk(b,0,"program"),this._setChunk(b,1,"xform",this.modelTransform),this._setChunk(b,2,"lookAt",this.viewTransform),this._setChunk(b,3,"camera",this.projTransform),this._setChunk(b,4,"flags",this.flags),this._setChunk(b,5,"shader",this.shader),this._setChunk(b,6,"shaderParams",this.shaderParams),this._setChunk(b,7,"style",this.style),this._setChunk(b,8,"depthBuffer",this.depthBuffer),this._setChunk(b,9,"colorBuffer",this.colorBuffer),this._setChunk(b,10,"view",this.view),this._setChunk(b,11,"name",this.name),this._setChunk(b,12,"lights",this.lights),this._setChunk(b,13,"material",this.material),this._setChunk(b,14,"texture",this.texture),this._setChunk(b,15,"cubemap",this.cubemap),this._setChunk(b,16,"clips",this.clips),this._setChunk(b,17,"renderer",this.renderer),this._setChunk(b,18,"geometry",this.morphGeometry,this.geometry),this._setChunk(b,19,"listeners",this.renderListeners),this._setChunk(b,20,"draw",this.geometry)},SceneJS_Display.prototype._setChunk=function(a,b,c,d,e){var f,g=this._chunkFactory.chunkTypes[c];if(d){if(d.empty){var h=a.chunks[b];return h&&this._chunkFactory.putChunk(h),void(a.chunks[b]=null)}f=g.prototype.programGlobal?"_"+d.stateId:"p"+a.program.id+"_"+d.stateId,e&&(f+="__"+e.stateId)}else f="p"+a.program.id;f=b+"__"+f;var h=a.chunks[b];if(h){if(h.id==f)return;this._chunkFactory.putChunk(h)}a.chunks[b]=this._chunkFactory.getChunk(f,c,a.program,d,e),"lights"==c&&this._setAmbient(d)},SceneJS_Display.prototype._setAmbient=function(a){for(var b,c=a.lights,d=0,e=c.length;e>d;d++)b=c[d],"ambient"==b.mode&&(this._ambientColor[0]=b.color[0],this._ambientColor[1]=b.color[1],this._ambientColor[2]=b.color[2])},SceneJS_Display.prototype.removeObject=function(a){var b=this._objects[a];b&&(this._programFactory.putProgram(b.program),b.program=null,b.hash=null,this._objectFactory.putObject(b),delete this._objects[a],this.objectListDirty=!0)},SceneJS_Display.prototype.selectTags=function(a){this._tagSelector=a,this.drawListDirty=!0},SceneJS_Display.prototype.render=function(a){a=a||{},this.objectListDirty&&(this._buildObjectList(),this.objectListDirty=!1,this.stateOrderDirty=!0),this.stateOrderDirty&&(this._makeStateSortKeys(),this.stateOrderDirty=!1,this.stateSortDirty=!0),this.stateSortDirty&&(this._stateSort(),this.stateSortDirty=!1,this.drawListDirty=!0),this.drawListDirty&&(this._buildDrawList(),this.imageDirty=!0),(this.imageDirty||a.force)&&(this._doDrawList({clear:a.clear!==!1}),this.imageDirty=!1,this.pickBufDirty=!0)},SceneJS_Display.prototype._buildObjectList=function(){this._objectListLen=0;for(var a in this._objects)this._objects.hasOwnProperty(a)&&(this._objectList[this._objectListLen++]=this._objects[a])},SceneJS_Display.prototype._makeStateSortKeys=function(){for(var a,b=0,c=this._objectListLen;c>b;b++)a=this._objectList[b],a.program?a.sortKey=1e12*(a.stage.priority+1)+1e9*(a.flags.transparent?2:1)+1e6*(a.layer.priority+1)+1e3*(a.program.id+1)+a.texture.stateId:a.sortKey=-1},SceneJS_Display.prototype._stateSort=function(){this._objectList.length=this._objectListLen,this._objectList.sort(this._stateSortObjects)},SceneJS_Display.prototype._stateSortObjects=function(a,b){return a.sortKey-b.sortKey},SceneJS_Display.prototype._logObjectList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._objectListLen+" objects");for(var a=0,b=this._objectListLen;b>a;a++){var c=this._objectList[a];console.log("SceneJS_Display : object["+a+"] sortKey = "+c.sortKey)}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._buildDrawList=function(){this._lastStateId=this._lastStateId||[],this._lastPickStateId=this._lastPickStateId||[];for(var a=0;23>a;a++)this._lastStateId[a]=null,this._lastPickStateId[a]=null;this._drawListLen=0,this._pickDrawListLen=0;var b,c,d,e,f,g={},h=[],i=[];this._tagSelector&&(c=this._tagSelector.mask,d=this._tagSelector.regex),this._objectDrawList=this._objectDrawList||[],this._objectDrawListLen=0;for(var a=0,j=this._objectListLen;j>a;a++)if(b=this._objectList[a],b.enable.enabled!==!1&&(f=b.flags,f.enabled!==!1&&b.layer.enabled&&(!c||(e=b.tag,!e.tag||(e.mask!=c&&(e.mask=c,e.matches=d.test(e.tag)),e.matches)))))if(b.renderTarget.targets)for(var k,l,m,n=b.renderTarget.targets,o=0,p=n.length;p>o;o++)k=n[o],l=k.coreId,m=g[l],m||(m=[],g[l]=m,h.push(m),i.push(this._chunkFactory.getChunk(k.stateId,"renderTarget",b.program,k))),m.push(b);else this._objectDrawList[this._objectDrawListLen++]=b;for(var m,k,b,q,a=0,j=h.length;j>a;a++){m=h[a],k=i[a],this._appendRenderTargetChunk(k);for(var o=0,p=m.length;p>o;o++)b=m[o],q=b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q)}b&&this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1,"renderTarget",b.program,{}));for(var a=0,j=this._objectDrawListLen;j>a;a++)b=this._objectDrawList[a],q=!b.stage||b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q);this.drawListDirty=!1},SceneJS_Display.prototype._appendRenderTargetChunk=function(a){this._drawList[this._drawListLen++]=a},SceneJS_Display.prototype._appendObjectToDrawLists=function(a,b){for(var c,d=a.chunks,e=a.flags.picking,f=0,g=d.length;g>f;f++)c=d[f],c&&(c.draw&&(c.unique||this._lastStateId[f]!=c.id)&&(this._drawList[this._drawListLen++]=c,this._lastStateId[f]=c.id),c.pick&&b!==!1&&e&&(c.unique||this._lastPickStateId[f]!=c.id)&&(this._pickDrawList[this._pickDrawListLen++]=c,this._lastPickStateId[f]=c.id))},SceneJS_Display.prototype._logDrawList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._drawListLen+" draw list chunks");for(var a=0,b=this._drawListLen;b>a;a++){var c=this._drawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._logPickList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._pickDrawListLen+" pick list chunks");for(var a=0,b=this._pickDrawListLen;b>a;a++){var c=this._pickDrawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype.pick=function(a){var b=this._canvas.canvas,c=this._canvas.ssaaMultiplier,d=null,e=a.canvasX*c,f=a.canvasY*c,g=this.pickBuf;g||(g=this.pickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.pickBufDirty=!0),this.render(),g.bind(),this.pickBufDirty&&(g.clear(),this._doDrawList({pick:!0,clear:!0}),this._canvas.gl.finish(),this.pickBufDirty=!1,this.rayPickBufDirty=!0);var h=g.read(e,f),i=h[0]+256*h[1]+65536*h[2],j=i>=1?i-1:-1;g.unbind();var k=this._frameCtx.pickNames[j];if(k&&(d={name:k.name,path:k.path,nodeId:k.nodeId,canvasPos:[e,f]},a.rayPick)){var l=this.rayPickBuf;l||(l=this.rayPickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.rayPickBufDirty=!0),l.bind(),this.rayPickBufDirty&&(l.clear(),this._doDrawList({pick:!0,rayPick:!0,clear:!0}),this.rayPickBufDirty=!1),h=l.read(e,f),l.unbind();var m=this._unpackDepth(h),n=b.width,o=b.height,p=(e-n/2)/(n/2),q=-(f-o/2)/(o/2),r=this._frameCtx.cameraMat,s=this._frameCtx.viewMat,t=SceneJS_math_mulMat4(r,s,[]),u=SceneJS_math_inverseMat4(t,[]),v=SceneJS_math_transformVector4(u,[p,q,-1,1]);v=SceneJS_math_mulVec4Scalar(v,1/v[3]);var w=SceneJS_math_transformVector4(u,[p,q,1,1]);w=SceneJS_math_mulVec4Scalar(w,1/w[3]);var x=SceneJS_math_subVec3(w,v,[]),y=SceneJS_math_addVec3(v,SceneJS_math_mulVec4Scalar(x,m,[]),[]);d.worldPos=y}return d},SceneJS_Display.prototype.readPixels=function(a,b){this._readPixelBuf||(this._readPixelBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas})),this._readPixelBuf.bind(),this._readPixelBuf.clear(),this.render({force:!0});for(var c,d,e=0;b>e;e++)c=a[e]||(a[e]={}),d=this._readPixelBuf.read(c.x,c.y),c.r=d[0],c.g=d[1],c.b=d[2],c.a=d[3];this._readPixelBuf.unbind()},SceneJS_Display.prototype._unpackDepth=function(a){var b=[a[0]/256,a[1]/256,a[2]/256,a[3]/256],c=[1/16777216,1/65536,1/256,1];return SceneJS_math_dotVector4(b,c)},SceneJS_Display.prototype._doDrawList=function(a){var b=this._canvas.gl,c=this._frameCtx;c.renderTarget=null,c.targetIndex=0,c.renderBuf=null,c.viewMat=null,c.modelMat=null,c.cameraMat=null,c.renderer=null,c.depthbufEnabled=null,c.clearDepth=null,c.depthFunc=b.LESS,c.scissorTestEnabled=!1,c.blendEnabled=!1,c.backfaces=!0,c.frontface="ccw",c.pick=!!a.pick,c.rayPick=!!a.rayPick,c.pickIndex=0,c.textureUnit=0,c.lineWidth=1,c.transparent=!1,c.ambientColor=this._ambientColor,c.aspect=this._canvas.canvas.width/this._canvas.canvas.height,this._canvas.UINT_INDEX_ENABLED&&b.getExtension("OES_element_index_uint");var d=b.getExtension("OES_vertex_array_object");if(c.VAO=d?d:null,b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),this.transparent?b.clearColor(0,0,0,0):b.clearColor(this._ambientColor[0],this._ambientColor[1],this._ambientColor[2],1),a.clear&&b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),b.frontFace(b.CCW),b.disable(b.CULL_FACE),b.disable(b.BLEND),a.pick)for(var e=0,f=this._pickDrawListLen;f>e;e++)this._pickDrawList[e].pick(c);else for(var e=0,f=this._drawListLen;f>e;e++)this._drawList[e].draw(c);if(b.flush(),c.renderBuf&&c.renderBuf.unbind(),c.VAO){c.VAO.bindVertexArrayOES(null);for(var e=0;10>e;e++)b.disableVertexAttribArray(e)}},SceneJS_Display.prototype.destroy=function(){this._programFactory.destroy()};var SceneJS_ProgramSourceFactory=new function(){function a(a){if(a.renderTarget&&a.renderTarget.targets)for(var b=a.renderTarget.targets,c=0,d=b.length;d>c;c++)if("depth"===b[c].bufType)return!0;return!1}function b(a){return a.getShaderPrecisionFormat?a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.HIGH_FLOAT).precision>0?"highp":a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.MEDIUM_FLOAT).precision>0?"mediump":"lowp":"mediump"}this._sourceCache={},this.getSource=function(a,b){var c=this._sourceCache[a];return c?(c.useCount++,c):this._sourceCache[a]=new SceneJS_ProgramSource(a,this._composePickingVertexShader(b),this._composePickingFragmentShader(b),this._composeRenderingVertexShader(b),this._composeRenderingFragmentShader(b))},this.putSource=function(a){var b=this._sourceCache[a];b&&0==--b.useCount&&(this._sourceCache[b.hash]=null)},this._composePickingVertexShader=function(a){var b=!!a.morphGeometry.targets,c=["attribute vec3 SCENEJS_aVertex;","uniform mat4 SCENEJS_uMMatrix;","uniform mat4 SCENEJS_uVMatrix;","uniform mat4 SCENEJS_uVNMatrix;","uniform mat4 SCENEJS_uPMatrix;"];return c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),b&&(c.push("uniform float SCENEJS_uMorphFactor;"),a.morphGeometry.targets[0].vertexBuf&&c.push("attribute vec3 SCENEJS_aMorphVertex;")),c.push("void main(void) {"),c.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "),b&&a.morphGeometry.targets[0].vertexBuf&&c.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "),c.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "),c.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"),c.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"),c.push("}"),c},this._composePickingFragmentShader=function(a){var c=a.clips.clips.length>0,d=b(a._canvas.gl),e=["precision "+d+" float;"];if(e.push("varying vec4 SCENEJS_vWorldVertex;"),e.push("varying vec4 SCENEJS_vViewVertex;"),e.push("uniform bool SCENEJS_uRayPickMode;"),e.push("uniform vec3 SCENEJS_uPickColor;"),e.push("uniform float SCENEJS_uZNear;"),e.push("uniform float SCENEJS_uZFar;"),e.push("uniform bool SCENEJS_uClipping;"),c)for(var f=0;f 0.0) { discard; }"),e.push("}")}return e.push(" if (SCENEJS_uRayPickMode) {"),e.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"),e.push(" gl_FragColor = packDepth(zNormalizedDepth); "),e.push(" } else {"),e.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "),e.push(" }"),e.push("}"),e},this._isTexturing=function(a){if(a.texture.layers&&a.texture.layers.length>0){if(a.geometry.uvBuf||a.geometry.uvBuf2)return!0;if(a.morphGeometry.targets&&(a.morphGeometry.targets[0].uvBuf||a.morphGeometry.targets[0].uvBuf2))return!0}return!1},this._isCubeMapping=function(a){return a.flags.reflective&&a.cubemap.layers&&a.cubemap.layers.length>0&&a.geometry.normalBuf},this._hasNormals=function(a){return a.geometry.normalBuf?!0:a.morphGeometry.targets&&a.morphGeometry.targets[0].normalBuf?!0:!1},this._hasTangents=function(a){if(a.texture){var b=a.texture.layers;if(!b)return!1;for(var c=0,d=b.length;d>c;c++)if("normals"==b[c].applyTo)return!0}return!1},this._composeRenderingVertexShader=function(a){var b=a.shader.shaders||{};if(b.vertex&&b.vertex.code&&""!=b.vertex.code&&SceneJS._isEmpty(b.vertex.hooks))return[b.vertex.code];var c=b.vertex||{},d=c.hooks||{},e=b.fragment||{},f=e.hooks||{},g=this._isTexturing(a),h=this._hasNormals(a),i=this._hasTangents(a),j=a.clips.clips.length>0,k=!!a.morphGeometry.targets,l=[];if(l.push("uniform mat4 SCENEJS_uMMatrix;"),l.push("uniform mat4 SCENEJS_uVMatrix;"),l.push("uniform mat4 SCENEJS_uPMatrix;"),l.push("attribute vec3 SCENEJS_aVertex;"),l.push("uniform vec3 SCENEJS_uWorldEye;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("attribute vec3 SCENEJS_aNormal;"),l.push("uniform mat4 SCENEJS_uMNMatrix;"),l.push("uniform mat4 SCENEJS_uVNMatrix;"),l.push("varying vec3 SCENEJS_vViewNormal;"),i&&l.push("attribute vec4 SCENEJS_aTangent;");for(var m=0;m0,m=b(c._canvas.gl),n=["\n"];if(n.push("precision "+m+" float;"),l&&n.push("varying vec4 SCENEJS_vWorldVertex;"),n.push("varying vec4 SCENEJS_vViewVertex;"),n.push("uniform float SCENEJS_uZNear;"),n.push("uniform float SCENEJS_uZFar;"),l)for(var o=0;oo;o++)p=c.texture.layers[o],n.push("uniform sampler2D SCENEJS_uSampler"+o+";"),p.matrix&&n.push("uniform mat4 SCENEJS_uLayer"+o+"Matrix;"),n.push("uniform float SCENEJS_uLayer"+o+"BlendFactor;")}if(i&&h)for(var p,o=0,q=c.cubemap.layers.length;q>o;o++)p=c.cubemap.layers[o],n.push("uniform samplerCube SCENEJS_uCubeMapSampler"+o+";"),n.push("uniform float SCENEJS_uCubeMapIntensity"+o+";");if(n.push("uniform bool SCENEJS_uClipping;"),n.push("uniform bool SCENEJS_uSolid;"),n.push("uniform bool SCENEJS_uDepthMode;"),n.push("uniform bool SCENEJS_uTransparent;"),c.geometry.colorBuf&&n.push("varying vec4 SCENEJS_vColor;"),n.push("uniform vec3 SCENEJS_uAmbientColor;"),n.push("uniform vec3 SCENEJS_uMaterialColor;"),n.push("uniform float SCENEJS_uMaterialAlpha;"),n.push("uniform float SCENEJS_uMaterialEmit;"),n.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"),n.push("uniform float SCENEJS_uMaterialSpecular;"),n.push("uniform float SCENEJS_uMaterialShine;"),n.push("varying vec3 SCENEJS_vViewEyeVec;"),i){n.push("varying vec3 SCENEJS_vViewNormal;");for(var r,o=0;o 0.0) { discard; }"),n.push("}")}i&&j&&(n.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"),n.push(" if (a < 0.0) {"),n.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"),n.push(" return;"),n.push(" }")),n.push(" vec3 ambient= SCENEJS_uAmbientColor;"),g&&c.geometry.uvBuf&&f.texturePos&&n.push(f.texturePos+"(SCENEJS_vUVCoord);"),f.viewPos&&n.push(f.viewPos+"(SCENEJS_vViewVertex);"),i&&f.viewNormal&&n.push(f.viewNormal+"(SCENEJS_vViewNormal);"),c.geometry.colorBuf?n.push(" vec3 color = SCENEJS_vColor.rgb;"):n.push(" vec3 color = SCENEJS_uMaterialColor;"),n.push(" float alpha = SCENEJS_uMaterialAlpha;"),n.push(" float emit = SCENEJS_uMaterialEmit;"),n.push(" float specular = SCENEJS_uMaterialSpecular;"),n.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"),n.push(" float shine = SCENEJS_uMaterialShine;"),f.materialBaseColor&&n.push("color="+f.materialBaseColor+"(color);"),f.materialAlpha&&n.push("alpha="+f.materialAlpha+"(alpha);"),f.materialEmit&&n.push("emit="+f.materialEmit+"(emit);"),f.materialSpecular&&n.push("specular="+f.materialSpecular+"(specular);"),f.materialSpecularColor&&n.push("specularColor="+f.materialSpecularColor+"(specularColor);"),f.materialShine&&n.push("shine="+f.materialShine+"(shine);"),i&&(n.push(" float attenuation = 1.0;"),k?n.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"):n.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"));var p;if(g){n.push(" vec4 texturePos;"),n.push(" vec2 textureCoord=vec2(0.0,0.0);");for(var o=0,q=c.texture.layers.length;q>o;o++){if(p=c.texture.layers[o],"normal"==p.applyFrom&&i){if(!c.geometry.normalBuf){SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors");continue}n.push("texturePos=vec4(viewNormalVec.xyz, 1.0);")}if("uv"==p.applyFrom){if(!c.geometry.uvBuf){SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates");continue}n.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);")}if("uv2"==p.applyFrom){if(!c.geometry.uvBuf2){SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates");continue}n.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);")}p.matrix?n.push("textureCoord=(SCENEJS_uLayer"+o+"Matrix * texturePos).xy;"):n.push("textureCoord=texturePos.xy;"),"alpha"==p.applyTo&&("multiply"==p.blendMode?n.push("alpha = alpha * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"):"add"==p.blendMode&&n.push("alpha = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * alpha) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);")),"baseColor"==p.applyTo&&("multiply"==p.blendMode?n.push("color = color * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"):n.push("color = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * color) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);")),"emit"==p.applyTo&&("multiply"==p.blendMode?n.push("emit = emit * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):n.push("emit = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * emit) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"specular"==p.applyTo&&i&&("multiply"==p.blendMode?n.push("specular = specular * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):n.push("specular = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * specular) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"shine"==p.applyTo&&("multiply"==p.blendMode?n.push("shine = shine * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):n.push("shine = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * shine) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"normals"==p.applyTo&&i&&n.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);")}}if(i&&h){n.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"),n.push("envLookup.y = envLookup.y * -1.0;"),n.push("vec4 envColor;");for(var o=0,q=c.cubemap.layers.length;q>o;o++)p=c.cubemap.layers[o],n.push("envColor = textureCube(SCENEJS_uCubeMapSampler"+o+", envLookup);"),n.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity"+o+");")}if(n.push(" vec4 fragColor;"),i){n.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"),n.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"),n.push(" vec3 viewLightVec;"),n.push(" float dotN;"),n.push(" float lightDist;");for(var r,o=0,q=c.lights.lights.length;q>o;o++)r=c.lights.lights[o],"ambient"!=r.mode&&(n.push("viewLightVec = SCENEJS_vViewLightVecAndDist"+o+".xyz;"),"point"==r.mode&&(n.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),n.push("lightDist = SCENEJS_vViewLightVecAndDist"+o+".w;"),n.push("attenuation = 1.0 - ( SCENEJS_uLightAttenuation"+o+"[0] + SCENEJS_uLightAttenuation"+o+"[1] * lightDist + SCENEJS_uLightAttenuation"+o+"[2] * lightDist * lightDist);"),r.diffuse&&n.push(" lightValue += dotN * SCENEJS_uLightColor"+o+" * attenuation;"),r.specular&&n.push(" specularValue += specularColor * SCENEJS_uLightColor"+o+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;")),"dir"==r.mode&&(n.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),r.diffuse&&n.push(" lightValue += dotN * SCENEJS_uLightColor"+o+";"),r.specular&&n.push("specularValue += specularColor * SCENEJS_uLightColor"+o+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);")));n.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);")}else n.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);");return f.pixelColor&&n.push("fragColor="+f.pixelColor+"(fragColor);"),a(c)?(n.push(" if (SCENEJS_uDepthMode) {"),n.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"),n.push(" const vec4 bias = vec4(1.0 / 255.0,"),n.push(" 1.0 / 255.0,"),n.push(" 1.0 / 255.0,"),n.push(" 0.0);"),n.push(" float r = depth;"),n.push(" float g = fract(r * 255.0);"),n.push(" float b = fract(g * 255.0);"),n.push(" float a = fract(b * 255.0);"),n.push(" vec4 colour = vec4(r, g, b, a);"),n.push(" gl_FragColor = colour - (colour.yzww * bias);"),n.push(" } else {"),n.push(" gl_FragColor = fragColor;"),n.push(" };")):n.push(" gl_FragColor = fragColor;"),n.push("}"),n}},SceneJS_ProgramSource=function(a,b,c,d,e){this.hash=a,this.pickVertexSrc=b,this.pickFragmentSrc=c,this.drawVertexSrc=d,this.drawFragmentSrc=e,this.useCount=0},SceneJS_ProgramFactory=function(a){this._canvas=a.canvas,this._programs={},this._nextProgramId=0};SceneJS_ProgramFactory.prototype.getProgram=function(a,b){var c=this._programs[a];if(!c){var d=SceneJS_ProgramSourceFactory.getSource(a,b);c=new SceneJS_Program(this._nextProgramId++,a,d,this._canvas.gl),this._programs[a]=c}return c.useCount++,c},SceneJS_ProgramFactory.prototype.putProgram=function(a){--a.useCount<=0&&(a.draw.destroy(),a.pick.destroy(),SceneJS_ProgramSourceFactory.putSource(a.hash),delete this._programs[a.hash])},SceneJS_ProgramFactory.prototype.webglRestored=function(){var a,b=this._canvas.gl;for(var c in this._programs)this._programs.hasOwnProperty(c)&&(a=this._programs[c],a&&a.build&&a.build(b))},SceneJS_ProgramFactory.prototype.destroy=function(){};var SceneJS_Program=function(a,b,c,d){this.id=a,this.hash=c.hash,this.source=c,this.gl=d,this.UINT_INDEX_ENABLED=!!d.getExtension("OES_element_index_uint"),this.draw=null,this.pick=null,this.useCount=0,this.build(d)};SceneJS_Program.prototype.build=function(a){this.gl=a,this.draw=new SceneJS._webgl.Program(a,[this.source.drawVertexSrc.join("\n")],[this.source.drawFragmentSrc.join("\n")]), +this.pick=new SceneJS._webgl.Program(a,[this.source.pickVertexSrc.join("\n")],[this.source.pickFragmentSrc.join("\n")])};var SceneJS_ObjectFactory=function(){};SceneJS_ObjectFactory.prototype._freeObjects=[],SceneJS_ObjectFactory.prototype._numFreeObjects=0,SceneJS_ObjectFactory.prototype.getObject=function(a){var b;return this._numFreeObjects>0?(b=this._freeObjects[--this._numFreeObjects],b.id=a,b):new SceneJS_Object(a)},SceneJS_ObjectFactory.prototype.putObject=function(a){this._freeObjects[this._numFreeObjects++]=a};var SceneJS_Object=function(a){this.id=a,this.hash=null,this.sortKey=null,this.chunks=[],this.chunksLen=0,this.program=null,this.layer=null,this.texture=null,this.flags=null,this.tag=null};SceneJS.RenderContext=function(a){this._frameCtx=a},SceneJS.RenderContext.prototype.getCameraMatrix=function(){return this._frameCtx.cameraMat},SceneJS.RenderContext.prototype.getViewMatrix=function(){return this._frameCtx.viewMat},SceneJS.RenderContext.prototype.getModelMatrix=function(){return this._frameCtx.modelMat},SceneJS.RenderContext.prototype.getCanvasPos=function(a){this.getProjPos(a);var b=this._frameCtx.canvas.canvas,c=this._frameCtx.canvas.ssaaMultiplier,d=b.width/c,e=b.height/c,f=this._pc,g=f[0]/f[3]*d*.5,h=f[1]/f[3]*e*.5;return{x:g+.5*d,y:e-h-.5*e}},SceneJS.RenderContext.prototype.getCameraPos=function(a){return this.getProjPos(a),this._camPos=SceneJS_math_normalizeVec3(this._pc,[0,0,0]),{x:this._camPos[0],y:this._camPos[1],z:this._camPos[2]}},SceneJS.RenderContext.prototype.getProjPos=function(a){return this.getViewPos(a),this._pc=SceneJS_math_transformPoint3(this._frameCtx.cameraMat,this._vc),{x:this._pc[0],y:this._pc[1],z:this._pc[2],w:this._pc[3]}},SceneJS.RenderContext.prototype.getViewPos=function(a){return this.getWorldPos(a),this._vc=SceneJS_math_transformPoint3(this._frameCtx.viewMat,this._wc),{x:this._vc[0],y:this._vc[1],z:this._vc[2],w:this._vc[3]}},SceneJS.RenderContext.prototype.getWorldPos=function(a){return this._wc=SceneJS_math_transformPoint3(this._frameCtx.modelMat,a||[0,0,0]),{x:this._wc[0],y:this._wc[1],z:this._wc[2],w:this._wc[3]}};var SceneJS_Chunk=function(){};SceneJS_Chunk.prototype.init=function(a,b,c,d){this.id=a,this.program=b,this.core=c,this.core2=d,this.build&&this.build()};var SceneJS_ChunkFactory=function(){this._chunks={},this.chunkTypes=SceneJS_ChunkFactory.chunkTypes};SceneJS_ChunkFactory.chunkTypes={},SceneJS_ChunkFactory._freeChunks={},SceneJS_ChunkFactory.createChunkType=function(a){if(!a.type)throw"'type' expected in params";var b=SceneJS_Chunk,c=function(){this.useCount=0,this.init.apply(this,arguments)};return c.prototype=new b,c.prototype.constructor=c,a.drawAndPick&&(a.draw=a.pick=a.drawAndPick),SceneJS_ChunkFactory.chunkTypes[a.type]=c,SceneJS._apply(a,c.prototype),SceneJS_ChunkFactory._freeChunks[a.type]={chunks:[],chunksLen:0},c},SceneJS_ChunkFactory.prototype.getChunk=function(a,b,c,d,e){var f=SceneJS_ChunkFactory.chunkTypes[b];if(!f)throw"chunk type not supported: '"+b+"'";var g=this._chunks[a];if(g)return g.useCount++,g;var h=SceneJS_ChunkFactory._freeChunks[b];return h.chunksLen>0&&(g=h.chunks[--h.chunksLen]),g?g.init(a,c,d,e):g=new f(a,c,d,e),g.type=b,g.useCount=1,this._chunks[a]=g,g},SceneJS_ChunkFactory.prototype.putChunk=function(a){if(0!=a.useCount&&--a.useCount<=0){a.recycle&&a.recycle(),delete this._chunks[a.id];var b=SceneJS_ChunkFactory._freeChunks[a.type];b.chunks[b.chunksLen++]=a}},SceneJS_ChunkFactory.prototype.webglRestored=function(){var a;for(var b in this._chunks)this._chunks.hasOwnProperty(b)&&(a=this._chunks[b],a&&a.build&&a.build())},SceneJS_ChunkFactory.createChunkType({type:"camera",build:function(){this._uPMatrixDraw=this.program.draw.getUniform("SCENEJS_uPMatrix"),this._uZNearDraw=this.program.draw.getUniform("SCENEJS_uZNear"),this._uZFarDraw=this.program.draw.getUniform("SCENEJS_uZFar"),this._uPMatrixPick=this.program.pick.getUniform("SCENEJS_uPMatrix"),this._uZNearPick=this.program.pick.getUniform("SCENEJS_uZNear"),this._uZFarPick=this.program.pick.getUniform("SCENEJS_uZFar")},draw:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixDraw&&this._uPMatrixDraw.setValue(this.core.mat),this._uZNearDraw&&this._uZNearDraw.setValue(this.core.optics.near),this._uZFarDraw&&this._uZFarDraw.setValue(this.core.optics.far),a.cameraMat=this.core.mat},pick:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixPick&&this._uPMatrixPick.setValue(this.core.mat),a.rayPick&&(this._uZNearPick&&this._uZNearPick.setValue(this.core.optics.near),this._uZFarPick&&this._uZFarPick.setValue(this.core.optics.far)),a.cameraMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"clips",build:function(){this._draw=this._draw||[];for(var a=this.program.draw,b=0,c=this.core.clips.length;c>b;b++)this._draw[b]={uClipMode:a.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:a.getUniform("SCENEJS_uClipNormalAndDist"+b)};this._pick=this._pick||[];for(var d=this.program.pick,b=0,c=this.core.clips.length;c>b;b++)this._pick[b]={uClipMode:d.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:d.getUniform("SCENEJS_uClipNormalAndDist"+b)}},drawAndPick:function(a){for(var b,c,d,e=a.pick?this._pick:this._draw,f=this.core.clips,g=(this.program.gl,0),h=f.length;h>g;g++)a.pick?(b=e[g].uClipMode,c=e[g].uClipNormalAndDist):(b=e[g].uClipMode,c=e[g].uClipNormalAndDist),b&&c&&(d=f[g],"inside"==d.mode?(b.setValue(2),c.setValue(d.normalAndDist)):"outside"==d.mode?(b.setValue(1),c.setValue(d.normalAndDist)):b.setValue(0))}}),SceneJS_ChunkFactory.createChunkType({type:"draw",unique:!0,build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode")},drawAndPick:function(a){var b=this.program.gl,c=this.program.UINT_INDEX_ENABLED?b.UNSIGNED_INT:b.UNSIGNED_SHORT;a.pick?this._depthModePick&&this._depthModePick.setValue(a.depthMode):this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),b.drawElements(this.core.primitive,this.core.indexBuf.numItems,c,0)}}),SceneJS_ChunkFactory.createChunkType({type:"flags",build:function(){var a=this.program.draw;this._uClippingDraw=a.getUniform("SCENEJS_uClipping"),this._uSolidDraw=a.getUniform("SCENEJS_uSolid");var b=this.program.pick;this._uClippingPick=b.getUniform("SCENEJS_uClipping")},drawAndPick:function(a){var b=this.program.gl,c=this.core.backfaces;a.backfaces!=c&&(c?b.disable(b.CULL_FACE):b.enable(b.CULL_FACE),a.backfaces=c);var d=this.core.frontface;a.frontface!=d&&("ccw"==d?b.frontFace(b.CCW):b.frontFace(b.CW),a.frontface=d);var e=this.core.transparent;a.transparent!=e&&(a.pick||(e?(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA),a.blendEnabled=!0):(b.disable(b.BLEND),a.blendEnabled=!1)),a.transparent=e),a.pick?this._uClippingPick&&this._uClippingPick.setValue(this.core.clipping):(this._uClippingDraw&&this._uClippingDraw.setValue(this.core.clipping),this._uSolidDraw&&this._uSolidDraw.setValue(this.core.solid))}}),SceneJS_ChunkFactory.createChunkType({type:"renderTarget",programGlobal:!0,draw:function(a){var b=this.program.gl;a.renderBuf&&(b.flush(),a.renderBuf.unbind(),a.renderBuf=null);var c=this.core.renderBuf;return c?(c.bind(),a.depthMode="depth"===this.core.bufType,a.depthMode||a.blendEnabled&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA)),b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),b.clearColor(a.ambientColor[0],a.ambientColor[1],a.ambientColor[2],1),b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),void(a.renderBuf=c)):void(a.depthMode=!1)}}),SceneJS_ChunkFactory.createChunkType({type:"geometry",build:function(){var a=this.program.draw;this._aVertexDraw=a.getAttribute("SCENEJS_aVertex"),this._aNormalDraw=a.getAttribute("SCENEJS_aNormal"),this._aUVDraw=a.getAttribute("SCENEJS_aUVCoord"),this._aUV2Draw=a.getAttribute("SCENEJS_aUVCoord2"),this._aTangentDraw=a.getAttribute("SCENEJS_aTangent"),this._aColorDraw=a.getAttribute("SCENEJS_aVertexColor"),this._aMorphVertexDraw=a.getAttribute("SCENEJS_aMorphVertex"),this._aMorphNormalDraw=a.getAttribute("SCENEJS_aMorphNormal"),this._uMorphFactorDraw=a.getUniform("SCENEJS_uMorphFactor");var b=this.program.pick;this._aVertexPick=b.getAttribute("SCENEJS_aVertex"),this._aMorphVertexPick=b.getAttribute("SCENEJS_aMorphVertex"),this._uMorphFactorPick=b.getUniform("SCENEJS_uMorphFactor"),this.VAO=null,this.VAOMorphKey1=0,this.VAOMorphKey2=0,this.VAOHasInterleavedBuf=!1},recycle:function(){if(this.VAO){var a=this.program.gl.getExtension("OES_vertex_array_object");a.deleteVertexArrayOES(this.VAO),this.VAO=null}},morphDraw:function(){this.VAOMorphKey1=this.core.key1,this.VAOMorphKey2=this.core.key2;var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexDraw?(this._aVertexDraw.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexDraw.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aMorphNormalDraw?(this._aNormalDraw.bindFloatArrayBuffer(a.normalBuf),this._aMorphNormalDraw.bindFloatArrayBuffer(b.normalBuf)):this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this.setDrawMorphFactor()},setDrawMorphFactor:function(){this._uMorphFactorDraw&&this._uMorphFactorDraw.setValue*this.core.factor},draw:function(a){var b=this.core.targets&&this.core.targets.length,c=this.core2.interleavedBuf&&!this.core2.interleavedBuf.dirty;if(this.VAO){if(a.VAO.bindVertexArrayOES(this.VAO),b){if(this.VAOMorphKey1==this.core.key1&&this.VAOMorphKey2==this.core.key2)return void this.setDrawMorphFactor()}else if(c||!this.VAOHasInterleavedBuf)return}else if(a.VAO){a.VAO.bindVertexArrayOES(null),this.VAO=a.VAO.createVertexArrayOES(),a.VAO.bindVertexArrayOES(this.VAO);this.program.gl}b?this.morphDraw():c?(this.VAOHasInterleavedBuf=!0,this.core2.interleavedBuf.bind(),this._aVertexDraw&&this._aVertexDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedPositionOffset),this._aNormalDraw&&this._aNormalDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedNormalOffset),this._aUVDraw&&this._aUVDraw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUVOffset),this._aUV2Draw&&this._aUV2Draw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUV2Offset),this._aColorDraw&&this._aColorDraw.bindInterleavedFloatArrayBuffer(4,this.core2.interleavedStride,this.core2.interleavedColorOffset),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())):(this.VAOHasInterleavedBuf=!1,this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())),this.core2.indexBuf.bind()},morphPick:function(){var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexPick?(this._aVertexPick.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexPick.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this._uMorphFactorPick&&this._uMorphFactorPick.setValue(this.core.factor)},pick:function(a){this.core.targets&&this.core.targets.length?this.morphPick():this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this.core2.indexBuf.bind()}}),SceneJS_ChunkFactory.createChunkType({type:"lights",build:function(){this._uAmbientColor=this._uAmbientColor||[],this._uLightColor=this._uLightColor||[],this._uLightDir=this._uLightDir||[],this._uLightPos=this._uLightPos||[],this._uLightCutOff=this._uLightCutOff||[],this._uLightSpotExp=this._uLightSpotExp||[],this._uLightAttenuation=this._uLightAttenuation||[];for(var a=this.core.lights,b=this.program,c=0,d=a.length;d>c;c++)switch(a[c].mode){case"ambient":this._uAmbientColor[c]=b.draw.getUniform("SCENEJS_uAmbientColor");break;case"dir":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=null,this._uLightDir[c]=b.draw.getUniform("SCENEJS_uLightDir"+c);break;case"point":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=b.draw.getUniform("SCENEJS_uLightPos"+c),this._uLightDir[c]=null,this._uLightAttenuation[c]=b.draw.getUniform("SCENEJS_uLightAttenuation"+c)}},draw:function(a){a.dirty&&this.build();for(var b,c=this.core.lights,d=(this.program.gl,0),e=c.length;e>d;d++)b=c[d],this._uAmbientColor[d]?this._uAmbientColor[d].setValue(b.color):(this._uLightColor[d]&&this._uLightColor[d].setValue(b.color),this._uLightPos[d]&&(this._uLightPos[d].setValue(b.pos),this._uLightAttenuation[d]&&this._uLightAttenuation[d].setValue(b.attenuation)),this._uLightDir[d]&&this._uLightDir[d].setValue(b.dir))}}),SceneJS_ChunkFactory.createChunkType({type:"listeners",programGlobal:!0,build:function(){},draw:function(a){for(var b=this.core.listeners,c=a.renderListenerCtx,d=b.length-1;d>=0;d--)if(b[d](c)===!0)return!0}}),SceneJS_ChunkFactory.createChunkType({type:"lookAt",build:function(){this._uvMatrixDraw=this.program.draw.getUniform("SCENEJS_uVMatrix"),this._uVNMatrixDraw=this.program.draw.getUniform("SCENEJS_uVNMatrix"),this._uWorldEyeDraw=this.program.draw.getUniform("SCENEJS_uWorldEye"),this._uvMatrixPick=this.program.pick.getUniform("SCENEJS_uVMatrix")},draw:function(a){this.core.dirty&&this.core.rebuild();this.program.gl;this._uvMatrixDraw&&this._uvMatrixDraw.setValue(this.core.mat),this._uVNMatrixDraw&&this._uVNMatrixDraw.setValue(this.core.normalMat),this._uWorldEyeDraw&&this._uWorldEyeDraw.setValue(this.core.lookAt.eye),a.viewMat=this.core.mat},pick:function(a){this.program.gl;this._uvMatrixPick&&this._uvMatrixPick.setValue(this.core.mat),a.viewMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"material",build:function(){var a=this.program.draw;this._uMaterialBaseColor=a.getUniform("SCENEJS_uMaterialColor"),this._uMaterialSpecularColor=a.getUniform("SCENEJS_uMaterialSpecularColor"),this._uMaterialSpecular=a.getUniform("SCENEJS_uMaterialSpecular"),this._uMaterialShine=a.getUniform("SCENEJS_uMaterialShine"),this._uMaterialEmit=a.getUniform("SCENEJS_uMaterialEmit"),this._uMaterialAlpha=a.getUniform("SCENEJS_uMaterialAlpha")},draw:function(){this.program.gl;this._uMaterialBaseColor&&this._uMaterialBaseColor.setValue(this.core.baseColor),this._uMaterialSpecularColor&&this._uMaterialSpecularColor.setValue(this.core.specularColor),this._uMaterialSpecular&&this._uMaterialSpecular.setValue(this.core.specular),this._uMaterialShine&&this._uMaterialShine.setValue(this.core.shine),this._uMaterialEmit&&this._uMaterialEmit.setValue(this.core.emit),this._uMaterialAlpha&&this._uMaterialAlpha.setValue(this.core.alpha)}}),SceneJS_ChunkFactory.createChunkType({type:"name",build:function(){this._uPickColor=this.program.pick.getUniform("SCENEJS_uPickColor")},pick:function(a){if(this._uPickColor&&this.core.name){a.pickNames[a.pickIndex++]=this.core;var b=a.pickIndex>>16&255,c=a.pickIndex>>8&255,d=255&a.pickIndex;this._uPickColor.setValue([d/255,c/255,b/255])}}}),SceneJS_ChunkFactory.createChunkType({type:"program",build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode"),this._rayPickMode=this.program.pick.getUniform("SCENEJS_uRayPickMode")},draw:function(a){var b=this.program.draw;b.bind(),a.textureUnit=0;var c=this.program.gl;if(this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),!a.VAO)for(var d=0;10>d;d++)c.disableVertexAttribArray(d);a.drawProgram=this.program.draw},pick:function(a){var b=this.program.pick;b.bind();var c=this.program.gl;this._rayPickMode&&this._rayPickMode.setValue(a.rayPick),this._depthModePick&&this._depthModePick.setValue(a.depthMode),a.textureUnit=0;for(var d=0;10>d;d++)c.disableVertexAttribArray(d)}}),SceneJS_ChunkFactory.createChunkType({type:"renderer",build:function(){},drawAndPick:function(a){if(this.core.props){var b=this.program.gl;a.renderer&&(a.renderer.props.restoreProps(b),a.renderer=this.core),this.core.props.setProps(b)}}}),SceneJS_ChunkFactory.createChunkType({type:"depthBuffer",programGlobal:!0,drawAndPick:function(a){var b=this.program.gl,c=this.core.enabled;a.depthbufEnabled!=c&&(c?b.enable(b.DEPTH_TEST):b.disable(b.DEPTH_TEST),a.depthbufEnabled=c);var d=this.core.clearDepth;a.clearDepth!=d&&(b.clearDepth(d),a.clearDepth=d);var e=this.core.depthFunc;a.depthFunc!=e&&(b.depthFunc(e),a.depthFunc=e),this.core.clear&&b.clear(b.DEPTH_BUFFER_BIT)}}),SceneJS_ChunkFactory.createChunkType({type:"colorBuffer",programGlobal:!0,build:function(){},drawAndPick:function(a){if(!a.transparent){var b=this.core.blendEnabled,c=this.program.gl;a.blendEnabled!=b&&(b?c.enable(c.BLEND):c.disable(c.BLEND),a.blendEnabled=b);var d=this.core.colorMask;c.colorMask(d.r,d.g,d.b,d.a)}}}),SceneJS_ChunkFactory.createChunkType({type:"view",programGlobal:!0,build:function(){},drawAndPick:function(a){var b=this.core.scissorTestEnabled;if(a.scissorTestEnabled!=b){var c=this.program.gl;b?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST),a.scissorTestEnabled=b}}}),SceneJS_ChunkFactory.createChunkType({type:"shader",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"shaderParams",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"style",programGlobal:!0,drawAndPick:function(a){var b=this.core.lineWidth;if(a.lineWidth!=b){var c=this.program.gl;c.lineWidth(b),a.lineWidth=b}}}),SceneJS_ChunkFactory.createChunkType({type:"texture",build:function(){this._uTexSampler=this._uTexSampler||[],this._uTexMatrix=this._uTexMatrix||[],this._uTexBlendFactor=this._uTexBlendFactor||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uTexSampler[d]="SCENEJS_uSampler"+d,this._uTexMatrix[d]=c.getUniform("SCENEJS_uLayer"+d+"Matrix"),this._uTexBlendFactor[d]=c.getUniform("SCENEJS_uLayer"+d+"BlendFactor")},draw:function(a){a.textureUnit=0;var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uTexSampler[e]&&c.texture&&(d.bindTexture(this._uTexSampler[e],c.texture,a.textureUnit++),c._matrixDirty&&c.buildMatrix&&c.buildMatrix.call(c),this._uTexMatrix[e]&&this._uTexMatrix[e].setValue(c.matrixAsArray),this._uTexBlendFactor[e]&&this._uTexBlendFactor[e].setValue(c.blendFactor));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"cubemap",build:function(){this._uCubeMapSampler=this._uCubeMapSampler||[],this._uCubeMapIntensity=this._uCubeMapIntensity||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uCubeMapSampler[d]="SCENEJS_uCubeMapSampler"+d,this._uCubeMapIntensity[d]=c.getUniform("SCENEJS_uCubeMapIntensity"+d)},draw:function(a){var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uCubeMapSampler[e]&&c.texture&&(d.bindTexture(this._uCubeMapSampler[e],c.texture,a.textureUnit++),this._uCubeMapIntensity[e]&&this._uCubeMapIntensity[e].setValue(c.intensity));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"xform",build:function(){var a=this.program.draw;this._uMatLocationDraw=a.getUniform("SCENEJS_uMMatrix"),this._uNormalMatLocationDraw=a.getUniform("SCENEJS_uMNMatrix");var b=this.program.pick;this._uMatLocationPick=b.getUniform("SCENEJS_uMMatrix")},draw:function(a){(SceneJS_configsModule.configs.forceXFormCoreRebuild===!0||this.core.dirty&&this.core.build)&&this.core.build();this.program.gl;this._uMatLocationDraw&&this._uMatLocationDraw.setValue(this.core.mat),this._uNormalMatLocationDraw&&this._uNormalMatLocationDraw.setValue(this.core.normalMat),a.modelMat=this.core.mat},pick:function(a){this.core.dirty&&this.core.build();this.program.gl;this._uMatLocationPick&&this._uMatLocationPick.setValue(this.core.mat),a.modelMat=this.core.mat}}); \ No newline at end of file diff --git a/build/4.2.0/scenejs-4.2.0.js b/build/4.2.0/scenejs-4.2.0.js index 6f3ef137..39e3598e 100644 --- a/build/4.2.0/scenejs-4.2.0.js +++ b/build/4.2.0/scenejs-4.2.0.js @@ -4,7 +4,7 @@ * A WebGL-based 3D scene graph from xeoLabs * http://scenejs.org/ * - * Built on 2015-06-10 + * Built on 2015-06-11 * * MIT License * Copyright 2015, Lindsay Kay @@ -5971,6 +5971,9 @@ SceneJS._webgl.nextHighestPowerOfTwo = function (x) { } else if (type === gl.FLOAT_MAT4) { func = function (v) { + + // Caching this matrix is actually slower than not caching + gl.uniformMatrix4fv(location, gl.FALSE, v); }; @@ -8241,8 +8244,8 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { backfaces: true, // Show backfaces frontface: "ccw", // Default vertex winding for front face reflective: true, // Reflects reflection node cubemap, if it exists, by default. - solid: true, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect - hash: "refl;s;" + solid: false, // When true, renders backfaces without texture or shading, for a cheap solid cross-section effect + hash: "refl;;" }; var coreStack = []; @@ -8272,7 +8275,7 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { this._core.backfaces = true; // Show backfaces this._core.frontface = "ccw"; // Default vertex winding for front face this._core.reflective = true; // Reflects reflection node cubemap, if it exists, by default. - this._core.solid = true; // Renders backfaces without texture or shading, for a cheap solid cross-section effect + this._core.solid = false; // Renders backfaces without texture or shading, for a cheap solid cross-section effect if (params.flags) { // 'flags' property is actually optional in the node definition this.setFlags(params.flags); } @@ -8317,12 +8320,14 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { core.reflective = flags.reflective; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } if (flags.solid != undefined) { core.solid = flags.solid; core.hash = core.reflective ? "refl" : ""; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; @@ -8437,8 +8442,9 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { reflective = !!reflective; if (this._core.reflective != reflective) { this._core.reflective = reflective; - this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";"; + this._core.hash = (reflective ? "refl" : "") + this._core.solid ? ";s" : ";;"; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; }; @@ -8451,8 +8457,9 @@ SceneJS_NodeFactory.prototype.putNode = function (node) { solid = !!solid; if (this._core.solid != solid) { this._core.solid = solid; - this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s" : ";"; + this._core.hash = (this._core.reflective ? "refl" : "") + solid ? ";s;" : ";;"; this._engine.branchDirty(this); + this._engine.display.imageDirty = true; } return this; }; @@ -15661,7 +15668,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._sourceCache = {}; // Source codes are shared across all scenes - /** * Get sourcecode for a program to render the given states */ @@ -15698,9 +15704,6 @@ var SceneJS_ProgramSourceFactory = new (function () { this._composePickingVertexShader = function (states) { var morphing = !!states.morphGeometry.targets; var src = [ - - "precision mediump float;", - "attribute vec3 SCENEJS_aVertex;", "uniform mat4 SCENEJS_uMMatrix;", "uniform mat4 SCENEJS_uVMatrix;", @@ -15743,8 +15746,10 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = [ - "precision mediump float;" + "precision " + floatPrecision + " float;" ]; src.push("varying vec4 SCENEJS_vWorldVertex;"); @@ -15865,9 +15870,7 @@ var SceneJS_ProgramSourceFactory = new (function () { var clipping = states.clips.clips.length > 0; var morphing = !!states.morphGeometry.targets; - var src = [ - "precision mediump float;" - ]; + var src = []; src.push("uniform mat4 SCENEJS_uMMatrix;"); // Model matrix src.push("uniform mat4 SCENEJS_uVMatrix;"); // View matrix @@ -16165,9 +16168,11 @@ var SceneJS_ProgramSourceFactory = new (function () { var tangents = this._hasTangents(states); var clipping = states.clips.clips.length > 0; + var floatPrecision = getFSFloatPrecision(states._canvas.gl); + var src = ["\n"]; - src.push("precision mediump float;"); + src.push("precision " + floatPrecision + " float;"); if (clipping) { @@ -16577,6 +16582,22 @@ var SceneJS_ProgramSourceFactory = new (function () { return false; } + function getFSFloatPrecision(gl) { + if (!gl.getShaderPrecisionFormat) { + return "mediump"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) { + return "highp"; + } + + if (gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) { + return "mediump"; + } + + return "lowp"; + } + })();;/** * @class Source code for pick and draw shader programs, to be compiled into one or more {@link SceneJS_Program}s * @private diff --git a/build/4.2.0/scenejs-4.2.0.min.js b/build/4.2.0/scenejs-4.2.0.min.js index 5db1ccc7..3952cf72 100644 --- a/build/4.2.0/scenejs-4.2.0.min.js +++ b/build/4.2.0/scenejs-4.2.0.min.js @@ -4,7 +4,7 @@ * A WebGL-based 3D scene graph from xeoLabs * http://scenejs.org/ * - * Built on 2015-06-10 + * Built on 2015-06-11 * * MIT License * Copyright 2015, Lindsay Kay @@ -15,8 +15,8 @@ if(void 0===require){var requirejs,require,define;!function(ba){function J(a){return"[object Function]"===N.call(a)}function K(a){return"[object Array]"===N.call(a)}function z(a,b){if(a){var c;for(c=0;c-1&&(!a[c]||!b(a[c],c,a));c-=1);}}function t(a,b){return ha.call(a,b)}function m(a,b){return t(a,b)&&a[b]}function H(a,b){for(var c in a)if(t(a,c)&&b(a[c],c))break}function S(a,b,c,d){return b&&H(b,function(b,e){(c||!t(a,e))&&(d&&"string"!=typeof b?(a[e]||(a[e]={}),S(a[e],b,c,d)):a[e]=b)}),a}function v(a,b){return function(){return b.apply(a,arguments)}}function ca(a){throw a}function da(a){if(!a)return a;var b=ba;return z(a.split("."),function(a){b=b[a]}),b}function B(a,b,c,d){return b=Error(b+"\nhttp://requirejs.org/docs/errors.html#"+a),b.requireType=a,b.requireModules=d,c&&(b.originalError=c),b}function ia(a){function b(a,b,c){var d,e,f,g,h,i,j,k=b&&b.split("/");d=k;var l=C.map,n=l&&l["*"];if(a&&"."===a.charAt(0))if(b){for(d=m(C.pkgs,b)?k=[b]:k.slice(0,k.length-1),b=a=d.concat(a.split("/")),d=0;b[d];d+=1)if(e=b[d],"."===e)b.splice(d,1),d-=1;else if(".."===e){if(1===d&&(".."===b[2]||".."===b[0]))break;d>0&&(b.splice(d-1,2),d-=2)}d=m(C.pkgs,b=a[0]),a=a.join("/"),d&&a===b+"/"+d.main&&(a=b)}else 0===a.indexOf("./")&&(a=a.substring(2));if(c&&l&&(k||n)){for(b=a.split("/"),d=b.length;d>0;d-=1){if(f=b.slice(0,d).join("/"),k)for(e=k.length;e>0;e-=1)if((c=m(l,k.slice(0,e).join("/")))&&(c=m(c,f))){g=c,h=d;break}if(g)break;!i&&n&&m(n,f)&&(i=m(n,f),j=d)}!g&&i&&(g=i,h=j),g&&(b.splice(0,h,g),a=b.join("/"))}return a}function c(a){A&&z(document.getElementsByTagName("script"),function(b){return b.getAttribute("data-requiremodule")===a&&b.getAttribute("data-requirecontext")===w.contextName?(b.parentNode.removeChild(b),!0):void 0})}function d(a){var b=m(C.paths,a);return b&&K(b)&&1-1&&(b=a.substring(0,c),a=a.substring(c+1,a.length)),[b,a]}function f(a,c,d,f){var g,h,i=null,j=c?c.name:null,k=a,l=!0,n="";return a||(l=!1,a="_@r"+(M+=1)),a=e(a),i=a[0],a=a[1],i&&(i=b(i,j,f),h=m(I,i)),a&&(i?n=h&&h.normalize?h.normalize(a,function(a){return b(a,j,f)}):b(a,j,f):(n=b(a,j,f),a=e(n),i=a[0],n=a[1],d=!0,g=w.nameToUrl(n))),d=!i||h||d?"":"_unnormalized"+(N+=1),{prefix:i,name:n,parentMap:c,unnormalized:!!d,url:g,originalName:k,isDefine:l,id:(i?i+"!"+n:n)+d}}function g(a){var b=a.id,c=m(D,b);return c||(c=D[b]=new w.Module(a)),c}function i(a,b,c){var d=a.id,e=m(D,d);!t(I,d)||e&&!e.defineEmitComplete?(e=g(a),e.error&&"error"===b?c(e.error):e.on(b,c)):"defined"===b&&c(I[d])}function j(a,b){var c=a.requireModules,d=!1;b?b(a):(z(c,function(b){(b=m(D,b))&&(b.error=a,b.events.error&&(d=!0,b.emit("error",a)))}),d||h.onError(a))}function k(){U.length&&(ja.apply(G,[G.length-1,0].concat(U)),U=[])}function l(a){delete D[a],delete E[a]}function n(a,b,c){var d=a.map.id;a.error?a.emit("error",a.error):(b[d]=!0,z(a.depMaps,function(d,e){var f=d.id,g=m(D,f);g&&!a.depMatched[e]&&!c[f]&&(m(b,f)?(a.defineDep(e,I[f]),a.check()):n(g,b,c))}),c[d]=!0)}function o(){var a,b,e,f,g=(e=1e3*C.waitSeconds)&&w.startTime+e<(new Date).getTime(),h=[],i=[],k=!1,l=!0;if(!s){if(s=!0,H(E,function(e){if(a=e.map,b=a.id,e.enabled&&(a.isDefine||i.push(e),!e.error))if(!e.inited&&g)d(b)?k=f=!0:(h.push(b),c(b));else if(!e.inited&&e.fetched&&a.isDefine&&(k=!0,!a.prefix))return l=!1}),g&&h.length)return e=B("timeout","Load timeout for modules: "+h,null,h),e.contextName=w.contextName,j(e);l&&z(i,function(a){n(a,{},{})}),g&&!f||!k||!A&&!ea||y||(y=setTimeout(function(){y=0,o()},50)),s=!1}}function p(a){t(I,a[0])||g(f(a[0],null,!0)).init(a[1],a[2])}function q(a){var a=a.currentTarget||a.srcElement,b=w.onScriptLoad;return a.detachEvent&&!Z?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1),b=w.onScriptError,(!a.detachEvent||Z)&&a.removeEventListener("error",b,!1),{node:a,id:a&&a.getAttribute("data-requiremodule")}}function r(){var a;for(k();G.length;){if(a=G.shift(),null===a[0])return j(B("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));p(a)}}var s,u,w,x,y,C={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{},config:{}},D={},E={},F={},G=[],I={},L={},M=1,N=1;return x={require:function(a){return a.require?a.require:a.require=w.makeRequire(a.map)},exports:function(a){return a.usingExports=!0,a.map.isDefine?a.exports?a.exports:a.exports=I[a.map.id]={}:void 0},module:function(a){return a.module?a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){var b=m(C.pkgs,a.map.id);return(b?m(C.config,a.map.id+"/"+b.main):m(C.config,a.map.id))||{}},exports:I[a.map.id]}}},u=function(a){this.events=m(F,a.id)||{},this.map=a,this.shim=m(C.shim,a.id),this.depExports=[],this.depMaps=[],this.depMatched=[],this.pluginMaps={},this.depCount=0},u.prototype={init:function(a,b,c,d){d=d||{},this.inited||(this.factory=b,c?this.on("error",c):this.events.error&&(c=v(this,function(a){this.emit("error",a)})),this.depMaps=a&&a.slice(0),this.errback=c,this.inited=!0,this.ignore=d.ignore,d.enabled||this.enabled?this.enable():this.check())},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0,w.startTime=(new Date).getTime();var a=this.map;if(!this.shim)return a.prefix?this.callPlugin():this.load();w.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],v(this,function(){return a.prefix?this.callPlugin():this.load()}))}},load:function(){var a=this.map.url;L[a]||(L[a]=!0,w.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var d=this.exports,e=this.factory;if(this.inited){if(this.error)this.emit("error",this.error);else if(!this.defining){if(this.defining=!0,1>this.depCount&&!this.defined){if(J(e)){if(this.events.error&&this.map.isDefine||h.onError!==ca)try{d=w.execCb(c,e,b,d)}catch(f){a=f}else d=w.execCb(c,e,b,d);if(this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!==this.exports?d=b.exports:void 0===d&&this.usingExports&&(d=this.exports)),a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",j(this.error=a)}else d=e;this.exports=d,this.map.isDefine&&!this.ignore&&(I[c]=d,h.onResourceLoad)&&h.onResourceLoad(w,this.map,this.depMaps),l(c),this.defined=!0}this.defining=!1,this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,c=a.id,d=f(a.prefix);this.depMaps.push(d),i(d,"defined",v(this,function(d){var e,k;k=this.map.name;var n=this.map.parentMap?this.map.parentMap.name:null,o=w.makeRequire(a.parentMap,{enableBuildCallback:!0});this.map.unnormalized?(d.normalize&&(k=d.normalize(k,function(a){return b(a,n,!0)})||""),d=f(a.prefix+"!"+k,this.map.parentMap),i(d,"defined",v(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),(k=m(D,d.id))&&(this.depMaps.push(d),this.events.error&&k.on("error",v(this,function(a){this.emit("error",a)})),k.enable())):(e=v(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),e.error=v(this,function(a){this.inited=!0,this.error=a,a.requireModules=[c],H(D,function(a){0===a.map.id.indexOf(c+"_unnormalized")&&l(a.map.id)}),j(a)}),e.fromText=v(this,function(b,d){var i=a.name,k=f(i),l=Q;d&&(b=d),l&&(Q=!1),g(k),t(C.config,c)&&(C.config[i]=C.config[c]);try{h.exec(b)}catch(m){return j(B("fromtexteval","fromText eval for "+c+" failed: "+m,m,[c]))}l&&(Q=!0),this.depMaps.push(k),w.completeLoad(i),o([i],e)}),d.load(a.name,o,e,C))})),w.enable(d,this),this.pluginMaps[d.id]=d},enable:function(){E[this.map.id]=this,this.enabling=this.enabled=!0,z(this.depMaps,v(this,function(a,b){var c,d;if("string"==typeof a){if(a=f(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap),this.depMaps[b]=a,c=m(x,a.id))return void(this.depExports[b]=c(this));this.depCount+=1,i(a,"defined",v(this,function(a){this.defineDep(b,a),this.check()})),this.errback&&i(a,"error",v(this,this.errback))}c=a.id,d=D[c],!t(x,c)&&d&&!d.enabled&&w.enable(a,this)})),H(this.pluginMaps,v(this,function(a){var b=m(D,a.id);b&&!b.enabled&&w.enable(a,this)})),this.enabling=!1,this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]),c.push(b)},emit:function(a,b){z(this.events[a],function(a){a(b)}),"error"===a&&delete this.events[a]}},w={config:C,contextName:a,registry:D,defined:I,urlFetched:L,defQueue:G,Module:u,makeModuleMap:f,nextTick:h.nextTick,onError:j,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=C.pkgs,c=C.shim,d={paths:!0,config:!0,map:!0};H(a,function(a,b){d[b]?"map"===b?(C.map||(C.map={}),S(C[b],a,!0,!0)):S(C[b],a,!0):C[b]=a}),a.shim&&(H(a.shim,function(a,b){K(a)&&(a={deps:a}),!a.exports&&!a.init||a.exportsFn||(a.exportsFn=w.makeShimExports(a)),c[b]=a}),C.shim=c),a.packages&&(z(a.packages,function(a){a="string"==typeof a?{name:a}:a,b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(fa,"")}}),C.pkgs=b),H(D,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=f(b))}),(a.deps||a.callback)&&w.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;return a.init&&(b=a.init.apply(ba,arguments)),b||a.exports&&da(a.exports)}},makeRequire:function(c,d){function e(b,i,k){var l,m;return d.enableBuildCallback&&i&&J(i)&&(i.__requireJsBuild=!0),"string"==typeof b?J(i)?j(B("requireargs","Invalid require call"),k):c&&t(x,b)?x[b](D[c.id]):h.get?h.get(w,b,c,e):(l=f(b,c,!1,!0),l=l.id,t(I,l)?I[l]:j(B("notloaded",'Module name "'+l+'" has not been loaded yet for context: '+a+(c?"":". Use require([])")))):(r(),w.nextTick(function(){r(),m=g(f(null,c)),m.skipMap=d.skipMap,m.init(b,i,k,{enabled:!0}),o()}),e)}return d=d||{},S(e,{isBrowser:A,toUrl:function(a){var d,e=a.lastIndexOf("."),f=a.split("/")[0];return-1!==e&&("."!==f&&".."!==f||e>1)&&(d=a.substring(e,a.length),a=a.substring(0,e)),w.nameToUrl(b(a,c&&c.id,!0),d,!0)},defined:function(a){return t(I,f(a,c,!1,!0).id)},specified:function(a){return a=f(a,c,!1,!0).id,t(I,a)||t(D,a)}}),c||(e.undef=function(a){k();var b=f(a,c,!0),d=m(D,a);delete I[a],delete L[b.url],delete F[a],d&&(d.events.defined&&(F[a]=d.events),l(a))}),e},enable:function(a){m(D,a.id)&&g(a).enable()},completeLoad:function(a){var b,c,e=m(C.shim,a)||{},f=e.exports;for(k();G.length;){if(c=G.shift(),null===c[0]){if(c[0]=a,b)break;b=!0}else c[0]===a&&(b=!0);p(c)}if(c=m(D,a),!b&&!t(I,a)&&c&&!c.inited){if(C.enforceDefine&&(!f||!da(f)))return d(a)?void 0:j(B("nodefine","No define call for "+a,null,[a]));p([a,e.deps||[],e.exportsFn])}o()},nameToUrl:function(a,b,c){var d,e,f,g,i,j;if(h.jsExtRegExp.test(a))g=a+(b||"");else{for(d=C.paths,e=C.pkgs,g=a.split("/"),i=g.length;i>0;i-=1){if(j=g.slice(0,i).join("/"),f=m(e,j),j=m(d,j)){K(j)&&(j=j[0]),g.splice(0,i,j);break}if(f){a=a===f.name?f.location+"/"+f.main:f.location,g.splice(0,i,a);break}}g=g.join("/"),g+=b||(/\?/.test(g)||c?"":".js"),g=("/"===g.charAt(0)||g.match(/^[\w\+\.\-]+:/)?"":C.baseUrl)+g}return C.urlArgs?g+((-1===g.indexOf("?")?"?":"&")+C.urlArgs):g},load:function(a,b){h.load(w,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){("load"===a.type||la.test((a.currentTarget||a.srcElement).readyState))&&(R=null,a=q(a),w.completeLoad(a.id))},onScriptError:function(a){var b=q(a);return d(b.id)?void 0:j(B("scripterror","Script error for: "+b.id,a,[b.id]))}},w.require=w.makeRequire(),w}var h,x,y,E,L,F,R,M,s,ga,ma=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/gm,na=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,fa=/\.js$/,ka=/^\.\//;x=Object.prototype;var N=x.toString,ha=x.hasOwnProperty,ja=Array.prototype.splice,A=!("undefined"==typeof window||!navigator||!window.document),ea=!A&&"undefined"!=typeof importScripts,la=A&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,Z="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),G={},u={},U=[],Q=!1;if("undefined"==typeof define){if("undefined"!=typeof requirejs){if(J(requirejs))return;u=requirejs,requirejs=void 0}"undefined"!=typeof require&&!J(require)&&(u=require,require=void 0),h=requirejs=function(a,b,c,d){var e,f="_";return!K(a)&&"string"!=typeof a&&(e=a,K(b)?(a=b,b=c,c=d):a=[]),e&&e.context&&(f=e.context),(d=m(G,f))||(d=G[f]=h.s.newContext(f)),e&&d.configure(e),d.require(a,b,c)},h.config=function(a){return h(a)},h.nextTick="undefined"!=typeof setTimeout?function(a){setTimeout(a,4)}:function(a){a()},require||(require=h),h.version="2.1.6",h.jsExtRegExp=/^\/|:|\?|\.js$/,h.isBrowser=A,x=h.s={contexts:G,newContext:ia},h({}),z(["toUrl","undef","defined","specified"],function(a){h[a]=function(){var b=G._;return b.require[a].apply(b,arguments)}}),A&&(y=x.head=document.getElementsByTagName("head")[0],E=document.getElementsByTagName("base")[0])&&(y=x.head=E.parentNode),h.onError=ca,h.load=function(a,b,c){var d,e=a&&a.config||{};if(A)return d=e.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),d.type=e.scriptType||"text/javascript",d.charset="utf-8",d.async=!0,d.setAttribute("data-requirecontext",a.contextName),d.setAttribute("data-requiremodule",b),!d.attachEvent||d.attachEvent.toString&&0>d.attachEvent.toString().indexOf("[native code")||Z?(d.addEventListener("load",a.onScriptLoad,!1),d.addEventListener("error",a.onScriptError,!1)):(Q=!0,d.attachEvent("onreadystatechange",a.onScriptLoad)),d.src=c,M=d,E?y.insertBefore(d,E):y.appendChild(d),M=null,d;if(ea)try{importScripts(c),a.completeLoad(b)}catch(f){a.onError(B("importscripts","importScripts failed for "+b+" at "+c,f,[b]))}},A&&O(document.getElementsByTagName("script"),function(a){return y||(y=a.parentNode),(L=a.getAttribute("data-main"))?(s=L,u.baseUrl||(F=s.split("/"),s=F.pop(),ga=F.length?F.join("/")+"/":"./",u.baseUrl=ga),s=s.replace(fa,""),h.jsExtRegExp.test(s)&&(s=L),u.deps=u.deps?u.deps.concat(s):[s],!0):void 0}),define=function(a,b,c){var d,e;"string"!=typeof a&&(c=b,b=a,a=null),K(b)||(c=b,b=null),!b&&J(c)&&(b=[],c.length&&(c.toString().replace(ma,"").replace(na,function(a,c){b.push(c)}),b=(1===c.length?["require"]:["require","exports","module"]).concat(b))),Q&&((d=M)||(R&&"interactive"===R.readyState||O(document.getElementsByTagName("script"),function(a){return"interactive"===a.readyState?R=a:void 0}),d=R),d&&(a||(a=d.getAttribute("data-requiremodule")),e=G[d.getAttribute("data-requirecontext")])),(e?e.defQueue:U).push([a,b,c])},define.amd={jQuery:!0},h.exec=function(b){return eval(b)},h(u)}}(this)}WebGLDebugUtils=function(){function a(a){if(null==m){m={};for(var b in a)"number"==typeof a[b]&&(m[a[b]]=b)}}function b(){if(null==m)throw"WebGLDebugUtils.init(ctx) not called"}function c(a){return b(),void 0!==m[a]}function d(a){b();var c=m[a];return void 0!==c?c:"*UNKNOWN WebGL ENUM (0x"+a.toString(16)+")"}function e(a,b,c){var e=l[a];return void 0!==e&&e[b]?d(c):null===c?"null":void 0===c?"undefined":c.toString()}function f(a,b){for(var c="",d=0;dd;++d)a.disableVertexAttribArray(d),a.vertexAttribPointer(d,4,a.FLOAT,!1,0,0),a.vertexAttrib1f(d,0);a.deleteBuffer(c);for(var e=a.getParameter(a.MAX_TEXTURE_IMAGE_UNITS),d=0;e>d;++d)a.activeTexture(a.TEXTURE0+d),a.bindTexture(a.TEXTURE_CUBE_MAP,null),a.bindTexture(a.TEXTURE_2D,null);for(a.activeTexture(a.TEXTURE0),a.useProgram(null),a.bindBuffer(a.ARRAY_BUFFER,null),a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,null),a.bindFramebuffer(a.FRAMEBUFFER,null),a.bindRenderbuffer(a.RENDERBUFFER,null),a.disable(a.BLEND),a.disable(a.CULL_FACE),a.disable(a.DEPTH_TEST),a.disable(a.DITHER),a.disable(a.SCISSOR_TEST),a.blendColor(0,0,0,0),a.blendEquation(a.FUNC_ADD),a.blendFunc(a.ONE,a.ZERO),a.clearColor(0,0,0,0),a.clearDepth(1),a.clearStencil(-1),a.colorMask(!0,!0,!0,!0),a.cullFace(a.BACK),a.depthFunc(a.LESS),a.depthMask(!0),a.depthRange(0,1),a.frontFace(a.CCW),a.hint(a.GENERATE_MIPMAP_HINT,a.DONT_CARE),a.lineWidth(1),a.pixelStorei(a.PACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_ALIGNMENT,4),a.pixelStorei(a.UNPACK_FLIP_Y_WEBGL,!1),a.pixelStorei(a.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),a.UNPACK_COLORSPACE_CONVERSION_WEBGL&&a.pixelStorei(a.UNPACK_COLORSPACE_CONVERSION_WEBGL,a.BROWSER_DEFAULT_WEBGL),a.polygonOffset(0,0),a.sampleCoverage(1,!1),a.scissor(0,0,a.canvas.width,a.canvas.height),a.stencilFunc(a.ALWAYS,0,4294967295),a.stencilMask(4294967295),a.stencilOp(a.KEEP,a.KEEP,a.KEEP),a.viewport(0,0,a.canvas.width,a.canvas.height),a.clear(a.COLOR_BUFFER_BIT|a.DEPTH_BUFFER_BIT|a.STENCIL_BUFFER_BIT);a.getError(););}function j(a){function b(a){return"function"==typeof a?a:function(b){a.handleEvent(b)}}function c(a){var b=a.addEventListener;a.addEventListener=function(c,d,e){switch(c){case"webglcontextlost":x(d);break;case"webglcontextrestored":y(d);break;default:b.apply(a,arguments)}}}function d(){for(var a=Object.keys(w),b=0;b=0&&setTimeout(function(){a.restoreContext()},v)},0)}},a.restoreContext=function(){q&&o.length&&setTimeout(function(){if(!u)throw"can not restore. webglcontestlost listener did not call event.preventDefault";h(),i(l),q=!1,t=0,u=!1;for(var a=o.slice(),b=j("context restored"),c=0;c0)return!1;if(0===b.length)return!0;for(var c in b)if(a.call(b,c))return!1;return!0},this.reset=function(){var a=[];for(var b in this._engines)this._engines.hasOwnProperty(b)&&(a.push(this._engines[b]),delete this._engines[b],this._engineIds.removeItem(b));for(;a.length>0;)a.pop().destroy();SceneJS_events.fireEvent(SceneJS_events.RESET)}};!function(){var a;SceneJS.on("configs",function(b){if(b.pluginPath!=a){a=b.pluginPath;var c=a+"/lib";require.config({paths:{scenejsPluginDeps:c}})}})}();var SceneJS_eventManager=function(){this._handlerIds=new SceneJS_Map,this.typeHandlers={}};SceneJS_eventManager.prototype.createEvent=function(a){this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0})},SceneJS_eventManager.prototype.onEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0}),d=this._handlerIds.addItem(a),e=c.handlers;return e[d]=b,c.numSubs++,d},SceneJS_eventManager.prototype.fireEvent=function(a,b){var c=this.typeHandlers[a]||(this.typeHandlers[a]={handlers:{},numSubs:0});if(c.numSubs>0){var d=c.handlers;for(var e in d)d.hasOwnProperty(e)&&d[e](b)}},SceneJS_eventManager.prototype.unEvent=function(a){var b=this._handlerIds.items[a];if(b){this._handlerIds.removeItem(a);var c=this.typeHandlers[b];c&&(delete c[a],this.typeHandlers[b].numSubs--)}},SceneJS.Plugins=new function(){function a(a,c,f,g){var h=d[a]||(d[a]={});h[c]=g,b(f,0,function(){for(var b=a+c,d=e[b]||(e[b]=[]);d.length>0;)d.pop()(g);delete e[b]})}function b(a,d,e){if(!a||d>=a.length)return void e();var f=a[d],g=SceneJS_configsModule.configs.pluginPath;if(!g)throw"no pluginPath config";f=g+"/"+f,c(f,function(){b(a,d+1,e)})}function c(a,b){var c=document.createElement("script");c.type="text/javascript",c.readyState?c.onreadystatechange=function(){("loaded"==c.readyState||"complete"==c.readyState)&&(c.onreadystatechange=null,b&&b())}:c.onload=function(){b&&b()},c.src=a,document.getElementsByTagName("head")[0].appendChild(c)}var d={},e={};this.addPlugin=function(){var b,c,d=arguments[0],e=arguments[1];4==arguments.length?(b=arguments[2],c=arguments[3]):c=arguments[2],a(d,e,b,c)},this.hasPlugin=function(a,b){var c=d[a];return c&&!!c[b]},this.getPlugin=function(a,b,f){var g=d[a];if(g){var h=g[b];if(h)return void f(h)}var i=a+b,j=e[i]||(e[i]=[]);if(j.push(f),!(j.length>1)){var k=SceneJS_configsModule.configs.pluginPath;if(!k)throw"no pluginPath config";var l=k+"/"+a+"/"+b+".js";c(l)}}};var SceneJS_events=new function(){this.ERROR=0,this.RESET=1,this.NODE_CREATED=2,this.SCENE_CREATED=3,this.SCENE_COMPILING=4,this.SCENE_DESTROYED=5,this.OBJECT_COMPILING=6,this.WEBGL_CONTEXT_LOST=7,this.WEBGL_CONTEXT_RESTORED=8;var a=[];this.addListener=function(b,c,d){var e=a[b];e||(e=[],a[b]=e);for(var f={command:c,priority:void 0==d?e.length:d},g=-1,h=0,i=e.length;i>h;h++)if(!e[h]){g=h;break}0>g&&(e.push(f),g=e.length-1);var j=b+"."+g;return j},this.removeListener=function(b){var c=b.lastIndexOf("."),d=parseInt(b.substr(0,c)),e=parseInt(b.substr(c+1)),f=a[d];f&&delete f[e]},this.fireEvent=function(b,c){var d=a[b];if(d){c=c||{};for(var e=0;e',e.appendChild(f)}var h=document.getElementById(b);if(!h)throw SceneJS_error.fatalError(SceneJS.errors.CANVAS_NOT_FOUND,"SceneJS.Scene attribute 'canvasId' does not match any elements in the page");this.canvasId=b,this.options=d||{},this.canvas=this.options.simulateWebGLContextLost?WebGLDebugUtils.makeLostContextSimulatingCanvas(h):h,this.ssaaMultiplier=this.options.ssaaMultiplier||1,this.canvas.width=this.canvas.clientWidth*this.ssaaMultiplier,this.canvas.height=this.canvas.clientHeight*this.ssaaMultiplier,this.contextAttr=c,this.gl=null,this.initWebGL()};SceneJS_Canvas.prototype._WEBGL_CONTEXT_NAMES=["webgl","experimental-webgl","webkit-3d","moz-webgl","moz-glweb20"],SceneJS_Canvas.prototype.initWebGL=function(){for(var a=0;!this.gl&&af;f++)d.createNode(a.nodes[f],function(a){c.addNode(a),++e==g&&(b&&b(c),d.scene.publish("nodes/"+c.id,c))});else b&&(b(c),d.scene.publish("nodes/"+c.id,c))})},SceneJS_Engine.prototype._doDestroyNodes=function(){for(var a;this._numNodesToDestroy>0;)a=this._nodesToDestroy[--this._numNodesToDestroy],a._doDestroy(),this._coreFactory.putCore(a._core),this._nodeFactory.putNode(a)},SceneJS_Engine.prototype.findNode=function(a){return this._nodeFactory.nodes.items[a]},SceneJS_Engine.prototype.findNodes=function(a){var b=new RegExp(a),c=[],d=this._nodeFactory.nodes.items;for(var e in d)d.hasOwnProperty(e)&&b.test(e)&&c.push(d[e]);return c},SceneJS_Engine.prototype.hasCore=function(a,b){return this._coreFactory.hasCore(a,b)},SceneJS_Engine.prototype.branchDirty=function(a){if(!this.sceneDirty&&a!=window){a.branchDirty=!0,a.dirty=!0;for(var b=a.parent;b&&!b.dirty&&!b.branchDirty;b=b.parent)b.dirty=!0;this._sceneBranchesDirty=!0}},SceneJS_Engine.prototype.renderFrame=function(a){var b=!1;if(this._needCompile()||a&&a.force)for(var c=(new Date).getTime(),d=a&&a.force,e=0;e0?setTimeout(window[e],1e3/d.fps):requestAnimationFrame(window[e]))},setTimeout(window[e],0)}},SceneJS_Engine.prototype.pick=function(a,b,c){this._needCompile()&&this._doCompile();var d=this.display.pick({canvasX:a,canvasY:b,rayPick:c?c.rayPick:!1});return d},SceneJS_Engine.prototype.readPixels=function(a,b){return this._needCompile()&&this._doCompile(),this.display.readPixels(a,b)},SceneJS_Engine.prototype._needCompile=function(){return this.display.imageDirty||this.display.drawListDirty||this.display.stateSortDirty||this.display.stateOrderDirty||this.display.objectListDirty||this._sceneBranchesDirty||this.sceneDirty},SceneJS_Engine.prototype._doCompile=function(){if(this._sceneBranchesDirty||this.sceneDirty){this._sceneBranchesDirty=!1,SceneJS_events.fireEvent(SceneJS_events.SCENE_COMPILING,{engine:this}),this.pubSubProxy=new SceneJS_PubSubProxy(this.scene,null);var a={pubSubProxy:this.pubSubProxy};this.scene._compileNodes(a),this.sceneDirty=!1}this._doDestroyNodes()},SceneJS_Engine.prototype.pause=function(a){this.paused=a},SceneJS_Engine.prototype.stop=function(){this.running&&(this.running=!1,this.paused=!1,window["__scenejs_sceneLoop"+this.id]=null)},SceneJS_Engine.prototype.destroyNode=function(a){this._nodesToDestroy[this._numNodesToDestroy++]=a;var b=this.sceneStatus.nodes[a.id];b&&(this.sceneStatus.numTasks-=b.numTasks,delete this.sceneStatus.nodes[a.id])},SceneJS_Engine.prototype.destroy=function(){this.destroyed=!0},self.Int32Array||(self.Int32Array=Array,self.Float32Array=Array),function(){for(var a=0,b=["ms","moz","webkit","o"],c=0;ch;h++)i[h](g);SceneJS.publish("configs",this.configs)},this.getConfigs=function(a){if(a){for(var b=this.configs,c=a.split("."),d=0;b&&dc;c++)b.push("----");e=b.join("")},this.error=function(a){this._log("error",a)},this.warn=function(a){this._log("warn",a)},this.info=function(a){this._log("info",a)},this.debug=function(a){this._log("debug",a)},this.setFuncs=function(a){if(a){b=a;for(var d in c)this._flush(d)}},this._flush=function(a){var d=c[a];if(d){var e=b?b[a]:null;if(e){for(var f=0;fy;++y)f=b[y],c=f[0],d=f[1],e=f[2],g[y]=[i*c+m*d+q*e+u,j*c+n*d+r*e+v,k*c+o*d+s*e+w,l*c+p*d+t*e+x];return g},SceneJS_math_transformVector3=function(a,b){var c=b[0],d=b[1],e=b[2];return[a[0]*c+a[4]*d+a[8]*e,a[1]*c+a[5]*d+a[9]*e,a[2]*c+a[6]*d+a[10]*e]},SceneJS_math_transformVector4=function(a,b){var c=b[0],d=b[1],e=b[2],f=b[3];return[a[0]*c+a[4]*d+a[8]*e+a[12]*f,a[1]*c+a[5]*d+a[9]*e+a[13]*f,a[2]*c+a[6]*d+a[10]*e+a[14]*f,a[3]*c+a[7]*d+a[11]*e+a[15]*f]},SceneJS_math_projectVec4=function(a){var b=1/a[3];return[a[0]*b,a[1]*b,a[2]*b,1]},SceneJS_math_Plane3=function(a,b,c){if(this.normal=[0,0,1],this.offset=0,a&&b){var d=a[0],e=a[1],f=a[2];if(this.offset=b,c){var g=Math.sqrt(d*d+e*e+f*f);g>0&&(g=1/g,this.normal[0]=d*g,this.normal[1]=e*g,this.normal[2]=f*g,this.offset*=g)}}},SceneJS_math_MAX_DOUBLE=Number.POSITIVE_INFINITY,SceneJS_math_MIN_DOUBLE=Number.NEGATIVE_INFINITY,SceneJS_math_Box3=function(a,b){this.min=a||[SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE,SceneJS_math_MAX_DOUBLE],this.max=b||[SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE,SceneJS_math_MIN_DOUBLE],this.init=function(a,b){return this.min[0]=a[0],this.min[1]=a[1],this.min[2]=a[2],this.max[0]=b[0],this.max[1]=b[1],this.max[2]=b[2],this},this.fromPoints=function(a){for(var b=a.length,c=0;b>c;++c){var d=a[c][3],e=a[c][0]/d,f=a[c][1]/d,g=a[c][2]/d;ethis.max[0]&&(this.max[0]=e),f>this.max[1]&&(this.max[1]=f),g>this.max[2]&&(this.max[2]=g)}return this},this.isEmpty=function(){return this.min[0]>=this.max[0]&&this.min[1]>=this.max[1]&&this.min[2]>=this.max[2]},this.getCenter=function(){return[(this.max[0]+this.min[0])/2,(this.max[1]+this.min[1])/2,(this.max[2]+this.min[2])/2]},this.getSize=function(){return[this.max[0]-this.min[0],this.max[1]-this.min[1],this.max[2]-this.min[2]]},this.getFacesAreas=function(){var a=this.size;return[a[1]*a[2],a[0]*a[2],a[0]*a[1]]},this.getSurfaceArea=function(){var a=this.getFacesAreas();return 2*(a[0]+a[1]+a[2])},this.getVolume=function(){var a=this.size;return a[0]*a[1]*a[2]},this.getOffset=function(a){return this.min[0]-=a,this.min[1]-=a,this.min[2]-=a,this.max[0]+=a,this.max[1]+=a,this.max[2]+=a,this}},SceneJS_math_AxisBox3=function(a,b){var c=a[0],d=a[1],e=a[2],f=b[0],g=b[1],h=b[2];this.verts=[[c,d,e],[f,d,e],[f,g,e],[c,g,e],[c,d,h],[f,d,h],[f,g,h],[c,g,h]],this.toBox3=function(){for(var a=new SceneJS_math_Box3,b=0;8>b;++b)for(var c=this.verts[b],d=0;3>d;++d)c[d]a.max[d]&&(a.max[d]=c[d])}},SceneJS_math_Sphere3=function(a,b){this.center=[a[0],a[1],a[2]],this.radius=b,this.isEmpty=function(){return 0===this.radius},this.surfaceArea=function(){return 4*Math.PI*this.radius*this.radius},this.getVolume=function(){var a=this.radius;return 4/3*Math.PI*a*a*a}},SceneJS_math_billboardMat=function(a){var b=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],c=[SceneJS_math_lenVec4(b[0]),SceneJS_math_lenVec4(b[1]),SceneJS_math_lenVec4(b[2])],d=SceneJS_math_mat4();SceneJS_math_rcpVec3(c,d);var e=SceneJS_math_scalingMat4v(c);SceneJS_math_mulVec4Scalar(b[0],d[0]),SceneJS_math_mulVec4Scalar(b[1],d[1]),SceneJS_math_mulVec4Scalar(b[2],d[2]);var f=SceneJS_math_identityMat4();return SceneJS_math_setRowMat4(f,0,b[0]),SceneJS_math_setRowMat4(f,1,b[1]),SceneJS_math_setRowMat4(f,2,b[2]),SceneJS_math_mulMat4(f,e)},SceneJS_math_FrustumPlane=function(a,b,c,d){var e=1/Math.sqrt(a*a+b*b+c*c);this.normal=[a*e,b*e,c*e],this.offset=d*e,this.testVertex=[this.normal[0]>=0?1:0,this.normal[1]>=0?1:0,this.normal[2]>=0?1:0]},SceneJS_math_OUTSIDE_FRUSTUM=3,SceneJS_math_INTERSECT_FRUSTUM=4,SceneJS_math_INSIDE_FRUSTUM=5,SceneJS_math_Frustum=function(a,b,c){var d=SceneJS_math_mat4();SceneJS_math_mulMat4(b,a,d);var e=d[0],f=d[1],g=d[2],h=d[3],i=d[4],j=d[5],k=d[6],l=d[7],m=d[8],n=d[9],o=d[10],p=d[11],q=d[12],r=d[13],s=d[14],t=d[15],u=[new SceneJS_math_FrustumPlane(h-e,l-i,p-m,t-q),new SceneJS_math_FrustumPlane(h+e,l+i,p+m,t+q),new SceneJS_math_FrustumPlane(h-f,l-j,p-n,t-r),new SceneJS_math_FrustumPlane(h+f,l+j,p+n,t+r),new SceneJS_math_FrustumPlane(h-g,l-k,p-o,t-s),new SceneJS_math_FrustumPlane(h+g,l+k,p+o,t+s)],v=[SceneJS_math_getColMat4(a,0),SceneJS_math_getColMat4(a,1),SceneJS_math_getColMat4(a,2)],w=[SceneJS_math_lenVec4(v[0]),SceneJS_math_lenVec4(v[1]),SceneJS_math_lenVec4(v[2])],x=SceneJS_math_rcpVec3(w),y=SceneJS_math_scalingMat4v(w),z=SceneJS_math_scalingMat4v(x);SceneJS_math_mulVec4Scalar(v[0],x[0]),SceneJS_math_mulVec4Scalar(v[1],x[1]),SceneJS_math_mulVec4Scalar(v[2],x[2]);var A=SceneJS_math_identityMat4();SceneJS_math_setRowMat4(A,0,v[0]),SceneJS_math_setRowMat4(A,1,v[1]),SceneJS_math_setRowMat4(A,2,v[2]),this.matrix||(this.matrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(b,a,this.matrix),this.billboardMatrix||(this.billboardMatrix=SceneJS_math_mat4()),SceneJS_math_mulMat4(z,SceneJS_math_mulMat4(A,y),this.billboardMatrix),this.viewport=c.slice(0,4),this.textAxisBoxIntersection=function(a){for(var b=SceneJS_math_INSIDE_FRUSTUM,c=[a.min,a.max],d=null,e=0;6>e;++e){if(d=u[e],d.normal[0]*c[d.testVertex[0]][0]+d.normal[1]*c[d.testVertex[1]][1]+d.normal[2]*c[d.testVertex[2]][2]+d.offset<0)return SceneJS_math_OUTSIDE_FRUSTUM;d.normal[0]*c[1-d.testVertex[0]][0]+d.normal[1]*c[1-d.testVertex[1]][1]+d.normal[2]*c[1-d.testVertex[2]][2]+d.offset<0&&(b=SceneJS_math_INTERSECT_FRUSTUM)}return b},this.getProjectedSize=function(a){var b=SceneJS_math_mat4();SceneJS_math_subVec3(a.max,a.min,b);var d=SceneJS_math_lenVec3(b),e=Math.abs(d),f=[.5*(a.min[0]+a.max[0]),.5*(a.min[1]+a.max[1]),.5*(a.min[2]+a.max[2]),0],g=.5*e,h=[-g,0,0,1],i=[g,0,0,1];return h=SceneJS_math_mulMat4v4(this.billboardMatrix,h),h=SceneJS_math_addVec4(h,f),h=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,h)),i=SceneJS_math_mulMat4v4(this.billboardMatrix,i),i=SceneJS_math_addVec4(i,f),i=SceneJS_math_projectVec4(SceneJS_math_mulMat4v4(this.matrix,i)),c[2]*Math.abs(i[0]-h[0])},this.getProjectedState=function(a){for(var b,d,e,f=SceneJS_math_transformPoints3(this.matrix,a),g=1e7,h=1e7,i=-1e7,j=-1e7,k=f.length,l=0;k>l;++l)b=SceneJS_math_projectVec4(f[l]),d=b[0],e=b[1],-.5>d&&(d=-.5),-.5>e&&(e=-.5),d>.5&&(d=.5),e>.5&&(e=.5),g>d&&(g=d),h>e&&(h=e),d>i&&(i=d),e>j&&(j=e);g+=.5,h+=.5,i+=.5,j+=.5;var m=c[2],n=c[3];g*=m+15,h*=n+15,i*=m+15,j*=n+15;var o=SceneJS_math_mat4();SceneJS_math_subVec2([i,j],[g,h],o);var p=SceneJS_math_lenVec2(o);return 0>g&&(g=0),i>m&&(i=m),0>h&&(h=0),j>n&&(j=n),{canvasBox:{min:[g,h],max:[i,j]},canvasSize:p}}},SceneJS_math_identityQuaternion=function(){return[0,0,0,1]},SceneJS_math_angleAxisQuaternion=function(a,b,c,d){var e=d/180*Math.PI,f=e/2,g=Math.sin(f);return[g*a,g*b,g*c,Math.cos(f)]},SceneJS_math_mulQuaternions=function(a,b){var c=a[0],d=a[1],e=a[2],f=a[3],g=b[0],h=b[1],i=b[2],j=b[3];return[f*g+c*j+d*i-e*h,f*h+d*j+e*g-c*i,f*i+e*j+c*h-d*g,f*j-c*g-d*h-e*i]},SceneJS_math_newMat4FromQuaternion=function(a){var b=a[0],c=a[1],d=a[2],e=a[3],f=2*b,g=2*c,h=2*d,i=f*e,j=g*e,k=h*e,l=f*b,m=g*b,n=h*b,o=g*c,p=h*c,q=h*d,r=SceneJS_math_identityMat4();return SceneJS_math_setCellMat4(r,0,0,1-(o+q)),SceneJS_math_setCellMat4(r,0,1,m-k),SceneJS_math_setCellMat4(r,0,2,n+j),SceneJS_math_setCellMat4(r,1,0,m+k),SceneJS_math_setCellMat4(r,1,1,1-(l+q)),SceneJS_math_setCellMat4(r,1,2,p-i),SceneJS_math_setCellMat4(r,2,0,n-j),SceneJS_math_setCellMat4(r,2,1,p+i),SceneJS_math_setCellMat4(r,2,2,1-(l+o)),r},SceneJS_math_slerp=function(a,b,c){var d=.0174532925*b[3],e=.0174532925*c[3],f=d*e+b[0]*c[0]+b[1]*c[1]+b[2]*c[2];if(Math.abs(f)>=1)return[b[0],b[1],b[2],b[3]];var g=Math.acos(f),h=Math.sqrt(1-f*f);if(Math.abs(h)<.001)return[.5*b[0]+.5*c[0],.5*b[1]+.5*c[1],.5*b[2]+.5*c[2],.5*b[3]+.5*c[3]];var i=Math.sin((1-a)*g)/h,j=Math.sin(a*g)/h;return[b[0]*i+c[0]*j,b[1]*i+c[1]*j,b[2]*i+c[2]*j,57.295779579*(d*i+e*j)]},SceneJS_math_normalizeQuaternion=function(a){var b=SceneJS_math_lenVec4([a[0],a[1],a[2],a[3]]);return[a[0]/b,a[1]/b,a[2]/b,a[3]/b]},SceneJS_math_conjugateQuaternion=function(a){return[-a[0],-a[1],-a[2],a[3]]},SceneJS_math_angleAxisFromQuaternion=function(a){a=SceneJS_math_normalizeQuaternion(a);var b=a[3],c=2*Math.acos(b),d=Math.sqrt(1-b*b);return.001>d?{x:a[0],y:a[1],z:a[2],angle:57.295779579*c}:{x:a[0]/d,y:a[1]/d,z:a[2]/d,angle:57.295779579*c}},SceneJS_sceneStatusModule=new function(){function a(a){var b=document.getElementsByTagName("body")[0],c=document.createElement("div"),d=c.style;return d.position="absolute",d.width="200px",d.right="10px",d.top="0",d.padding="10px",d["z-index"]="10000",b.appendChild(c),c}function b(a,b){var c=document.createElement("div"),d=c.style;return d["font-family"]="Helvetica",d["font-size"]="14px",d.padding="5px",d.margin="4px",d["padding-left"]="12px",d.border="1px solid #000055",d.color="black",d.background="#AAAAAA",d.opacity="0.8",d["border-radius"]="3px",d["-moz-border-radius"]="3px",d["box-shadow"]="3px 3px 3px #444444",c.innerHTML=b,a.appendChild(c),c}function c(a){a.style.background="#AAFFAA";var b=.8,c=setInterval(function(){0>=b?(a.parentNode.removeChild(a),clearInterval(c)):(a.style.opacity=b,b-=.1)},100)}function d(a){a.style.background="#FFAAAA"}this.sceneStatus={};var e=new SceneJS_Map,f={},g={},h=this;SceneJS_events.addListener(SceneJS_events.SCENE_DESTROYED,function(a){var b=a.engine.id;delete h.sceneStatus[b],delete g[b]}),this.taskStarted=function(c,d){var h=SceneJS_configsModule.configs.statusPopups!==!1,i=c.getScene(),j=i.getId(),k=c.getId(),l=i.getCanvas(),m=e.addItem(),n=this.sceneStatus[j];n||(n=this.sceneStatus[j]={numTasks:0}),n.numTasks++;var o=g[j];o||(o=g[j]={sceneId:j,nodeStates:{},scene:i,popupContainer:h?a(l):null,descCounts:{}});var p=o.descCounts[d];void 0==p&&(p=o.descCounts[d]=0),o.descCounts[d]++;var q=o.nodeStates[k];q||(q=o.nodeStates[k]={nodeId:k,numTasks:0,tasks:{}}),d=d+" "+o.descCounts[d]+"...",q.numTasks++;var r={sceneState:o,nodeState:q,description:d,element:h?b(o.popupContainer,d):null};return q.tasks[m]=r,f[m]=r,m},this.taskFinished=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var d=b.sceneState;this.sceneStatus[d.sceneId].numTasks--,b.element&&c(b.element);var e=b.nodeState;return--e.numTasks<0&&(e.numTasks=0),delete e.tasks[a],0==e.numTasks&&delete d.nodeStates[e.nodeId],null},this.taskFailed=function(a){if(-1==a||null==a)return null;var b=f[a];if(!b)return null;var c=!!SceneJS_configsModule.configs.statusPopups,e=b.sceneState;this.sceneStatus[e.sceneId].numTasks--,c&&d(b.element);var g=b.nodeState;return g.numTasks--,delete g.tasks[a],0==g.numTasks&&delete b.sceneState.nodeStates[g.nodeId],null}};SceneJS._webgl={},SceneJS._webgl.ArrayBuffer=function(a,b,c,d,e,f){this.allocated=!1,this.gl=a,this.type=b, this.numItems=d,this.itemSize=e,this.usage=f,this._allocate(c,d)},SceneJS._webgl.ArrayBuffer.prototype._allocate=function(a,b){if(this.allocated=!1,this.handle=this.gl.createBuffer(),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to allocate WebGL ArrayBuffer");this.handle&&(this.gl.bindBuffer(this.type,this.handle),this.gl.bufferData(this.type,a,this.usage),this.gl.bindBuffer(this.type,null),this.numItems=b,this.length=a.length,this.allocated=!0)},SceneJS._webgl.ArrayBuffer.prototype.setData=function(a,b){this.allocated&&(a.length>this.length?(this.destroy(),this._allocate(a,a.length)):b||0===b?this.gl.bufferSubData(this.type,b,a):this.gl.bufferData(this.type,a))},SceneJS._webgl.ArrayBuffer.prototype.unbind=function(){this.allocated&&this.gl.bindBuffer(this.type,null)},SceneJS._webgl.ArrayBuffer.prototype.destroy=function(){this.allocated&&(this.gl.deleteBuffer(this.handle),this.handle=null,this.allocated=!1)},SceneJS._webgl.ArrayBuffer.prototype.bind=function(){this.allocated&&this.gl.bindBuffer(this.type,this.handle)},SceneJS._webgl.Attribute=function(a,b,c,d,e,f){this.gl=a,this.location=f,this.bindFloatArrayBuffer=function(b){b&&(b.bind(),a.enableVertexAttribArray(f),a.vertexAttribPointer(f,b.itemSize,a.FLOAT,!1,0,0))}},SceneJS._webgl.Attribute.prototype.bindInterleavedFloatArrayBuffer=function(a,b,c){this.gl.enableVertexAttribArray(this.location),this.gl.vertexAttribPointer(this.location,a,this.gl.FLOAT,!1,b,c)},SceneJS._webgl.enumMap={funcAdd:"FUNC_ADD",funcSubtract:"FUNC_SUBTRACT",funcReverseSubtract:"FUNC_REVERSE_SUBTRACT",zero:"ZERO",one:"ONE",srcColor:"SRC_COLOR",oneMinusSrcColor:"ONE_MINUS_SRC_COLOR",dstColor:"DST_COLOR",oneMinusDstColor:"ONE_MINUS_DST_COLOR",srcAlpha:"SRC_ALPHA",oneMinusSrcAlpha:"ONE_MINUS_SRC_ALPHA",dstAlpha:"DST_ALPHA",oneMinusDstAlpha:"ONE_MINUS_DST_ALPHA",contantColor:"CONSTANT_COLOR",oneMinusConstantColor:"ONE_MINUS_CONSTANT_COLOR",constantAlpha:"CONSTANT_ALPHA",oneMinusConstantAlpha:"ONE_MINUS_CONSTANT_ALPHA",srcAlphaSaturate:"SRC_ALPHA_SATURATE",front:"FRONT",back:"BACK",frontAndBack:"FRONT_AND_BACK",never:"NEVER",less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL",always:"ALWAYS",cw:"CW",ccw:"CCW",linear:"LINEAR",nearest:"NEAREST",linearMipMapNearest:"LINEAR_MIPMAP_NEAREST",nearestMipMapNearest:"NEAREST_MIPMAP_NEAREST",nearestMipMapLinear:"NEAREST_MIPMAP_LINEAR",linearMipMapLinear:"LINEAR_MIPMAP_LINEAR",repeat:"REPEAT",clampToEdge:"CLAMP_TO_EDGE",mirroredRepeat:"MIRRORED_REPEAT",alpha:"ALPHA",rgb:"RGB",rgba:"RGBA",luminance:"LUMINANCE",luminanceAlpha:"LUMINANCE_ALPHA",textureBinding2D:"TEXTURE_BINDING_2D",textureBindingCubeMap:"TEXTURE_BINDING_CUBE_MAP",compareRToTexture:"COMPARE_R_TO_TEXTURE",unsignedByte:"UNSIGNED_BYTE"},SceneJS._webgl.RenderBuffer=function(a){this.allocated=!1,this.canvas=a.canvas,this.gl=a.canvas.gl,this.buf=null,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.webglRestored=function(a){this.gl=a,this.buf=null,this.allocated=!1,this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.bind=function(){this._touch(),this.bound||(this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.bound=!0)},SceneJS._webgl.RenderBuffer.prototype._touch=function(){var a=this.canvas.canvas.width,b=this.canvas.canvas.height;if(this.buf){if(this.buf.width==a&&this.buf.height==b)return;this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf)}this.buf={framebuf:this.gl.createFramebuffer(),renderbuf:this.gl.createRenderbuffer(),texture:this.gl.createTexture(),width:a,height:b},this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),this.gl.bindTexture(this.gl.TEXTURE_2D,this.buf.texture),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,this.gl.NEAREST),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE);try{this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,null)}catch(c){var d=new WebGLUnsignedByteArray(a*b*3);this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,a,b,0,this.gl.RGBA,this.gl.UNSIGNED_BYTE,d)}if(this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.renderbufferStorage(this.gl.RENDERBUFFER,this.gl.DEPTH_COMPONENT16,a,b),this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER,this.gl.COLOR_ATTACHMENT0,this.gl.TEXTURE_2D,this.buf.texture,0),this.gl.framebufferRenderbuffer(this.gl.FRAMEBUFFER,this.gl.DEPTH_ATTACHMENT,this.gl.RENDERBUFFER,this.buf.renderbuf),this.gl.bindTexture(this.gl.TEXTURE_2D,null),this.gl.bindRenderbuffer(this.gl.RENDERBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,this.buf.framebuf),!this.gl.isFramebuffer(this.buf.framebuf))throw SceneJS_error.fatalError(SceneJS.errors.INVALID_FRAMEBUFFER,"Invalid framebuffer");var e=this.gl.checkFramebufferStatus(this.gl.FRAMEBUFFER);switch(e){case this.gl.FRAMEBUFFER_COMPLETE:break;case this.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");case this.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");case this.gl.FRAMEBUFFER_UNSUPPORTED:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");default:throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Incomplete framebuffer: "+e)}this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.clear=function(){if(!this.bound)throw"Render buffer not bound";this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT),this.gl.disable(this.gl.BLEND)},SceneJS._webgl.RenderBuffer.prototype.read=function(a,b){var c=a,d=this.canvas.canvas.height-b,e=new Uint8Array(4);return this.gl.readPixels(c,d,1,1,this.gl.RGBA,this.gl.UNSIGNED_BYTE,e),e},SceneJS._webgl.RenderBuffer.prototype.unbind=function(){this.gl.bindFramebuffer(this.gl.FRAMEBUFFER,null),this.bound=!1},SceneJS._webgl.RenderBuffer.prototype.getTexture=function(){var a=this;return{bind:function(b){return a.buf&&a.buf.texture?(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,a.buf.texture),!0):!1},unbind:function(b){a.buf&&a.buf.texture&&(a.gl.activeTexture(a.gl["TEXTURE"+b]),a.gl.bindTexture(a.gl.TEXTURE_2D,null))}}},SceneJS._webgl.RenderBuffer.prototype.destroy=function(){this.buf&&(this.gl.deleteTexture(this.buf.texture),this.gl.deleteFramebuffer(this.buf.framebuf),this.gl.deleteRenderbuffer(this.buf.renderbuf),this.buf=null,this.bound=!1)},SceneJS._webgl.Program=function(a,b,c){this.allocated=!1,this.gl=a,this._uniforms={},this._samplers={},this._attributes={},this.uniformValues=[],this.materialSettings={specularColor:[0,0,0],specular:0,shine:0,emit:0,alpha:0},this._shaders=[];var d,e,f,g,h,i;for(e=0;ee;++e)f=a.getActiveUniform(this.handle,e),f&&(g=f.name,"\x00"==g[g.length-1]&&(g=g.substr(0,g.length-1)),h=a.getUniformLocation(this.handle,g),f.type==a.SAMPLER_2D||f.type==a.SAMPLER_CUBE||35682==f.type?this._samplers[g]=new SceneJS._webgl.Sampler(a,this.handle,g,f.type,f.size,h):(this._uniforms[g]=new SceneJS._webgl.Uniform(a,this.handle,g,f.type,f.size,h,k),this.uniformValues[k]=null,++k));var l=a.getProgramParameter(this.handle,a.ACTIVE_ATTRIBUTES);for(e=0;l>e;e++)d=a.getActiveAttrib(this.handle,e),d&&(h=a.getAttribLocation(this.handle,d.name),this._attributes[d.name]=new SceneJS._webgl.Attribute(a,this.handle,d.name,d.type,d.size,h));this.allocated=!0}},SceneJS._webgl.Program.prototype.bind=function(){this.allocated&&this.gl.useProgram(this.handle)},SceneJS._webgl.Program.prototype.getUniformLocation=function(a){if(this.allocated){var b=this._uniforms[a];return b?b.getLocation():void 0}},SceneJS._webgl.Program.prototype.getUniform=function(a){if(this.allocated){var b=this._uniforms[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.getAttribute=function(a){if(this.allocated){var b=this._attributes[a];return b?b:void 0}},SceneJS._webgl.Program.prototype.bindFloatArrayBuffer=function(a,b){if(this.allocated){var c=this._attributes[a];c&&c.bindFloatArrayBuffer(b)}},SceneJS._webgl.Program.prototype.bindTexture=function(a,b,c){if(!this.allocated)return!1;var d=this._samplers[a];return d?d.bindTexture(b,c):!1},SceneJS._webgl.Program.prototype.destroy=function(){if(this.allocated){this.gl.deleteProgram(this.handle);for(var a in this._shaders)this.gl.deleteShader(this._shaders[a].handle);this.handle=null,this._attributes=null,this._uniforms=null,this._samplers=null,this.allocated=!1}},SceneJS._webgl.Program.prototype.setUniform=function(a,b){if(this.allocated){var c=this._uniforms[a];c&&(this.uniformValues[c.index]===b&&c.numberValue||(c.setValue(b),this.uniformValues[c.index]=b))}},SceneJS._webgl.Sampler=function(a,b,c,d,e,f){this.bindTexture=function(b,c){return b.bind(c)?(a.uniform1i(f,c),!0):!1}},SceneJS._webgl.Shader=function(a,b,c){if(this.allocated=!1,this.handle=a.createShader(b),!this.handle)throw SceneJS_error.fatalError(SceneJS.errors.OUT_OF_VRAM,"Failed to create WebGL shader");if(a.shaderSource(this.handle,c),a.compileShader(this.handle),this.valid=0!=a.getShaderParameter(this.handle,a.COMPILE_STATUS),!this.valid&&!a.isContextLost()){SceneJS.log.error("Shader program failed to compile: "+a.getShaderInfoLog(this.handle)),SceneJS.log.error("Shader source:");for(var d=c.split("\n"),e=0;eb){var d=b/c,e=a.width*d,f=a.height*d,g=document.createElement("canvas");g.width=SceneJS._webgl.nextHighestPowerOfTwo(e),g.height=SceneJS._webgl.nextHighestPowerOfTwo(f);var h=g.getContext("2d");h.drawImage(a,0,0,a.width,a.height,0,0,g.width,g.height),a=g}return a},SceneJS._webgl.ensureImageSizePowerOfTwo=function(a){if(!SceneJS._webgl.isPowerOfTwo(a.width)||!SceneJS._webgl.isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=SceneJS._webgl.nextHighestPowerOfTwo(a.width),b.height=SceneJS._webgl.nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b}return a},SceneJS._webgl.isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS._webgl.nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS._webgl.Uniform=function(a,b,c,d,e,f,g,h){var i=null,j=null;if(d===a.BOOL)i=function(b){j!==b&&(j=b,a.uniform1i(f,b))};else if(d===a.BOOL_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.BOOL_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.BOOL_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.INT)i=function(b){j!==b&&(j=b,a.uniform1iv(f,b))};else if(d===a.INT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2iv(f,b))};else if(d===a.INT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3iv(f,b))};else if(d===a.INT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4iv(f,b))};else if(d===a.FLOAT)i=function(b){j!==b&&(j=b,a.uniform1f(f,b))};else if(d===a.FLOAT_VEC2)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1])&&(j=b,a.uniform2fv(f,b))};else if(d===a.FLOAT_VEC3)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2])&&(j=b,a.uniform3fv(f,b))};else if(d===a.FLOAT_VEC4)i=function(b){(null===j||j[0]!==b[0]||j[1]!==b[1]||j[2]!==b[2]||j[3]!==b[3])&&(j=b,a.uniform4fv(f,b))};else if(d===a.FLOAT_MAT2)i=function(b){a.uniformMatrix2fv(f,a.FALSE,b)};else if(d===a.FLOAT_MAT3)i=function(b){a.uniformMatrix3fv(f,a.FALSE,b)};else{if(d!==a.FLOAT_MAT4)throw"Unsupported shader uniform type: "+d;i=function(b){a.uniformMatrix4fv(f,a.FALSE,b)}}this.setValue=i,this.getLocation=function(){return f},this.index=g};var SceneJS_nodeEventsModule=new function(){var a,b=[],c=[],d=0,e={type:"listeners",stateId:SceneJS._baseStateId++,empty:!0,listeners:[]};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){d=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(d>0){var g={type:"listeners",stateId:b[d-1],listeners:c.slice(0,d)};f.display.renderListeners=g}else f.display.renderListeners=e;a=!1}}),this.preVisitNode=function(e){var f=e._topicSubs.rendered,g=e._topicSubs.worldPos,h=e._topicSubs.viewPos,i=e._topicSubs.cameraPos,j=e._topicSubs.projPos,k=e._topicSubs.canvasPos;(f||g||h||i||j||k)&&(b[d]=e.id,c[d]=function(a){f&&e.publish("rendered",a,!0),g&&e.publish("worldPos",a.getWorldPos()),h&&e.publish("viewPos",a.getViewPos()),i&&e.publish("cameraPos",a.getCameraPos()),j&&e.publish("projPos",a.getProjPos()),k&&e.publish("canvasPos",a.getCanvasPos())},d++,a=!0)},this.postVisitNode=function(c){c.id==b[d-1]&&(d--,a=!0)}},SceneJS_Core=function(a){this.type=a,this.coreId=null,this.stateId=null,this.useCount=0},SceneJS_CoreFactory=function(){this._stateMap=new SceneJS_Map(null,SceneJS._baseStateId),this._cores={}};SceneJS_CoreFactory.coreTypes={},SceneJS_CoreFactory.createCoreType=function(a,b){},SceneJS_CoreFactory.addCoreBuilder=function(a,b){},SceneJS_CoreFactory.coreAliases={rotate:"xform",translate:"xform",scale:"xform",matrix:"xform",xform:"xform"},SceneJS_CoreFactory.prototype.getCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];d||(d=this._cores[a]={});var e;return b&&(e=d[b])?(e.useCount++,e):(e=new SceneJS_Core(a),e.useCount=1,e.stateId=this._stateMap.addItem(e),e.coreId=void 0!=b&&null!=b?b:e.stateId,d[e.coreId]=e,e)},SceneJS_CoreFactory.prototype.hasCore=function(a,b){var c=SceneJS_CoreFactory.coreAliases[a];c&&(a=c);var d=this._cores[a];return d&&d[b]},SceneJS_CoreFactory.prototype.putCore=function(a){if(0!=a.useCount&&--a.useCount<=0){var b=this._cores[a.type];delete b[a.coreId],this._stateMap.removeItem(a.stateId)}},SceneJS_CoreFactory.prototype.webglRestored=function(){var a,b;for(var c in this._cores)if(this._cores.hasOwnProperty(c)&&(a=this._cores[c]))for(var d in a)a.hasOwnProperty(d)&&(b=a[d],b&&b.webglRestored&&b.webglRestored())},SceneJS.Node=function(){},SceneJS.Node.prototype.constructor=SceneJS.Node,SceneJS.Node.prototype._construct=function(a,b,c,d){this._engine=a,this._core=b,this.coreId=b.coreId,this.id=c.id||c.nodeId||d,this.type=c.type||"node",this.data=c.data,this.parent=null,this.nodes=[],this._handleMap=new SceneJS_Map,this._topicSubs={},this._handleTopics={},this._topicPubs={},this._listeners={},this._numListeners=0,this.dirty=!1,this.branchDirty=!1,this._init&&this._init(c)},SceneJS.Node.prototype.taskStarted=function(a){return SceneJS_sceneStatusModule.taskStarted(this,a||"Task")},SceneJS.Node.prototype.taskFinished=function(a){return SceneJS_sceneStatusModule.taskFinished(a)},SceneJS.Node.prototype.taskFailed=function(a){return SceneJS_sceneStatusModule.taskFailed(a)},SceneJS.Node.prototype.log=function(){var a,b;switch(1==arguments.length?(a="info",b=arguments[0]):2==arguments.length&&(a=arguments[0],b=arguments[1]),a){case"warn":b="WARN; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;case"error":b="ERROR; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b;break;default:b="INFO; [SceneJS.Node type="+this.type+", id="+this.id+"] : "+b}console[a]?console[a](b):console.log(b)},SceneJS.Node.prototype.publish=function(a,b,c){if(c||(this._topicPubs[a]=b),this._topicSubs[a]){var d=this._topicSubs[a];for(var e in d)d.hasOwnProperty(e)&&d[e].call(this,b)}},SceneJS.Node.prototype.unpublish=function(a){var b=this._topicSubs[a];if(b)for(var c in b)b.hasOwnProperty(c)&&b[c].call(this,null);delete this._topicPubs[a]},SceneJS.Node.prototype.on=function(a,b){var c=this._topicSubs[a];c||(c={},this._topicSubs[a]=c);var d=this._handleMap.addItem();c[d]=b,this._handleTopics[d]=a;var e=this._topicPubs[a];return e&&b.call(this,e),"rendered"==a&&this._engine.branchDirty(this),d},SceneJS.Node.prototype.off=function(a){var b=this._handleTopics[a];if(b){delete this._handleTopics[a];var c=this._topicSubs[b];c&&delete c[a],this._handleMap.removeItem(a),"rendered"==b&&this._engine.branchDirty(this)}},SceneJS.Node.prototype.once=function(a,b){var c=this,d=this.on(a,function(a){c.off(d),b(a)})},SceneJS.Node.prototype.getScene=function(){return this._engine.scene},SceneJS.Node.prototype.getCoreId=function(){return this._core.coreId},SceneJS.Node.prototype.getID=function(){return this.id},SceneJS.Node.prototype.getId=function(){return this.id},SceneJS.Node.prototype.getNodeId=function(){return this.id},SceneJS.Node.prototype.getType=function(){return this.type},SceneJS.Node.prototype.getData=function(){return this.data},SceneJS.Node.prototype.setData=function(a){return this.data=a,this},SceneJS.Node.prototype.getNumNodes=function(){return this.nodes.length},SceneJS.Node.prototype.getNodes=function(){return this.nodes.slice(0)},SceneJS.Node.prototype.getNodeAt=function(a){return 0>a||a>=this.nodes.length?null:this.nodes[a]},SceneJS.Node.prototype.getFirstNode=function(){return 0==this.nodes.length?null:this.nodes[0]},SceneJS.Node.prototype.getLastNode=function(){return 0==this.nodes.length?null:this.nodes[this.nodes.length-1]},SceneJS.Node.prototype.getNode=function(a){for(var b=0;b0?(b[0].parent=null,this._engine.display.objectListDirty=!0,b[0]):null},SceneJS.Node.prototype.disconnect=function(){if(this.parent){for(var a=0;ab;b++)this.nodes[b].parent=null;var c=this.nodes;return this.nodes=[],this._engine.display.objectListDirty=!0,c},SceneJS.Node.prototype.removeNodes=function(){for(var a=this.disconnectNodes(),b=0;ba;a++)d[a].parent=this.parent;for(a=0,b=c.nodes.length;b>a;a++)if(c.nodes[a]===this)return c.nodes.splice.apply(c.nodes,[a,1].concat(d)),this.nodes=[],this.parent=null,this.destroy(),this._engine.branchDirty(c),c},SceneJS.Node.prototype.addNodes=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNodes - nodes argument is undefined");for(var c,d=[],e=a.length,f=a.length-1;f>=0;f--){var g=a[f];if("node"==g.type||this._engine.hasNodeType(g.type)){if(c=this.addNode(g),d[f]=c,0==--e)return b&&b(a),a}else{var h=this;!function(){var c=f;h.addNode(g,function(f){d[c]=f,0==--e&&b&&b(a)})}()}}return null},SceneJS.Node.prototype.addNode=function(a,b){if(a=a||{},a._compile){if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if("string"==typeof a){var c=this._engine.findNode(a);if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node not found: '"+a+"'");if(a=c,null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Node#addNode - node argument is still attached to another parent");return this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a}if(a.type=a.type||"node","node"==a.type||this._engine.hasNodeType(a.type))return a=this._engine.createNode(a),this.nodes.push(a),a.parent=this,this._engine.branchDirty(a),b&&b(a),a;var d=this;return this._engine.createNode(a,function(a){d.nodes.push(a),a.parent=d,d._engine.branchDirty(a),b&&b(a)}),null},SceneJS.Node.prototype.insertNode=function(a,b){if(!a)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is undefined");if(a._compile||(a=this._engine.createNode(a)),!a._compile)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is not a SceneJS.Node");if(null!=a.parent)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node argument is still attached to another parent");if(void 0===b||null===b)a.addNodes(this.disconnectNodes()),this.addNode(a);else{if(0>b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Node#insertNode - node index out of range: -1");b>=this.nodes.length?this.nodes.push(a):this.nodes.splice(b,0,a)}return a.parent=this,a},SceneJS.Node.prototype.mapNodes=function(a){if(a(this))return this;for(var b,c=0;cg;g++)e=d[g],e.options.scope?e.fn.call(e.options.scope,f):e.fn.call(this,f)}},SceneJS.Node.prototype.removeListener=function(a,b){var c=this._listeners[a];if(!c)return null;for(var d=0;d0},SceneJS.Node.prototype.removeListeners=function(){return this._listeners={},this._numListeners=0,this},SceneJS.Node.prototype.getParent=function(a){return this.parent},SceneJS.Node.prototype.getParentOfType=function(a){for(var b=this.parent;b&&b.type!=a;)b=b.parent;return b},SceneJS.Node.prototype.eachParent=function(a){if(!a)throw"SceneJS.Node.eachParent param 'fn' is null or undefined";for(var b=0,c=this;c.parent;){if(a.call(c.parent,b++)===!0)return c.parent;c=c.parent}return null},SceneJS.Node.prototype.hasNode=function(a){if(null===a||void 0===a)throw"SceneJS.Node.hasNode param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.hasNode param 'node' should be either an index number or an ID string";b=this.getNode(a)}return void 0!=b&&null!=b},SceneJS.Node.prototype.node=function(a){if(null===a||void 0===a)throw"SceneJS.Node.node param 'node' is null or undefined";var b,c=typeof a;if("number"==c)b=this.getNodeAt(a);else{if("string"!=c)throw"SceneJS.Node.node param 'node' should be either an index number or an ID string";b=this.getNode(a)}if(!b)throw"SceneJS.Node.node - node not found: '"+a+"'";return b},SceneJS.Node.prototype.eachNode=function(a,b){if(!a)throw"SceneJS.Node.eachNode param 'fn' is null or undefined";if("function"!=typeof a)throw"SceneJS.Node.eachNode param 'fn' should be a function";var c;b=b||{};var d=0;return b.andSelf&&a.call(this,d++)===!0?this:(b.depthFirst||b.breadthFirst?b.depthFirst&&(c=this._iterateEachNodeDepthFirst(a,this,d,!1)):c=this._iterateEachNode(a,this,d),c?c:void 0)},SceneJS.Node.prototype.numNodes=function(){return this.nodes.length},SceneJS.Node.prototype._iterateEachNode=function(a,b,c){for(var d,e=b.nodes.length,f=0;e>f;f++)if(d=b.nodes[f],a.call(d,c++)===!0)return d;return null},SceneJS.Node.prototype._iterateEachNodeDepthFirst=function(a,b,c,d){if(d&&a.call(b,c++)===!0)return b;d=!0;for(var e,f=b.nodes.length,g=0;f>g;g++)if(e=this._iterateEachNodeDepthFirst(a,b.nodes[g],c,d))return e;return null},SceneJS.Node.prototype.findNodesByType=function(a,b){return this._findNodesByType(a,[],b)},SceneJS.Node.prototype._findNodesByType=function(a,b,c){var d;for(d=0;dd;d++)c=this.nodes[d],c.branchDirty=c.branchDirty||this.branchDirty,(c.dirty||c.branchDirty||this._engine.sceneDirty)&&(c._compile(a),c.dirty=!1,c.branchDirty=!1);b&&SceneJS_nodeEventsModule.postVisitNode(this)},SceneJS.Node.prototype.destroy=function(){if(!this.destroyed){if(this.parent)for(var a=0;aa;a++)this.nodes[a]._destroyTree()},SceneJS.Node.prototype._doDestroy=function(){return this._destroy&&this._destroy(),this},SceneJS_PubSubProxy=function(a,b){this.scene=a,this.proxy=b};var SceneJS_NodeFactory=function(){this.nodes=new SceneJS_Map({})};SceneJS_NodeFactory.nodeTypes={},SceneJS_NodeFactory._subs={},SceneJS_NodeFactory.createNodeType=function(a,b,c){if(SceneJS_NodeFactory.nodeTypes[a])throw"Node type already defined: "+a;var d=function(){SceneJS.Node.apply(this,arguments),this.type=a};d.prototype=new SceneJS.Node,d.prototype.constructor=d,SceneJS_NodeFactory.nodeTypes[a]=d;var e=SceneJS_NodeFactory.nodeTypes[a];if(!e)throw"Node type plugin did not install itself correctly";c&&c(d);var f=SceneJS_NodeFactory._subs[a];if(f){for(;f.length>0;)f.pop()(e);delete f[a]}return d},SceneJS_NodeFactory.prototype.getNode=function(a,b,c,d){b.type=b.type||"node";var e;if(e="node"==b.type?SceneJS.Node:SceneJS_NodeFactory.nodeTypes[b.type])return this._createNode(e,a,b,c,d);var f=this;this._getType(a,b.type,function(e){f._createNode(e,a,b,c,d)})},SceneJS_NodeFactory.prototype._createNode=function(a,b,c,d,e){var f=new a,g=c.id||c.nodeId;return g?this.nodes.addItem(g,f):g=this.nodes.addItem(f),f._construct(b,d,c,g),e&&e(f),f},SceneJS_NodeFactory.prototype._getType=function(a,b,c){var d=SceneJS_NodeFactory.nodeTypes[b];if(d)return void c(d);var e=SceneJS_NodeFactory._subs[b]||(SceneJS_NodeFactory._subs[b]=[]);if(e.push(c),!(e.length>1)){var f=SceneJS_sceneStatusModule.taskStarted(a.scene,"Loading plugin");e.push(function(){SceneJS_sceneStatusModule.taskFinished(f)});var g=SceneJS_configsModule.configs.pluginPath; -if(!g)throw"no typePath config";this._loadScript(g+"/node/"+b+".js",function(){SceneJS_sceneStatusModule.taskFailed(f)})}},SceneJS_NodeFactory.prototype._loadScript=function(a,b){var c=document.createElement("script");c.type="text/javascript",c.src=a,c.onerror=b,document.getElementsByTagName("head")[0].appendChild(c)},SceneJS_NodeFactory.prototype.putNode=function(a){this.nodes.removeItem(a.id)},function(){function a(a){var b=a.optics;if("ortho"==b.type?a.matrix=SceneJS_math_orthoMat4c(b.left,b.right,b.bottom,b.top,b.near,b.far):"frustum"==b.type?a.matrix=SceneJS_math_frustumMatrix4(b.left,b.right,b.bottom,b.top,b.near,b.far):"perspective"==b.type&&(a.matrix=SceneJS_math_perspectiveMatrix4(b.fovy*Math.PI/180,b.aspect,b.near,b.far)),a.pan){var c=a.pan,d=SceneJS_math_translationMat4v([c.x||0,c.y||0,c.z||0]);a.matrix=SceneJS_math_mulMat4(d,a.matrix,[])}a.mat?a.mat.set(a.matrix):a.mat=new Float32Array(a.matrix)}var b=SceneJS_math_perspectiveMatrix4(45,1,.1,1e4),c=new Float32Array(b),d={type:"camera",stateId:SceneJS._baseStateId++,matrix:b,mat:c,optics:{type:"perspective",fovy:45,aspect:1,near:.1,far:1e4},checkAspect:function(b,c){b.optics.aspect!=c&&(b.optics.aspect=c,a(this))}},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.projTransform=d,f=0}),SceneJS.Camera=SceneJS_NodeFactory.createNodeType("camera"),SceneJS.Camera.prototype._init=function(b){if(1==this._core.useCount){b.optics=b.optics||{};var c=this.getScene().getCanvas();b.optics.aspect=c.width/c.height,this.setOptics(b.optics),b.pan&&this.setPan(b.pan);var d=this;this._canvasSizeSub=this.getScene().on("canvasSize",function(b){d._core.optics.aspect=b.aspect,a(d._core),d._engine.display.imageDirty=!0})}},SceneJS.Camera.getDefaultMatrix=function(){return c},SceneJS.Camera.prototype.setOptics=function(b){var c=this._core;if(b){var d=b.type||c.optics.type||"perspective";if("ortho"==d)c.optics=SceneJS._applyIf(SceneJS_math_ORTHO_OBJ,{type:d,left:b.left,bottom:b.bottom,near:b.near,right:b.right,top:b.top,far:b.far});else if("frustum"==d)c.optics={type:d,left:b.left||-1,bottom:b.bottom||-1,near:b.near||.1,right:b.right||1,top:b.top||1,far:b.far||1e4};else{if("perspective"!=d)throw b.type?SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not supported - supported types are 'perspective', 'frustum' and 'ortho'"):SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not specified - supported types are 'perspective', 'frustum' and 'ortho'");c.optics={type:d,fovy:b.fovy||60,aspect:void 0==b.aspect?1:b.aspect,near:b.near||.1,far:b.far||1e4}}}else c.optics={type:"perspective",fovy:60,aspect:1,near:.1,far:1e4};this._core.optics.pan=b.pan,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.setPan=function(b){this._core.pan=b,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.getOptics=function(){var a={};for(var b in this._core.optics)this._core.optics.hasOwnProperty(b)&&(a[b]=this._core.optics[b]);return a},SceneJS.Camera.prototype.getMatrix=function(){return this._core.matrix.slice(0)},SceneJS.Camera.prototype._compile=function(a){this._engine.display.projTransform=e[f++]=this._core,this._compileNodes(a),this._engine.display.projTransform=--f>0?e[f-1]:d},SceneJS.Camera.prototype._destroy=function(){this.getScene().off(this._canvasSizeSub)}}(),function(){var a={type:"clips",stateId:SceneJS._baseStateId++,empty:!0,hash:"",clips:[]},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.clips=a,c=0}),SceneJS.Clips=SceneJS_NodeFactory.createNodeType("clips"),SceneJS.Clips.prototype._init=function(a){if(1==this._core.useCount){var b=a.clips;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"clips node attribute missing : 'clips'");this._core.clips=this._core.clips||[];for(var c=0,d=b.length;d>c;c++)this._setClip(c,b[c])}},SceneJS.Clips.prototype.setClips=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.clips.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'clips': index out of range ("+this._core.clips.length+" clips defined)");this._setClip(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Clips.prototype._setClip=function(a,b){var c=this._core.clips[a]||(this._core.clips[a]={});c.normalAndDist=[b.x||0,b.y||0,b.z||0,b.dist||0];var d=b.mode||c.mode||"disabled";if("inside"!=d&&"outside"!=d&&"disabled"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'");c.mode=d,this._core.hash=null},SceneJS.Clips.prototype._compile=function(d){this._core.hash||(this._core.hash=this._core.clips.length),this._engine.display.clips=b[c++]=this._core,this._compileNodes(d),this._engine.display.clips=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"enable",enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.enable=a,c=0}),SceneJS.Enable=SceneJS_NodeFactory.createNodeType("enable"),SceneJS.Enable.prototype._init=function(a){1==this._core.useCount&&(this._core.enabled=!0,void 0!=a.enabled&&this.setEnabled(a.enabled))},SceneJS.Enable.prototype.setEnabled=function(a){return a!==this._core.enabled&&(this._core.enabled=a,this._engine.display.drawListDirty=!0,this.publish("enabled",a)),this},SceneJS.Enable.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Enable.prototype._compile=function(d){this._engine.display.enable=b[c++]=this._core,this._compileNodes(d),this._engine.display.enable=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"flags",picking:!0,clipping:!0,enabled:!0,transparent:!1,backfaces:!0,frontface:"ccw",reflective:!0,solid:!0,hash:"refl;s;"},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.flags=a,c=0}),SceneJS.Flags=SceneJS_NodeFactory.createNodeType("flags"),SceneJS.Flags.prototype._init=function(a){1==this._core.useCount&&(this._core.picking=!0,this._core.clipping=!0,this._core.enabled=!0,this._core.transparent=!1,this._core.backfaces=!0,this._core.frontface="ccw",this._core.reflective=!0,this._core.solid=!0,a.flags&&this.setFlags(a.flags))},SceneJS.Flags.prototype.setFlags=function(a){var b=this._core;return void 0!=a.picking&&(b.picking=!!a.picking,this._engine.display.drawListDirty=!0),void 0!=a.clipping&&(b.clipping=!!a.clipping,this._engine.display.imageDirty=!0),void 0!=a.enabled&&(b.enabled=!!a.enabled,this._engine.display.drawListDirty=!0),void 0!=a.transparent&&(b.transparent=!!a.transparent,this._engine.display.stateSortDirty=!0),void 0!=a.backfaces&&(b.backfaces=!!a.backfaces,this._engine.display.imageDirty=!0),void 0!=a.frontface&&(b.frontface=a.frontface,this._engine.display.imageDirty=!0),void 0!=a.reflective&&(b.reflective=a.reflective,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),void 0!=a.solid&&(b.solid=a.solid,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.addFlags=function(a){return this.setFlags(a)},SceneJS.Flags.prototype.getFlags=function(){var a=this._core;return{picking:a.picking,clipping:a.clipping,enabled:a.enabled,transparent:a.transparent,backfaces:a.backfaces,frontface:a.frontface,reflective:a.reflective,solid:a.solid}},SceneJS.Flags.prototype.setPicking=function(a){return a=!!a,this._core.picking!=a&&(this._core.picking=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getPicking=function(){return this._core.picking},SceneJS.Flags.prototype.setClipping=function(a){return a=!!a,this._core.clipping!=a&&(this._core.clipping=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getClipping=function(){return this._core.clipping},SceneJS.Flags.prototype.setEnabled=function(a){return a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Flags.prototype.setTransparent=function(a){return a=!!a,this._core.transparent!=a&&(this._core.transparent=a,this._engine.display.stateOrderDirty=!0),this},SceneJS.Flags.prototype.getTransparent=function(){return this._core.transparent},SceneJS.Flags.prototype.setBackfaces=function(a){return a=!!a,this._core.backfaces!=a&&(this._core.backfaces=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getBackfaces=function(){return this._core.backfaces},SceneJS.Flags.prototype.setFrontface=function(a){return this._core.frontface!=a&&(this._core.frontface=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getFrontface=function(){return this._core.frontface},SceneJS.Flags.prototype.setReflective=function(a){return a=!!a,this._core.reflective!=a&&(this._core.reflective=a,this._core.hash=(a?"refl":"")+this._core.solid?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getReflective=function(){return this._core.reflective},SceneJS.Flags.prototype.setSolid=function(a){return a=!!a,this._core.solid!=a&&(this._core.solid=a,this._core.hash=(this._core.reflective?"refl":"")+a?";s":";",this._engine.branchDirty(this)),this},SceneJS.Flags.prototype.getSolid=function(){return this._core.solid},SceneJS.Flags.prototype._compile=function(d){this._engine.display.flags=b[c++]=this._core,this._compileNodes(d),this._engine.display.flags=--c>0?b[c-1]:a}}(),new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._core.renderBuf.webglRestored()}),SceneJS.ColorTarget=SceneJS_NodeFactory.createNodeType("colorTarget"),SceneJS.ColorTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="color",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.ColorTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.ColorTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._buildNodeCore()}),SceneJS.DepthTarget=SceneJS_NodeFactory.createNodeType("depthTarget"),SceneJS.DepthTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="depth",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.DepthTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.DepthTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a=[],b=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){b=0}),SceneJS.Geometry=SceneJS_NodeFactory.createNodeType("geometry"),SceneJS.Geometry.prototype._init=function(a){if(1==this._core.useCount){this._initNodeCore(a,{origin:a.origin,scale:a.scale,autoNormals:"auto"==a.normals}),this._buildNodeCore(this._engine.canvas.gl,this._core);var b=this;this._core.webglRestored=function(){b._buildNodeCore(b._engine.canvas.gl,b._core)}}},SceneJS.Geometry.prototype._initNodeCore=function(a,b){var c=this;b=b||{};var d=a.primitive||"triangles",e=this._core,f=this._engine.canvas.UINT_INDEX_ENABLED?Uint32Array:Uint16Array;e.primitive=this._getPrimitiveType(d),a.normals&&"triangles"==d&&("auto"===a.normals||a.normals===!0)&&a.positions&&a.indices&&this._buildNormals(a),e.arrays={positions:a.positions?new Float32Array(b.scale||b.origin?this._applyOptions(a.positions,b):a.positions):void 0,normals:a.normals?new Float32Array(a.normals):void 0,uv:a.uv?new Float32Array(a.uv):void 0,uv2:a.uv2?new Float32Array(a.uv2):void 0,colors:a.colors?new Float32Array(a.colors):void 0,indices:a.indices?new f(a.indices):void 0},delete a.positions,delete a.normals,delete a.uv,delete a.uv2,delete a.indices,delete a.colors,e.getTangentBuf=function(){if(e.tangentBuf)return e.tangentBuf;var a=e.arrays;if(a.positions&&a.indices&&a.uv){var b=c._engine.canvas.gl,d=new Float32Array(c._buildTangents(a));e.arrays.tangents=d;var f=b.STATIC_DRAW;return e.tangentBuf=new SceneJS._webgl.ArrayBuffer(b,b.ARRAY_BUFFER,d,d.length,3,f)}}},SceneJS.Geometry.prototype._getPrimitiveType=function(a){var b=this._engine.canvas.gl;switch(a){case"points":return b.POINTS;case"lines":return b.LINES;case"line-loop":return b.LINE_LOOP;case"line-strip":return b.LINE_STRIP;case"triangles":return b.TRIANGLES;case"triangle-strip":return b.TRIANGLE_STRIP;case"triangle-fan":return b.TRIANGLE_FAN;default:throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"geometry primitive unsupported: '"+a+"' - supported types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'")}},SceneJS.Geometry.prototype._applyOptions=function(a,b){var c=a.slice?a.slice(0):new Float32Array(a);if(b.scale)for(var d=void 0!=b.scale.x?b.scale.x:1,e=void 0!=b.scale.y?b.scale.y:1,f=void 0!=b.scale.z?b.scale.z:1,g=0,h=c.length;h>g;g+=3)c[g]*=d,c[g+1]*=e,c[g+2]*=f;if(b.origin)for(var i=void 0!=b.origin.x?b.origin.x:0,j=void 0!=b.origin.y?b.origin.y:0,k=void 0!=b.origin.z?b.origin.z:0,g=0,h=c.length;h>g;g+=3)c[g]-=i,c[g+1]-=j,c[g+2]-=k;return c};var c=function(a){a.vertexBuf&&(a.vertexBuf.destroy(),a.vertexBuf=null),a.normalBuf&&(a.normalBuf.destroy(),a.normalBuf=null),a.uvBuf&&(a.uvBuf.destroy(),a.uvBuf=null),a.uvBuf2&&(a.uvBuf2.destroy(),a.uvBuf2=null),a.colorBuf&&(a.colorBuf.destroy(),a.colorBuf=null),a.tangentBuf&&(a.tangentBuf.destroy(),a.tangentBuf=null),a.indexBuf&&(a.indexBuf.destroy(),a.indexBuf=null),a.interleavedBuf&&(a.interleavedBuf.destroy(),a.interleavedBuf=null)};SceneJS.Geometry.prototype._buildNodeCore=function(a,b){var d=a.STATIC_DRAW;try{var e=b.arrays,f=SceneJS.getConfigs("enableInterleaving")!==!1,g=0,h=0,i=[],j=[],k=function(a,b){return 0==g?g=a.length/b:a.length/b!=g&&(f=!1),i.push(a),j.push(b),h+=b,4*(h-b)};if(e.positions&&(f&&(b.interleavedPositionOffset=k(e.positions,3)),b.vertexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.positions,e.positions.length,3,d)),e.normals&&(f&&(b.interleavedNormalOffset=k(e.normals,3)),b.normalBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.normals,e.normals.length,3,d)),e.uv&&(f&&(b.interleavedUVOffset=k(e.uv,2)),b.uvBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv,e.uv.length,2,d)),e.uv2&&(f&&(b.interleavedUV2Offset=k(e.uv2,2)),b.uvBuf2=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv2,e.uv2.length,2,d)),e.colors&&(f&&(b.interleavedColorOffset=k(e.colors,4)),b.colorBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.colors,e.colors.length,4,d)),e.indices&&(b.indexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ELEMENT_ARRAY_BUFFER,e.indices,e.indices.length,1,d)),h>0&&f){for(var l=[],m=i.length,n=0;g>n;++n)for(var o=0;m>o;++o)for(var p=j[o],q=0;p>q;++q)l.push(i[o][n*p+q]);b.interleavedStride=4*h,b.interleavedBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,new Float32Array(l),l.length,h,d),b.interleavedBuf.dirty=!1}}catch(r){throw c(b),SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate geometry: "+r)}},SceneJS.Geometry.prototype._updateArray=function(a,b,c){var d=a.length,e=b.length;e+c>d&&(e-=e+c-d);for(var f=c,g=0;e>g;f++,g++)a[f]=b[g]},SceneJS.Geometry.prototype._buildNormals=function(a){for(var b,c,d,e,f,g,h=a.positions,i=a.indices,j=new Array(h.length/3),k=0,l=i.length-3;l>k;k+=3){b=i[k+0],c=i[k+1],d=i[k+2],e=[h[3*b+0],h[3*b+1],h[3*b+2]],f=[h[3*c+0],h[3*c+1],h[3*c+2]],g=[h[3*d+0],h[3*d+1],h[3*d+2]],f=SceneJS_math_subVec4(f,e,[0,0,0,0]),g=SceneJS_math_subVec4(g,e,[0,0,0,0]);var m=SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(f,g,[0,0,0,0]),[0,0,0,0]);j[b]||(j[b]=[]),j[c]||(j[c]=[]),j[d]||(j[d]=[]),j[b].push(m),j[c].push(m),j[d].push(m)}for(var n=new Array(h.length),k=0,l=j.length;l>k;k++){for(var o=j[k].length,p=0,q=0,r=0,s=0;o>s;s++)p+=j[k][s][0],q+=j[k][s][1],r+=j[k][s][2];n[3*k+0]=p/o,n[3*k+1]=q/o,n[3*k+2]=r/o}a.normals=n},SceneJS.Geometry.prototype._buildTangents=function(a){for(var b=a.positions,c=a.indices,d=a.uv,e=[],f=0;ft;t++){var u=c[f+t];"undefined"!=typeof e[u]?e[u]=SceneJS_math_addVec3(e[u],s,[]):e[u]=s}}for(var v=[],w=0;wf;f+=3)c=b[f],d=b[f+1],e=b[f+2],cthis._boundary.xmax&&(this._boundary.xmax=c),d>this._boundary.ymax&&(this._boundary.ymax=d),e>this._boundary.zmax&&(this._boundary.zmax=e);return this._boundary},SceneJS.Geometry.prototype._compile=function(c){if(this._core._loading)return void this._compileNodes(c);var d=this._core;d.vertexBuf||(d=this._inheritVBOs(d)),d.indexBuf?(d.hash=[d.normalBuf?"t":"f",d.arrays&&d.arrays.tangents?"t":"f",d.uvBuf?"t":"f",d.uvBuf2?"t":"f",d.colorBuf?"t":"f",d.primitive].join(""),d.stateId=this._core.stateId,d.type="geometry",this._engine.display.geometry=a[b++]=d,SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING,{display:this._engine.display}),this._engine.display.buildObject(this.id)):a[b++]=this._core,this._compileNodes(c),b--},SceneJS.Geometry.prototype._inheritVBOs=function(c){for(var d={primitive:c.primitive,boundary:c.boundary,normalBuf:c.normalBuf,uvBuf:c.uvBuf,uvBuf2:c.uvBuf2,colorBuf:c.colorBuf,interleavedBuf:c.interleavedBuf,indexBuf:c.indexBuf,interleavedStride:c.interleavedStride,interleavedPositionOffset:c.interleavedPositionOffset,interleavedNormalOffset:c.interleavedNormalOffset,interleavedUVOffset:c.interleavedUVOffset,interleavedUV2Offset:c.interleavedUV2Offset,interleavedColorOffset:c.interleavedColorOffset},e=b-1;e>=0;e--)if(a[e].vertexBuf)return d.vertexBuf=a[e].vertexBuf,d.boundary=a[e].boundary,d.normalBuf=a[e].normalBuf,d.uvBuf=a[e].uvBuf,d.uvBuf2=a[e].uvBuf2,d.colorBuf=a[e].colorBuf,d.interleavedBuf=a[e].interleavedBuf,d.interleavedStride=a[e].interleavedStride,d.interleavedPositionOffset=a[e].interleavedPositionOffset,d.interleavedNormalOffset=a[e].interleavedNormalOffset,d.interleavedUVOffset=a[e].interleavedUVOffset,d.interleavedUV2Offset=a[e].interleavedUV2Offset,d.interleavedColorOffset=a[e].interleavedColorOffset,d;return d},SceneJS.Geometry.prototype._destroy=function(){this._engine.display.removeObject(this.id),1==this._core.useCount&&(this._destroyNodeCore(),this._source&&this._source.destroy&&this._source.destroy())},SceneJS.Geometry.prototype._destroyNodeCore=function(){document.getElementById(this._engine.canvas.canvasId)&&c(this._core)}},function(){var a={type:"stage",stateId:SceneJS._baseStateId++,priority:0,pickable:!0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.stage=a,c=0}),SceneJS.Stage=SceneJS_NodeFactory.createNodeType("stage"),SceneJS.Stage.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1,this._core.pickable=!!a.pickable)},SceneJS.Stage.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Stage.prototype.getPriority=function(){return this._core.priority},SceneJS.Stage.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype._compile=function(d){this._engine.display.stage=b[c++]=this._core,this._compileNodes(d),this._engine.display.stage=--c>0?b[c-1]:a}}(),function(){var a={type:"layer",stateId:SceneJS._baseStateId++,priority:0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.layer=a,c=0}),SceneJS.Layer=SceneJS_NodeFactory.createNodeType("layer"),SceneJS.Layer.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1)},SceneJS.Layer.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Layer.prototype.getPriority=function(){return this._core.priority},SceneJS.Layer.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.setClearDepth=function(a){a=a||0,this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Layer.prototype._compile=function(d){this._engine.display.layer=b[c++]=this._core,this._compileNodes(d),this._engine.display.layer=--c>0?b[c-1]:a}}(),SceneJS.Library=SceneJS_NodeFactory.createNodeType("library"),SceneJS.Library.prototype._compile=function(a){},function(){function a(a){if(a.lights&&a.lights.length>0){for(var b,c=a.lights,d=[],e=0,f=c.length;f>e;e++)b=c[e],d.push(b.mode),b.specular&&d.push("s"),b.diffuse&&d.push("d"),d.push("world"==b.space?"w":"v");a.hash=d.join("")}else a.hash=""}var b={type:"lights",stateId:SceneJS._baseStateId++,hash:null,empty:!1,lights:[{mode:"ambient",color:[.7,.7,.8],diffuse:!0,specular:!1},{mode:"dir",color:[1,1,1],diffuse:!0,specular:!0,dir:[-.5,-.5,-1],space:"view"},{mode:"dir",color:[1,1,1],diffuse:!1,specular:!0,dir:[1,-.9,-.7],space:"view"}]};a(b);var c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.lights=b,d=0}),SceneJS.Lights=SceneJS_NodeFactory.createNodeType("lights"),SceneJS.Lights.prototype._init=function(a){if(1==this._core.useCount){var b=a.lights;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"lights node attribute missing : 'lights'");this._core.lights=this._core.lights||[];for(var c=0,d=b.length;d>c;c++)this._initLight(c,b[c])}},SceneJS.Lights.prototype._initLight=function(a,b){var c=[];this._core.lights[a]=c;var d=b.mode||"dir";if("dir"!=d&&"point"!=d&&"ambient"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");var e=b.pos,f=b.dir,g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],c.mode=d,c.diffuse="ambient"==d?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==d?!1:void 0!=b.specular?b.specular:!0,c.pos=b.pos?[e.x||0,e.y||0,e.z||0]:[0,0,0],c.dir=b.dir?[f.x||0,f.y||0,f.z||0]:[0,0,1],c.attenuation=[void 0!=b.constantAttenuation?b.constantAttenuation:0,b.linearAttenuation||0,b.quadraticAttenuation||0];var h=b.space;if(h){if("view"!=h&&"world"!=h)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+h+"' - should be 'view' or 'world'")}else h="world";c.space=h,this._core.hash=null},SceneJS.Lights.prototype.setLights=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.lights.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'lights': index out of range ("+this._core.lights.length+" lights defined)");this._setLight(b,a[c]||{})}this._engine.branchDirty(this)},SceneJS.Lights.prototype._setLight=function(a,b){var c=this._core.lights[a],d=!1,e=!1;if(b.mode&&b.mode!=c.mode){var f=b.mode;if("dir"!=f&&"point"!=f&&"ambient"!=f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");c.mode=f,c.diffuse="ambient"==f?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==f?!1:void 0!=b.specular?b.specular:!0,e=!0}if(b.color){var g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],d=!0}var h=b.pos;h&&(c.pos=[h.x||0,h.y||0,h.z||0],d=!0);var i=b.dir;if(i&&(c.dir=[i.x||0,i.y||0,i.z||0],d=!0),void 0!=b.constantAttenuation&&(c.attenuation[0]=b.constantAttenuation,d=!0),void 0!=b.linearAttenuation&&(c.attenuation[1]=b.linearAttenuation,d=!0),void 0!=b.quadraticAttenuation&&(c.attenuation[2]=b.quadraticAttenuation,d=!0),b.space&&b.space!=c.space){var j=b.space;if("view"!=j&&"world"!=j)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+j+"' - should be 'view' or 'world'");c.space=j,this._core.hash=null,e=!0}void 0!=b.specular&&b.specular!=c.specular&&(c.specular=b.specular,e=!0),void 0!=b.diffuse&&b.diffuse!=c.diffuse&&(c.diffuse=b.diffuse,e=!0),e?this._engine.branchDirty(this):d&&(this._engine.display.imageDirty=!0),this._core.hash=null},SceneJS.Lights.prototype._compile=function(e){this._core.hash||a(this._core),this._engine.display.lights=c[d++]=this._core,this._compileNodes(e),this._engine.display.lights=--d>0?c[d-1]:b}}(),function(){var a=SceneJS_math_lookAtMat4c(0,0,10,0,0,0,0,1,0),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4())),d=new Float32Array(c),e={type:"lookAt",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,lookAt:SceneJS_math_LOOKAT_ARRAYS},f=[],g=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.viewTransform=e,g=0}),SceneJS.Lookat=SceneJS_NodeFactory.createNodeType("lookAt"),SceneJS.Lookat.prototype._init=function(a){if(this._mat=null,this._xf={type:"lookat"},1==this._core.useCount){this._core.eyeX=0,this._core.eyeY=0,this._core.eyeZ=10,this._core.lookX=0,this._core.lookY=0,this._core.lookZ=0,this._core.upX=0,this._core.upY=1,this._core.upZ=0,a.eye||a.look||a.up?(this.setEye(a.eye),this.setLook(a.look),this.setUp(a.up)):(this.setEye({x:0,y:0,z:10}),this.setLook({x:0,y:0,z:0}),this.setUp({x:0,y:1,z:0}));var b=this._core,c=this;this._core.rebuild=function(){b.matrix=SceneJS_math_lookAtMat4c(b.eyeX,b.eyeY,b.eyeZ,b.lookX,b.lookY,b.lookZ,b.upX,b.upY,b.upZ),b.lookAt={eye:[b.eyeX,b.eyeY,b.eyeZ],look:[b.lookX,b.lookY,b.lookZ],up:[b.upX,b.upY,b.upZ]},b.mat?(b.mat.set(b.matrix),b.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))):(b.mat=new Float32Array(b.matrix),b.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))),c.publish("matrix",b.matrix),b.dirty=!1},this._core.dirty=!0,this._tick=this.getScene().on("tick",function(){c._core.dirty&&c._core.rebuild()})}},SceneJS.Lookat.getDefaultMatrix=function(){return b},SceneJS.Lookat.prototype.setEye=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.eyeX=a.x),void 0!=a.y&&null!=a.y&&(this._core.eyeY=a.y),void 0!=a.z&&null!=a.z&&(this._core.eyeZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEye=function(a){return a=a||{},this._core.eyeX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.eyeY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.eyeZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeX=function(a){return this._core.eyeX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeY=function(a){return this._core.eyeY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0, -this},SceneJS.Lookat.prototype.setEyeZ=function(a){return this._core.eyeZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeX=function(a){return this._core.eyeX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeY=function(a){return this._core.eyeY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeZ=function(a){return this._core.eyeZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getEye=function(){return{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ}},SceneJS.Lookat.prototype.setLook=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.lookX=a.x),void 0!=a.y&&null!=a.y&&(this._core.lookY=a.y),void 0!=a.z&&null!=a.z&&(this._core.lookZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLook=function(a){return a=a||{},this._core.lookX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.lookY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.lookZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookX=function(a){return this._core.lookX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookY=function(a){return this._core.lookY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookZ=function(a){return this._core.lookZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookX=function(a){return this._core.lookX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookY=function(a){return this._core.lookY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookZ=function(a){return this._core.lookZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getLook=function(){return{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ}},SceneJS.Lookat.prototype.setUp=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.upX=a.x),void 0!=a.y&&null!=a.y&&(this._core.upY=a.y),void 0!=a.z&&null!=a.z&&(this._core.upZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUp=function(a){return a=a||{},this._core.upX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.upY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.upZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpX=function(a){return this._core.upX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpY=function(a){return this._core.upY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpZ=function(a){return this._core.upZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpX=function(a){return this._core.upX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpY=function(a){return this._core.upY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpZ=function(a){return this._core.upZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getUp=function(){return{x:this._core.upX,y:this._core.upY,z:this._core.upZ}},SceneJS.Lookat.prototype.getMatrix=function(){return this._core.dirty&&this._core.rebuild(),this._core.matrix.slice(0)},SceneJS.Lookat.prototype.getAttributes=function(){return{look:{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ},eye:{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ},up:{x:this._core.upX,y:this._core.upY,z:this._core.upZ}}},SceneJS.Lookat.prototype._compile=function(a){this._engine.display.viewTransform=f[g++]=this._core,this._compileNodes(a),this._engine.display.viewTransform=--g>0?f[g-1]:e},SceneJS.Lookat.prototype._destroy=function(){this.getScene().off(this._tick)}}(),new function(){var a={type:"material",stateId:SceneJS._baseStateId++,baseColor:[1,1,1],specularColor:[1,1,1],specular:1,shine:70,alpha:1,emit:0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.material=a,c=0}),SceneJS.Material=SceneJS_NodeFactory.createNodeType("material"),SceneJS.Material.prototype._init=function(a){1==this._core.useCount&&(this.setBaseColor(a.color||a.baseColor),this.setSpecularColor(a.specularColor),this.setSpecular(a.specular),this.setShine(a.shine),this.setEmit(a.emit),this.setAlpha(a.alpha))},SceneJS.Material.prototype.setBaseColor=function(b){var c=a.baseColor;return this._core.baseColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.baseColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.setColor=SceneJS.Material.prototype.setBaseColor,SceneJS.Material.prototype.getBaseColor=function(){return{r:this._core.baseColor[0],g:this._core.baseColor[1],b:this._core.baseColor[2]}},SceneJS.Material.prototype.getColor=SceneJS.Material.prototype.getBaseColor,SceneJS.Material.prototype.setSpecularColor=function(b){var c=a.specularColor;return this._core.specularColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.specularColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecularColor=function(){return{r:this._core.specularColor[0],g:this._core.specularColor[1],b:this._core.specularColor[2]}},SceneJS.Material.prototype.setSpecular=function(b){return this._core.specular=void 0!=b&&null!=b?b:a.specular,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecular=function(){return this._core.specular},SceneJS.Material.prototype.setShine=function(b){return this._core.shine=void 0!=b&&null!=b?b:a.shine,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getShine=function(){return this._core.shine},SceneJS.Material.prototype.setEmit=function(b){return this._core.emit=void 0!=b&&null!=b?b:a.emit,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getEmit=function(){return this._core.emit},SceneJS.Material.prototype.setAlpha=function(b){return this._core.alpha=void 0!=b&&null!=b?b:a.alpha,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getAlpha=function(){return this._core.alpha},SceneJS.Material.prototype._compile=function(d){this._engine.display.material=b[c++]=this._core,this._compileNodes(d),this._engine.display.material=--c>0?b[c-1]:a}},new function(){var a={type:"morphGeometry",stateId:SceneJS._baseStateId++,hash:"",morph:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.morphGeometry=a,c=0}),SceneJS.MorphGeometry=SceneJS_NodeFactory.createNodeType("morphGeometry"),SceneJS.MorphGeometry.prototype._init=function(a){if(1==this._core.useCount){if(this._sourceConfigs=a.source,this._source=null,a.source){if(!a.source.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry config expected: source.type");var b=this;SceneJS.Plugins.getPlugin("morphGeometry",this._sourceConfigs.type,function(c){if(!c)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: no support for source type '"+b._sourceConfigs.type+"' - need to include plugin for self source type, or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '"+b._sourceConfigs.type+"', ).");if(!c.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)");if(b._source=c.getSource(),!b._source.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'subscribe' method not found on source provided by plugin type '"+a.source.type+"'");var d=!1;b._source.subscribe(function(a){if(d){if(a.targets)for(var c,e,f,g=a.targets,h=b._core.targets,i=0,j=g.length;j>i;i++)c=g[i],e=c.targetIndex,f=h[e],c.positions&&f.vertexBuf&&(f.vertexBuf.bind(),f.vertexBuf.setData(c.positions,0));b._display.imageDirty=!0}else b._buildNodeCore(a),b._core._loading=!1,b._fireEvent("loaded"),b._engine.branchDirty(b),d=!0}),b._core._loading=!0,b._fireEvent("loading"),b._source.configure(b._sourceConfigs)})}else a.create instanceof Function?this._buildNodeCore(a.create()):this._buildNodeCore(a);this._core.webglRestored=function(){},this.setFactor(a.factor)}this._core.factor=a.factor||0,this._core.clamp=!!a.clamp},SceneJS.MorphGeometry.prototype._buildNodeCore=function(a){var b=a.targets||[];if(b.length<2)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node should have at least two targets");var c=a.keys||[];if(c.length!=b.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node mismatch in number of keys and targets");var d=this._core,e=this._engine.canvas.gl,f=e.STATIC_DRAW;d.keys=c,d.targets=[],d.key1=0,d.key2=1;for(var g,h,i,j,k,l=0,m=b.length;m>l;l++)k=b[l],!g&&k.positions&&(g=k.positions),!h&&k.normals&&(h=k.normals),!i&&k.uv&&(i=k.uv),!j&&k.uv2&&(j=k.uv2);try{for(var n,o,l=0,m=b.length;m>l;l++)k=b[l],n={},o=k.positions||g,o&&(n.positions="Float32Array"==typeof o?o:new Float32Array(o),n.vertexBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.positions,o.length,3,f),g=o),o=k.normals||h,o&&(n.normals="Float32Array"==typeof o?o:new Float32Array(o),n.normalBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.normals,o.length,3,f),h=o),o=k.uv||i,o&&(n.uv="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv,o.length,2,f),i=o),o=k.uv2||j,o&&(n.uv2="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf2=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv2,o.length,2,f),j=o),d.targets.push(n)}catch(p){for(var l=0,m=d.targets.length;m>l;l++)n=d.targets[l],n.vertexBuf&&n.vertexBuf.destroy(),n.normalBuf&&n.normalBuf.destroy(),n.uvBuf&&n.uvBuf.destroy(),n.uvBuf2&&n.uvBuf2.destroy();throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate VBO(s) for morphGeometry: "+p)}},SceneJS.MorphGeometry.prototype.setSource=function(a){this._sourceConfigs=a;var b=this._source;b&&b.configure(a)},SceneJS.MorphGeometry.prototype.getSource=function(){return this._sourceConfigs},SceneJS.MorphGeometry.prototype.setFactor=function(a){a=a||0;var b=this._core,c=b.keys,d=b.key1,e=b.key2,f=b.factor;if(ac[c.length-1])d=c.length-2,e=d+1;else{for(;c[d]>a;)d--,e--;for(;c[e]0?b[c-1]:a},SceneJS.MorphGeometry.prototype._makeHash=function(){var a=this._core;if(a.targets.length>0){var b=a.targets[0],c="t",d="f";a.hash=[b.vertexBuf?c:d,b.normalBuf?c:d,b.uvBuf?c:d,b.uvBuf2?c:d].join("")}else a.hash=""},SceneJS.MorphGeometry.prototype._destroy=function(){if(1==this._core.useCount){if(document.getElementById(this._engine.canvas.canvasId))for(var a,b=this._core,c=0,d=b.targets.length;d>c;c++)a=b.targets[c],a.vertexBuf&&a.vertexBuf.destroy(),a.normalBuf&&a.normalBuf.destroy(),a.uvBuf&&a.uvBuf.destroy(),a.uvBuf2&&a.uvBuf2.destroy();this._source&&this._source.destroy&&this._source.destroy()}}},function(){var a={type:"name",stateId:SceneJS._baseStateId++,name:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.name=a,c=0}),SceneJS.Name=SceneJS_NodeFactory.createNodeType("name"),SceneJS.Name.prototype._init=function(a){this.setName(a.name),this._core.nodeId=this.id},SceneJS.Name.prototype.setName=function(a){this._core.name=a||"unnamed",this._engine.branchDirty(this)},SceneJS.Name.prototype.getName=function(){return this._core.name},SceneJS.Name.prototype._compile=function(d){this._engine.display.name=b[c++]=this._core;for(var e,f=[],g=0;c>g;g++)e=b[g].name,e&&f.push(e);this._core.path=f.join("."),this._compileNodes(d),this._engine.display.name=--c>0?b[c-1]:a}}(),new function(){function a(a){var c;if(f>0){c={};for(var d in a)a.hasOwnProperty(d)&&void 0!=a[d]&&(c[d]=g(d))}return b(a.props),{props:a,setProps:function(b){h(b,a)},restoreProps:function(a){c&&i(a,c)}}}function b(a){var b;for(var c in a)a.hasOwnProperty(c)&&(b=a[c],void 0!=b&&null!=b&&(k[c]?a[c]=k[c](null,b):l[c]&&(a[c]=l[c](null,b))))}var c,d={type:"renderer",stateId:SceneJS._baseStateId++,props:null},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){c=a.engine.canvas,f=0,a.engine.display.renderer=e[f++]=d});var g=function(a){for(var b,c,d=f-1;d>=0;d--)if(b=e[d].props,b&&(c=b[a],void 0!=c&&null!=c))return b[a];return null},h=function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=k[c];d&&d(a,b[c])}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor),b.clear&&l.clear(a,b.clear)},i=function(a,b){var c;for(var d in b)if(b.hasOwnProperty(d)&&(c=b[d],void 0!=c&&null!=c)){var e=k[d];e&&e(a,c)}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor)},j=function(a,b){if(!b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Null SceneJS.State node config: "'+b+'"');var c=SceneJS._webgl.enumMap[b];if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Unrecognised SceneJS.State node config value: "'+b+'"');var d=a[c];if(!d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"This browser's WebGL does not support renderer node config value: \""+b+'"');return d},k={enableBlend:function(a,b){return a?void(b?a.enable(a.BLEND):a.disable(a.BLEND)):((null==b||void 0==b)&&(b=!1),b)},blendColor:function(a,b){return a?void a.blendColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},blendEquation:function(a,b){return a?void a.blendEquation(a,j(a,b)):b||"funcAdd"},blendEquationSeparate:function(a,b){return a?void a.blendEquation(j(a,b.rgb),j(a,b.alpha)):(b=b||{},{rgb:b.rgb||"funcAdd",alpha:b.alpha||"funcAdd"})},blendFunc:function(a,b){return a?void a.blendFunc(j(a,b.sfactor||"srcAlpha"),j(a,b.dfactor||"oneMinusSrcAlpha")):(b=b||{},{sfactor:b.sfactor||"srcAlpha",dfactor:b.dfactor||"oneMinusSrcAlpha"})},blendFuncSeparate:function(a,b){return a?void a.blendFuncSeparate(j(a,b.srcRGB||"zero"),j(a,b.dstRGB||"zero"),j(a,b.srcAlpha||"zero"),j(a,b.dstAlpha||"zero")):(b=b||{},{srcRGB:b.srcRGB||"zero",dstRGB:b.dstRGB||"zero",srcAlpha:b.srcAlpha||"zero",dstAlpha:b.dstAlpha||"zero"})},clearColor:function(a,b){return a?void a.clearColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},clearDepth:function(a,b){return a?void a.clearDepth(b):null==b||void 0==b?1:b},clearStencil:function(a,b){return a?void a.clearStencil(b):b||0},colorMask:function(a,b){return a?void a.colorMask(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},enableCullFace:function(a,b){return a?void(b?a.enable(a.CULL_FACE):a.disable(a.CULL_FACE)):b},cullFace:function(a,b){return a?void a.cullFace(j(a,b)):b||"back"},enableDepthTest:function(a,b){return a?void(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST)):((null==b||void 0==b)&&(b=!0),b)},depthFunc:function(a,b){return a?void a.depthFunc(j(a,b)):b||"less"},enableDepthMask:function(a,b){return a?void a.depthMask(b):((null==b||void 0==b)&&(b=!0),b)},depthRange:function(a,b){return a?void a.depthRange(b.zNear,b.zFar):(b=b||{},{zNear:void 0==b.zNear||null==b.zNear?0:b.zNear,zFar:void 0==b.zFar||null==b.zFar?1:b.zFar})},frontFace:function(a,b){return a?void a.frontFace(j(a,b)):b||"ccw"},lineWidth:function(a,b){return a?void a.lineWidth(b):b||1},enableScissorTest:function(a,b){return a?void(b?a.enable(a.SCISSOR_TEST):(b=!1,a.disable(a.SCISSOR_TEST))):b}},l={viewport:function(a,b){return a?void a.viewport(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||1,y:b.y||1,width:b.width||c.canvas.width,height:b.height||c.canvas.height})},scissor:function(a,b){return a?void a.scissor(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||0,y:b.y||0,width:b.width||1,height:b.height||1})},clear:function(a,b){if(!a)return b=b||{};var c;b.color&&(c=a.COLOR_BUFFER_BIT),b.depth&&(c|=a.DEPTH_BUFFER_BIT),b.stencil&&(c|=a.STENCIL_BUFFER_BIT)}};SceneJS.Renderer=SceneJS_NodeFactory.createNodeType("renderer"),SceneJS.Renderer.prototype._init=function(a){if(1==this._core.useCount){for(var b in a)a.hasOwnProperty(b)&&(this._core[b]=a[b]);this._core.dirty=!0}},SceneJS.Renderer.prototype.setViewport=function(a){this._core.viewport=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getViewport=function(){return this._core.viewport?{x:this._core.viewport.x,y:this._core.viewport.y,width:this._core.viewport.width,height:this._core.viewport.height}:void 0},SceneJS.Renderer.prototype.setScissor=function(a){this._core.scissor=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getScissor=function(){return this._core.scissor?{x:this._core.scissor.x,y:this._core.scissor.y,width:this._core.scissor.width,height:this._core.scissor.height}:void 0},SceneJS.Renderer.prototype.setClear=function(a){this._core.clear=a?{r:a.r||0,g:a.g||0,b:a.b||0}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getClear=function(){return this._core.clear?{r:this._core.clear.r,g:this._core.clear.g,b:this._core.clear.b}:null},SceneJS.Renderer.prototype.setEnableBlend=function(a){this._core.enableBlend=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getEnableBlend=function(){return this._core.enableBlend},SceneJS.Renderer.prototype.setBlendColor=function(a){this._core.blendColor=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendColor=function(){return this._core.blendColor?{r:this._core.blendColor.r,g:this._core.blendColor.g,b:this._core.blendColor.b,a:this._core.blendColor.a}:void 0},SceneJS.Renderer.prototype.setBlendEquation=function(a){this._core.blendEquation=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquation=function(){return this._core.blendEquation},SceneJS.Renderer.prototype.setBlendEquationSeparate=function(a){this._core.blendEquationSeparate=a?{rgb:a.rgb||"funcAdd",alpha:a.alpha||"funcAdd"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquationSeparate=function(){return this._core.blendEquationSeparate?{rgb:this._core.rgb,alpha:this._core.alpha}:void 0},SceneJS.Renderer.prototype.setBlendFunc=function(a){this._core.blendFunc=a?{sfactor:a.sfactor||"srcAlpha",dfactor:a.dfactor||"one"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendFunc=function(){return this._core.blendFunc?{sfactor:this._core.sfactor,dfactor:this._core.dfactor}:void 0},SceneJS.Renderer.prototype.setBlendFuncSeparate=function(a){this._core.blendFuncSeparate=a?{srcRGB:a.srcRGB||"zero",dstRGB:a.dstRGB||"zero",srcAlpha:a.srcAlpha||"zero",dstAlpha:a.dstAlpha||"zero"}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getBlendFuncSeparate=function(){return this._core.blendFuncSeparate?{srcRGB:this._core.blendFuncSeparate.srcRGB,dstRGB:this._core.blendFuncSeparate.dstRGB,srcAlpha:this._core.blendFuncSeparate.srcAlpha,dstAlpha:this._core.blendFuncSeparate.dstAlpha}:void 0},SceneJS.Renderer.prototype.setEnableCullFace=function(a){this._core.enableCullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableCullFace=function(){return this._core.enableCullFace},SceneJS.Renderer.prototype.setCullFace=function(a){this._core.cullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getCullFace=function(){return this._core.cullFace},SceneJS.Renderer.prototype.setEnableDepthTest=function(a){this._core.enableDepthTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthTest=function(){return this._core.enableDepthTest},SceneJS.Renderer.prototype.setDepthFunc=function(a){this._core.depthFunc=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthFunc=function(){return this._core.depthFunc},SceneJS.Renderer.prototype.setEnableDepthMask=function(a){this._core.enableDepthMask=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthMask=function(){return this._core.enableDepthMask},SceneJS.Renderer.prototype.setClearDepth=function(a){this._core.clearDepth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Renderer.prototype.setDepthRange=function(a){this._core.depthRange=a?{zNear:void 0==a.zNear||null==a.zNear?0:a.zNear,zFar:void 0==a.zFar||null==a.zFar?1:a.zFar}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthRange=function(){return this._core.depthRange?{zNear:this._core.depthRange.zNear,zFar:this._core.depthRange.zFar}:void 0},SceneJS.Renderer.prototype.setFrontFace=function(a){this._core.frontFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getFrontFace=function(){return this._core.frontFace},SceneJS.Renderer.prototype.setLineWidth=function(a){this._core.lineWidth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Renderer.prototype.setEnableScissorTest=function(a){this._core.enableScissorTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableScissorTest=function(){return this._core.enableScissorTest},SceneJS.Renderer.prototype.setClearStencil=function(a){this._core.clearStencil=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearStencil=function(){return this._core.clearStencil},SceneJS.Renderer.prototype.setColorMask=function(a){this._core.colorMask=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getColorMask=function(){return this._core.colorMask?{r:this._core.colorMask.r,g:this._core.colorMask.g,b:this._core.colorMask.b,a:this._core.colorMask.a}:void 0},SceneJS.Renderer.prototype._compile=function(b){this._core.dirty&&(this._core.props=a(this._core),this._core.dirty=!1),this._engine.display.renderer=e[f++]=this._core,this._compileNodes(b),this._engine.display.renderer=--f>0?e[f-1]:d}},function(){var a={less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL"},b={type:"depthBuffer",stateId:SceneJS._baseStateId++,enabled:!0,clearDepth:1,depthFunc:null,_depthFuncName:"less"},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){null===b.depthFunc&&(b.depthFunc=a.engine.canvas.gl.LESS),a.engine.display.depthBuffer=b,d=0}),SceneJS.DepthBuf=SceneJS_NodeFactory.createNodeType("depthBuffer"),SceneJS.DepthBuf.prototype._init=function(a){void 0!=a.enabled?this.setEnabled(a.enabled):1==this._core.useCount&&this.setEnabled(!0),void 0!=a.clearDepth?this.setClearDepth(a.clearDepth):1==this._core.useCount&&this.setClearDepth(1),void 0!=a.depthFunc?this.setDepthFunc(a.depthFunc):1==this._core.useCount&&this.setDepthFunc("less"),void 0!=a.clear?this.setClear(a.clear):1==this._core.useCount&&this.setClear(!0)},SceneJS.DepthBuf.prototype.setEnabled=function(a){return this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getEnabled=function(){return this._core.enabled},SceneJS.DepthBuf.prototype.setClear=function(a){return this._core.clear!=a&&(this._core.clear=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClear=function(){return this._core.clear},SceneJS.DepthBuf.prototype.setClearDepth=function(a){return this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.DepthBuf.prototype.setDepthFunc=function(b){if(this._core._depthFuncName!=b){var c=a[b];if(void 0==c)throw"unsupported value for 'clearFunc' attribute on depthBuffer node: '"+b+"' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";this._core.depthFunc=this._engine.canvas.gl[c],this._core._depthFuncName=b,this._engine.display.imageDirty=!0}return this},SceneJS.DepthBuf.prototype.getDepthFunc=function(){return this._core._depthFuncName},SceneJS.DepthBuf.prototype._compile=function(a){this._engine.display.depthBuffer=c[d++]=this._core,this._compileNodes(a),this._engine.display.depthBuffer=--d>0?c[d-1]:b}}(),function(){var a={type:"colorBuffer",stateId:SceneJS._baseStateId++,blendEnabled:!1,colorMask:{r:!0,g:!0,b:!0,a:!0}},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.colorBuffer=a,c=0}),SceneJS.ColorBuffer=SceneJS_NodeFactory.createNodeType("colorBuffer"),SceneJS.ColorBuffer.prototype._init=function(a){void 0!=a.blendEnabled?this.setBlendEnabled(a.blendEnabled):1==this._core.useCount&&this.setBlendEnabled(!1),this.setColorMask(a)},SceneJS.ColorBuffer.prototype.setBlendEnabled=function(a){this._core.blendEnabled!=a&&(this._core.blendEnabled=a,this._engine.display.imageDirty=!0),this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getBlendEnabled=function(){return this._core.blendEnabled},SceneJS.ColorBuffer.prototype.setColorMask=function(a){this._core.colorMask={r:void 0!=a.r&&null!=a.r?a.r:!0,g:void 0!=a.g&&null!=a.g?a.g:!0,b:void 0!=a.b&&null!=a.b?a.b:!0,a:void 0!=a.a&&null!=a.a?a.a:!0},this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getColorMask=function(){return this._core.colorMask},SceneJS.ColorBuffer.prototype._compile=function(d){this._engine.display.colorBuffer=b[c++]=this._core,this._compileNodes(d),this._engine.display.colorBuffer=--c>0?b[c-1]:a,this._engine.display.imageDirty=!0}}(),function(){var a={type:"view",stateId:SceneJS._baseStateId++,scissorTestEnabled:!1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.view=a,c=0}),SceneJS.View=SceneJS_NodeFactory.createNodeType("view"),SceneJS.View.prototype._init=function(a){void 0!=a.scissorTestEnabled?this.setScissorTestEnabled(a.scissorTestEnabled):1==this._core.useCount&&this.setScissorTestEnabled(!1)},SceneJS.View.prototype.setScissorTestEnabled=function(a){return this._core.scissorTestEnabled!=a&&(this._core.scissorTestEnabled=a,this._engine.display.imageDirty=!0),this},SceneJS.View.prototype.getScissorTestEnabled=function(){return this._core.scissorTestEnabled},SceneJS.View.prototype._compile=function(d){this._engine.display.view=b[c++]=this._core,this._compileNodes(d),this._engine.display.view=--c>0?b[c-1]:a}}(),SceneJS.Scene=SceneJS_NodeFactory.createNodeType("scene"),SceneJS.Scene.prototype._init=function(a){a.tagMask&&this.setTagMask(a.tagMask),this._tagSelector=null,this.transparent=a.transparent===!0},SceneJS.Scene.prototype.loseWebGLContext=function(){this._engine.loseWebGLContext()},SceneJS.Scene.prototype.getCanvas=function(){return this._engine.canvas.canvas},SceneJS.Scene.prototype.getGL=function(){return this._engine.canvas.gl},SceneJS.Scene.prototype.getZBufferDepth=function(){var a=this._engine.canvas.gl;return a.getParameter(a.DEPTH_BITS)},SceneJS.Scene.prototype.setSSAAMultiplier=function(a){return this._engine.canvas.setSSAAMultiplier(a)},SceneJS.Scene.prototype.setTagMask=function(a){a=a||"XXXXXXXXXXXXXXXXXXXXXXXXXX",this._tagSelector||(this._tagSelector={}),this._tagSelector.mask=a,this._tagSelector.regex=a?new RegExp(a):null,this._engine.display.selectTags(this._tagSelector)},SceneJS.Scene.prototype.getTagMask=function(){return this._tagSelector?this._tagSelector.mask:null},SceneJS.Scene.prototype.setNumPasses=function(a){this._engine.setNumPasses(a)},SceneJS.Scene.prototype.renderFrame=function(a){return this._engine.renderFrame(a)},SceneJS.Scene.prototype.needFrame=function(){this._engine.display.imageDirty=!0},SceneJS.Scene.prototype.start=function(a){this._engine.start(a)},SceneJS.Scene.prototype.setFPS=function(a){this._engine.fps=a},SceneJS.Scene.prototype.pause=function(a){this._engine.pause(a)},SceneJS.Scene.prototype.isRunning=function(){return this._engine.running},SceneJS.Scene.prototype.pick=function(a,b,c){var d=this._engine.pick(a,b,c);return this.renderFrame({force:!0}),d?(this.publish("pick",d),d):void this.publish("nopick")},SceneJS.Scene.prototype.readPixels=function(a,b){return this._engine.readPixels(a,b)},SceneJS.Scene.prototype._destroy=function(){this.destroyed||(delete SceneJS._engines[this.id],SceneJS._engineIds.removeItem(this.id),this.destroyed=!0)},SceneJS.Scene.prototype.isActive=function(){return!this._engine.destroyed},SceneJS.Scene.prototype.stop=function(){this._engine.stop()},SceneJS.Scene.prototype.containsNode=function(a){return!!this._engine.findNode(a)},SceneJS.Scene.prototype.findNodes=function(a){return this._engine.findNodes(a)},SceneJS.Scene.prototype.findNode=function(a,b){return this.getNode(a,b)},SceneJS.Scene.prototype.getNode=function(a,b){var c=this._engine.findNode(a);return c?(b&&b(c),c):b?void this.once("nodes/"+a,b):null},SceneJS.Scene.prototype.hasCore=function(a,b){return this._engine.hasCore(a,b)},SceneJS.Scene.prototype.getStatus=function(){var a=SceneJS_sceneStatusModule.sceneStatus[this.id];return a?SceneJS._shallowClone(a):{destroyed:!0}},new function(){function a(a){for(var b,c,d={},e=0;i>e;e++){b=a[e];for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c])}return d}var b={type:"shader",stateId:SceneJS._baseStateId++,hash:"",empty:!0,shader:{}},c=[],d=[],e=[],f=[],g=[],h=[],i=0,j=!0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.shader=b,i=0,j=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(k){if(j){if(i>0){var l={type:"shader",stateId:c[i-1],hash:c.slice(0,i).join("."),shaders:{fragment:{code:f.slice(0,i).join(""),hooks:a(g)},vertex:{code:d.slice(0,i).join(""),hooks:a(e)}},paramsStack:h.slice(0,i)};k.display.shader=l}else k.display.shader=b;j=!1}}),SceneJS.Shader=SceneJS_NodeFactory.createNodeType("shader"),SceneJS.Shader.prototype._init=function(a){1==this._core.useCount&&(this._setShaders(a.shaders),this.setParams(a.params))},SceneJS.Shader.prototype._setShaders=function(a){a=a||[],this._core.shaders={};for(var b,c=0,d=a.length;d>c;c++){if(b=a[c],!b.stage)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"shader 'stage' attribute expected");var e;b.code&&(e=SceneJS._isArray(b.code)?b.code.join(""):b.code),this._core.shaders[b.stage]={code:e,hooks:b.hooks}}},SceneJS.Shader.prototype.setParams=function(a){a=a||{};var b=this._core.params;b||(b=this._core.params={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.Shader.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.Shader.prototype._compile=function(a){c[i]=this._core.coreId;var b=this._core.shaders,k=b.fragment||{},l=b.vertex||{};f[i]=k.code||"",g[i]=k.hooks||{},d[i]=l.code||"", -e[i]=l.hooks||{},h[i]=this._core.params||{},i++,j=!0,this._compileNodes(a),i--,j=!0}},new function(){var a,b={type:"shaderParams",stateId:SceneJS._baseStateId++,empty:!0},c=[],d=[],e=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(c){c.engine.display.shaderParams=b,e=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(e>0){var g={type:"shaderParams",stateId:c[e-1],paramsStack:d.slice(0,e)};f.display.shaderParams=g}else f.display.shaderParams=b;a=!1}}),SceneJS.ShaderParams=SceneJS_NodeFactory.createNodeType("shaderParams"),SceneJS.ShaderParams.prototype._init=function(a){1==this._core.useCount&&this.setParams(a.params)},SceneJS.ShaderParams.prototype.setParams=function(a){a=a||{};var b=this._core;b.params||(b.params={});for(var c in a)a.hasOwnProperty(c)&&(b.params[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.ShaderParams.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.ShaderParams.prototype._compile=function(b){c[e]=this._core.coreId,d[e]=this._core.params,e++,a=!0,this._compileNodes(b),e--,a=!0}},function(){var a={type:"style",stateId:SceneJS._baseStateId++,lineWidth:1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.style=a,c=0}),SceneJS.Style=SceneJS_NodeFactory.createNodeType("style"),SceneJS.Style.prototype._init=function(a){void 0!=a.lineWidth&&this.setLineWidth(a.lineWidth)},SceneJS.Style.prototype.setLineWidth=function(a){return this._core.lineWidth!=a&&(this._core.lineWidth=a,this._engine.display.imageDirty=!0),this},SceneJS.Style.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Style.prototype._compile=function(d){this._engine.display.style=b[c++]=this._core,this._compileNodes(d),this._engine.display.style=--c>0?b[c-1]:a}}(),function(){var a={type:"tag",stateId:SceneJS._baseStateId++,tag:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.tag=a,c=0}),SceneJS.Tag=SceneJS_NodeFactory.createNodeType("tag"),SceneJS.Tag.prototype._init=function(a){if(1==this._core.useCount){if(!a.tag)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"tag node attribute missing : 'tag'");this.setTag(a.tag)}},SceneJS.Tag.prototype.setTag=function(a){var b=this._core;b.tag=a,b.pattern=null,b.matched=!1,this._engine.display.drawListDirty=!0},SceneJS.Tag.prototype.getTag=function(){return this._core.tag},SceneJS.Tag.prototype._compile=function(d){this._engine.display.tag=b[c++]=this._core,this._compileNodes(d),this._engine.display.tag=--c>0?b[c-1]:a}}(),new function(){var a={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.texture=a,c=0}),SceneJS.Texture=SceneJS_NodeFactory.createNodeType("_texture"),SceneJS.Texture.prototype._init=function(a){if(1==this._core.useCount){this._core.layers=[],this._core.params={};var b=void 0==a.waitForLoad?!0:a.waitForLoad;if(!a.layers)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers missing");if(!SceneJS._isArray(a.layers))throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers should be an array");for(var c,d=this._engine.canvas.gl,e=0;ec;c++)h._loadLayerTexture(b,a[c])}}},SceneJS.Texture.prototype._loadLayerTexture=function(a,b){var c=this,d=b.source;if(d){if(!d.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"texture layer config expected: source.type");SceneJS.Plugins.getPlugin("texture",d.type,function(e){if(!e.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'getSource' method missing on plugin for texture source type '"+d.type+"'.");var f=e.getSource({gl:a});if(!f.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'subscribe' method missing on plugin for texture source type '"+d.type+"'");var g=SceneJS_sceneStatusModule.taskStarted(c,"Loading texture");f.subscribe(function(){var d=!1;return function(e){d?c._engine.display.imageDirty=!0:(d=!0,c._setLayerTexture(a,b,e),SceneJS_sceneStatusModule.taskFinished(g))}}()),f.configure&&f.configure(d),b._source=f})}else{var e=b.uri||b.src,f=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),g=new Image;g.onload=function(){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);var e=SceneJS_configsModule.configs.maxTextureSize;e&&(g=SceneJS._webgl.clampImageSize(g,e)),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c._ensureImageSizePowerOfTwo(g)),c._setLayerTexture(a,b,d),SceneJS_sceneStatusModule.taskFinished(f),c._engine.display.imageDirty=!0},g.onerror=function(){SceneJS_sceneStatusModule.taskFailed(f)},0==e.indexOf("data")?g.src=e:(g.crossOrigin="Anonymous",g.src=e)}},SceneJS.Texture.prototype._ensureImageSizePowerOfTwo=function(a){if(!this._isPowerOfTwo(a.width)||!this._isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=this._nextHighestPowerOfTwo(a.width),b.height=this._nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b,a.crossOrigin=""}return a},SceneJS.Texture.prototype._isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS.Texture.prototype._nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS.Texture.prototype._setLayerTexture=function(a,b,c){b.texture=new SceneJS._webgl.Texture2D(a,{texture:c,minFilter:this._getGLOption("minFilter",a,b,a.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",a,b,a.LINEAR),wrapS:this._getGLOption("wrapS",a,b,a.REPEAT),wrapT:this._getGLOption("wrapT",a,b,a.REPEAT),isDepth:this._getOption(b.isDepth,!1),depthMode:this._getGLOption("depthMode",a,b,a.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",a,b,a.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",a,b,a.LEQUAL),flipY:this._getOption(b.flipY,!0),width:this._getOption(b.width,1),height:this._getOption(b.height,1),internalFormat:this._getGLOption("internalFormat",a,b,a.LEQUAL),sourceFormat:this._getGLOption("sourceType",a,b,a.ALPHA),sourceType:this._getGLOption("sourceType",a,b,a.UNSIGNED_BYTE),update:null}),this.destroyed&&b.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._getGLOption=function(a,b,c,d){var e=c[a];if(void 0==e)return d;var f=SceneJS._webgl.enumMap[e];if(void 0==f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+e+"'");var g=b[f];return g},SceneJS.Texture.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.Texture.prototype.setLayer=function(a){if(void 0==a.index||null==a.index)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index null or undefined");if(a.index<0||a.index>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(parseInt(a.index),a),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype.setLayers=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._setLayer=function(a,b){b=b||{};var c=this._core.layers[a];if(void 0!=b.blendFactor&&null!=b.blendFactor&&(c.blendFactor=b.blendFactor),b.source){var d=c._source;d&&d.configure&&d.configure(b.source)}(b.translate||b.rotate||b.scale)&&this._setLayerTransform(b,c)},SceneJS.Texture.prototype._setLayerTransform=function(a,b){var c,d;if(a.translate){var e=a.translate;void 0!=e.x&&(b.translate.x=e.x),void 0!=e.y&&(b.translate.y=e.y),c=SceneJS_math_translationMat4v([e.x||0,e.y||0,0])}if(a.scale){var f=a.scale;void 0!=f.x&&(b.scale.x=f.x),void 0!=f.y&&(b.scale.y=f.y),d=SceneJS_math_scalingMat4v([f.x||1,f.y||1,1]),c=c?SceneJS_math_mulMat4(c,d):d}if(a.rotate){var g=a.rotate;void 0!=g.z&&(b.rotate.z=g.z||0),d=SceneJS_math_rotationMat4v(.0174532925*g.z,[0,0,1]),c=c?SceneJS_math_mulMat4(c,d):d}c&&(b.matrix=c,b.matrixAsArray?b.matrixAsArray.set(b.matrix):b.matrixAsArray=new Float32Array(b.matrix),b.matrixAsArray=new Float32Array(b.matrix))},SceneJS.Texture.prototype._compile=function(d){this._core.hash||this._makeHash(),this._engine.display.texture=b[c++]=this._core,this._compileNodes(d),this._engine.display.texture=--c>0?b[c-1]:a},SceneJS.Texture.prototype._makeHash=function(){var a,b=this._core;if(b.layers&&b.layers.length>0){for(var c,d=b.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");a=e.join("")}else a="";b.hash!=a&&(b.hash=a)},SceneJS.Texture.prototype._destroy=function(){if(1==this._core.useCount)for(var a,b,c=this._core.layers,d=0,e=c.length;e>d;d++)a=c[d],a.texture&&a.texture.destroy(),b=a._source,b&&b.destroy&&b.destroy()}},new function(){function a(){var a,b;(0!=this.translate.x||0!=this.translate.y)&&(a=SceneJS_math_translationMat4v([this.translate.x||0,this.translate.y||0,0])),(1!=this.scale.x||1!=this.scale.y)&&(b=SceneJS_math_scalingMat4v([this.scale.x||1,this.scale.y||1,1]),a=a?SceneJS_math_mulMat4(a,b):b),0!=this.rotate&&(b=SceneJS_math_rotationMat4v(.0174532925*this.rotate,[0,0,1]),a=a?SceneJS_math_mulMat4(a,b):b),a&&(this.matrix=a,this.matrixAsArray?this.matrixAsArray.set(this.matrix):this.matrixAsArray=new Float32Array(this.matrix)),this._matrixDirty=!1}var b={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.texture=b,d=0});var c=[],d=0;SceneJS.TextureMap=SceneJS_NodeFactory.createNodeType("texture"),SceneJS.TextureMap.prototype._init=function(b){var c=this;if(1==this._core.useCount){if(b.applyFrom&&"uv"!=b.applyFrom&&"uv2"!=b.applyFrom&&"normal"!=b.applyFrom&&"geometry"!=b.applyFrom)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyFrom value is unsupported - should be either 'uv', 'uv2', 'normal' or 'geometry'");if(b.applyTo&&"baseColor"!=b.applyTo&&"color"!=b.applyTo&&"specular"!=b.applyTo&&"emit"!=b.applyTo&&"alpha"!=b.applyTo&&"normals"!=b.applyTo&&"shine"!=b.applyTo)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyTo value is unsupported - should be either 'color', 'baseColor', 'specular' or 'normals'");if(b.blendMode&&"add"!=b.blendMode&&"multiply"!=b.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layer blendMode value is unsupported - should be either 'add' or 'multiply'");"color"==b.applyTo&&(b.applyTo="baseColor"),SceneJS._apply({waitForLoad:void 0==b.waitForLoad?!0:b.waitForLoad,texture:null,applyFrom:b.applyFrom?b.applyFrom:"uv",applyTo:b.applyTo?b.applyTo:"baseColor",blendMode:b.blendMode?b.blendMode:"multiply",blendFactor:void 0!=b.blendFactor&&null!=b.blendFactor?b.blendFactor:1,translate:b.translate?SceneJS._apply(b.translate,{x:0,y:0}):{x:0,y:0},scale:b.scale?SceneJS._apply(b.scale,{x:1,y:1}):{x:1,y:1},rotate:b.rotate||0,matrix:null,_matrixDirty:!0,buildMatrix:a},this._core),a.call(this._core),b.src?(this._core.src=b.src,this._loadTexture(b.src)):b.image?(this._core.image=b.image,this._initTexture(b.image)):b.target&&this.getScene().getNode(b.target,function(a){c.setTarget(a)}),this._core.webglRestored=function(){c._core.image?c._initTexture(c._core.image):c._core.src?c._loadTexture(c._core.src):c._core.target}}},SceneJS.TextureMap.prototype._loadTexture=function(a){var b=this,c=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),d=new Image;d.onload=function(){b._initTexture(d),SceneJS_sceneStatusModule.taskFinished(c),b._engine.display.imageDirty=!0},d.onerror=function(){SceneJS_sceneStatusModule.taskFailed(c)},0==a.indexOf("data")?d.src=a:(d.crossOrigin="Anonymous",d.src=a)},SceneJS.TextureMap.prototype._initTexture=function(a){var b=this._engine.canvas.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);var d=SceneJS_configsModule.configs.maxTextureSize;d&&(a=SceneJS._webgl.clampImageSize(a,d)),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(a)),this._core.image=a,this._core.texture=new SceneJS._webgl.Texture2D(b,{texture:c,minFilter:this._getGLOption("minFilter",b.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",b.LINEAR),wrapS:this._getGLOption("wrapS",b.REPEAT),wrapT:this._getGLOption("wrapT",b.REPEAT),isDepth:this._getOption(this._core.isDepth,!1),depthMode:this._getGLOption("depthMode",b.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",b.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",b.LEQUAL),flipY:this._getOption(this._core.flipY,!0),width:this._getOption(this._core.width,1),height:this._getOption(this._core.height,1),internalFormat:this._getGLOption("internalFormat",b.ALPHA),sourceFormat:this._getGLOption("sourceFormat",b.ALPHA),sourceType:this._getGLOption("sourceType",b.UNSIGNED_BYTE),update:null}),this.destroyed&&this._core.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype._getGLOption=function(a,b){var c=this._engine.canvas.gl,d=this._core[a];if(void 0==d)return b;var e=SceneJS._webgl.enumMap[d];if(void 0==e)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+d+"'");return c[e]},SceneJS.TextureMap.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.TextureMap.prototype.setSrc=function(a){this._core.image=null,this._core.src=a,this._core.target=null,this._loadTexture(a)},SceneJS.TextureMap.prototype.setImage=function(a){this._core.image=a,this._core.src=null,this._core.target=null,this._initTexture(a)},SceneJS.TextureMap.prototype.setTarget=function(a){return"colorTarget"!=a.type&&"depthTarget"!=a.type?void console.log("Target node type not compatible: "+a.type):(delete this._core.src,this._core.target=a,this._core.src=null,this._core.image=null,this._core.texture=a._core.renderBuf.getTexture(),this._core.texture.bufType=a._core.bufType,void(this._engine.display.imageDirty=!0))},SceneJS.TextureMap.prototype.setBlendFactor=function(a){this._core.blendFactor=a,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getBlendFactor=function(){return this._core.blendFactor},SceneJS.TextureMap.prototype.setTranslate=function(a){this._core.translate||(this._core.translate={x:0,y:0}),this._core.translate.x=a.x,this._core.translate.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getTranslate=function(){return this._core.translate},SceneJS.TextureMap.prototype.setScale=function(a){this._core.scale||(this._core.scale={x:0,y:0}),this._core.scale.x=a.x,this._core.scale.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getScale=function(){return this._core.scale},SceneJS.TextureMap.prototype.setRotate=function(a){this._core.rotate=a,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getRotate=function(){return this._core.rotate},SceneJS.TextureMap.prototype.getMatrix=function(){return this._core._matrixDirty&&this._core.buildMatrix.call(this.core)(),this.core.matrix},SceneJS.TextureMap.prototype._compile=function(a){this.__core||(this.__core=this._engine._coreFactory.getCore("texture"));var e=this._engine.display.texture;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),c[d++]=this.__core,this._engine.display.texture=this.__core,this._compileNodes(a),this._engine.display.texture=--d>0?c[d-1]:b},SceneJS.TextureMap.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.TextureMap.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&!this._core.target&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}},function(){var a={type:"cubemap",stateId:SceneJS._baseStateId++,empty:!0,texture:null,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.cubemap=a,c=0}),SceneJS.Reflect=SceneJS_NodeFactory.createNodeType("reflect"),SceneJS.Reflect.prototype._init=function(a){if(1==this._core.useCount){if(this._core.hash="y",a.blendMode&&"add"!=a.blendMode&&"multiply"!=a.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"reflection blendMode value is unsupported - should be either 'add' or 'multiply'");this._core.blendMode=a.blendMode||"multiply",this._core.intensity=void 0!=a.intensity&&null!=a.intensity?a.intensity:1,this._core.applyTo="reflect";for(var b=this,c=this._engine.canvas.gl,d=c.createTexture(),e=[c.TEXTURE_CUBE_MAP_POSITIVE_X,c.TEXTURE_CUBE_MAP_NEGATIVE_X,c.TEXTURE_CUBE_MAP_POSITIVE_Y,c.TEXTURE_CUBE_MAP_NEGATIVE_Y,c.TEXTURE_CUBE_MAP_POSITIVE_Z,c.TEXTURE_CUBE_MAP_NEGATIVE_Z],f=[],g=SceneJS_sceneStatusModule.taskStarted(this,"Loading reflection texture"),h=!1,i=0;ii;i++)c.texImage2D(e[i],0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(f[i]));b._core.texture=new SceneJS._webgl.Texture2D(c,{texture:d,target:c.TEXTURE_CUBE_MAP,minFilter:c.LINEAR,magFilter:c.LINEAR,wrapS:c.CLAMP_TO_EDGE,wrapT:c.CLAMP_TO_EDGE}),SceneJS_sceneStatusModule.taskFinished(g),b._engine.display.imageDirty=!0}}}(),j.onerror=function(){h=!0,SceneJS_sceneStatusModule.taskFailed(g)},j.src=a.src[i]}}},SceneJS.Reflect.prototype._compile=function(d){this.__core||(this.__core=this._engine._coreFactory.getCore("cubemap"));var e=this._engine.display.cubemap;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),b[c++]=this.__core,this._engine.display.cubemap=this.__core,this._compileNodes(d),this._engine.display.cubemap=--c>0?b[c-1]:a},SceneJS.Reflect.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode);b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.Reflect.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}}(),SceneJS.XForm=SceneJS_NodeFactory.createNodeType("xform"),SceneJS.XForm.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.XForm.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.XForm.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.XForm.prototype.setElements=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.XForm elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.XForm.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Matrix=SceneJS_NodeFactory.createNodeType("matrix"),SceneJS.Matrix.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.Matrix.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Matrix.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Matrix.prototype.setMatrix=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Matrix elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Matrix.prototype.setElements=SceneJS.Matrix.prototype.setMatrix,SceneJS.Matrix.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Rotate=SceneJS_NodeFactory.createNodeType("rotate"),SceneJS.Rotate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setAngle(a.angle),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_rotationMat4v(b.angle*Math.PI/180,[b.x,b.y,b.z])}}},SceneJS.Rotate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Rotate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Rotate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for rotate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.setAngle=function(a){this._core.angle=a||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getAngle=function(){return this._core.angle},SceneJS.Rotate.prototype.setXYZ=function(a){a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Rotate.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getX=function(){return this._core.x},SceneJS.Rotate.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getY=function(){return this._core.y},SceneJS.Rotate.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getZ=function(){return this._core.z},SceneJS.Rotate.prototype.incAngle=function(a){this._core.angle+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Translate=SceneJS_NodeFactory.createNodeType("translate"),SceneJS.Translate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_translationMat4v([b.x,b.y,b.z],b.matrix)}}},SceneJS.Translate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Translate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Translate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for translate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Translate.prototype.setXYZ=function(a){return a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Translate.prototype.setX=function(a){return this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setY=function(a){return this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setZ=function(a){return this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incX=function(a){return this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incY=function(a){return this._core.y+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incZ=function(a){return this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getX=function(){return this._core.x},SceneJS.Translate.prototype.getY=function(){return this._core.y},SceneJS.Translate.prototype.getZ=function(){return this._core.z},SceneJS.Translate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Scale=SceneJS_NodeFactory.createNodeType("scale"),SceneJS.Scale.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_scalingMat4v([b.x,b.y,b.z])}}},SceneJS.Scale.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Scale.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Scale.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for scale node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setXYZ=function(a){a=a||{},this._core.x=void 0==a.x?1:a.x,this._core.y=void 0==a.y?1:a.y,this._core.z=void 0==a.z?1:a.z,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Scale.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getX=function(){return this._core.x},SceneJS.Scale.prototype.getY=function(){return this._core.y},SceneJS.Scale.prototype.getZ=function(){return this._core.z},SceneJS.Scale.prototype.incX=function(a){this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.incY=function(a){this._core.y+=a,this._core.matrixDirty=!0},SceneJS.Scale.prototype.incZ=function(a){this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()};var SceneJS_modelXFormStack=new function(){var a=SceneJS_math_identityMat4(),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(SceneJS_math_identityMat4(),SceneJS_math_mat4())),d=new Float32Array(c),e={type:"xform",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,parent:null,cores:[],numCores:0,dirty:!1,matrixDirty:!1},f=[],g=0;this.top=e;var h,i=this;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){g=0,i.top=e,h=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(a){h&&(g>0?a.display.modelTransform=f[g-1]:a.display.modelTransform=e,h=!1)}),this.buildCore=function(a){function b(a){a.dirty=!0,a.matrixDirty=!0;for(var c=0,d=a.numCores;d>c;c++)b(a.cores[c])}a.parent=null,a.cores=[],a.numCores=0,a.matrixDirty=!1,a.matrix=SceneJS_math_identityMat4(),a.mat=new Float32Array(a.matrix),a.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(a.matrix,SceneJS_math_mat4()))),a.dirty=!1,a.setDirty=function(){a.matrixDirty=!0,a.dirty,b(a)},a.build=function(){a.matrixDirty&&(a.buildMatrix&&a.buildMatrix(),a.matrixDirty=!1);var b,c=a.parent;if(c)for(b=a.matrix.slice(0);c;)c.matrixDirty&&(c.buildMatrix&&c.buildMatrix(),c.mat.set(c.matrix),c.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(c.matrix,SceneJS_math_mat4()))),c.matrixDirty=!1),SceneJS_math_mulMat4(c.matrix,b,b),!c.dirty,c=c.parent;else b=a.matrix;a.mat.set(b),a.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4()))),a.dirty=!1}},this.push=function(a){f[g++]=a,a.parent=this.top,a.dirty=!0,this.top&&(this.top.cores[this.top.numCores++]=a),a.numCores=0,this.top=a,h=!0},this.pop=function(){this.top=--g>0?f[g-1]:e,h=!0}};SceneJS.Types=new function(){this.addType=function(a,b){SceneJS_NodeFactory.createNodeType(a,b,function(a){var c;for(var d in b)if(b.hasOwnProperty(d))switch(c=b[d],d){case"init":case"construct":!function(){var c=b[d];a.prototype._init=function(a){c.call(this,a)},a.prototype._fromPlugin=!0}();break;case"destroy":case"destruct":a.prototype._destroy=c;break;default:a.prototype[d]=c}})},this.hasType=function(a){return!!SceneJS_NodeFactory.nodeTypes[a]}};var SceneJS_Display=function(a){this._canvas=a.canvas,this._programFactory=new SceneJS_ProgramFactory({canvas:a.canvas}),this._chunkFactory=new SceneJS_ChunkFactory,this.transparent=a.transparent===!0, -this.enable=null,this.flags=null,this.layer=null,this.stage=null,this.renderer=null,this.depthBuffer=null,this.colorBuffer=null,this.view=null,this.lights=null,this.material=null,this.texture=null,this.cubemap=null,this.modelTransform=null,this.viewTransform=null,this.projTransform=null,this.renderTarget=null,this.clips=null,this.morphGeometry=null,this.name=null,this.tag=null,this.renderListeners=null,this.shader=null,this.shaderParams=null,this.style=null,this.geometry=null,this._objectFactory=new SceneJS_ObjectFactory,this._objects={},this._ambientColor=[0,0,0,1],this._objectList=[],this._objectListLen=0,this._drawList=[],this._drawListLen=0,this._pickDrawList=[],this._pickDrawListLen=0,this._targetList=[],this._targetListLen=0,this._frameCtx={pickNames:[],canvas:this._canvas,VAO:null},this._frameCtx.renderListenerCtx=new SceneJS.RenderContext(this._frameCtx),this.objectListDirty=!0,this.stateOrderDirty=!0,this.stateSortDirty=!0,this.drawListDirty=!0,this.imageDirty=!0,this.pickBufDirty=!0,this.rayPickBufDirty=!0};SceneJS_Display.prototype.webglRestored=function(){this._programFactory.webglRestored(),this._chunkFactory.webglRestored();var a=this._canvas.gl;this.pickBuf&&this.pickBuf.webglRestored(a),this.rayPickBuf&&this.rayPickBuf.webglRestored(a),this.imageDirty=!0},SceneJS_Display.prototype.buildObject=function(a){var b=this._objects[a];b||(b=this._objects[a]=this._objectFactory.getObject(a),this.objectListDirty=!0),b.stage=this.stage,b.layer=this.layer,b.renderTarget=this.renderTarget,b.texture=this.texture,b.cubemap=this.cubemap,b.geometry=this.geometry,b.enable=this.enable,b.flags=this.flags,b.tag=this.tag;var c=[this.geometry.hash,this.shader.hash,this.clips.hash,this.morphGeometry.hash,this.texture.hash,this.cubemap.hash,this.lights.hash,this.flags.hash].join(";");b.program&&c==b.hash||(b.program&&this._programFactory.putProgram(b.program),b.program=this._programFactory.getProgram(c,this),b.hash=c),this._setChunk(b,0,"program"),this._setChunk(b,1,"xform",this.modelTransform),this._setChunk(b,2,"lookAt",this.viewTransform),this._setChunk(b,3,"camera",this.projTransform),this._setChunk(b,4,"flags",this.flags),this._setChunk(b,5,"shader",this.shader),this._setChunk(b,6,"shaderParams",this.shaderParams),this._setChunk(b,7,"style",this.style),this._setChunk(b,8,"depthBuffer",this.depthBuffer),this._setChunk(b,9,"colorBuffer",this.colorBuffer),this._setChunk(b,10,"view",this.view),this._setChunk(b,11,"name",this.name),this._setChunk(b,12,"lights",this.lights),this._setChunk(b,13,"material",this.material),this._setChunk(b,14,"texture",this.texture),this._setChunk(b,15,"cubemap",this.cubemap),this._setChunk(b,16,"clips",this.clips),this._setChunk(b,17,"renderer",this.renderer),this._setChunk(b,18,"geometry",this.morphGeometry,this.geometry),this._setChunk(b,19,"listeners",this.renderListeners),this._setChunk(b,20,"draw",this.geometry)},SceneJS_Display.prototype._setChunk=function(a,b,c,d,e){var f,g=this._chunkFactory.chunkTypes[c];if(d){if(d.empty){var h=a.chunks[b];return h&&this._chunkFactory.putChunk(h),void(a.chunks[b]=null)}f=g.prototype.programGlobal?"_"+d.stateId:"p"+a.program.id+"_"+d.stateId,e&&(f+="__"+e.stateId)}else f="p"+a.program.id;f=b+"__"+f;var h=a.chunks[b];if(h){if(h.id==f)return;this._chunkFactory.putChunk(h)}a.chunks[b]=this._chunkFactory.getChunk(f,c,a.program,d,e),"lights"==c&&this._setAmbient(d)},SceneJS_Display.prototype._setAmbient=function(a){for(var b,c=a.lights,d=0,e=c.length;e>d;d++)b=c[d],"ambient"==b.mode&&(this._ambientColor[0]=b.color[0],this._ambientColor[1]=b.color[1],this._ambientColor[2]=b.color[2])},SceneJS_Display.prototype.removeObject=function(a){var b=this._objects[a];b&&(this._programFactory.putProgram(b.program),b.program=null,b.hash=null,this._objectFactory.putObject(b),delete this._objects[a],this.objectListDirty=!0)},SceneJS_Display.prototype.selectTags=function(a){this._tagSelector=a,this.drawListDirty=!0},SceneJS_Display.prototype.render=function(a){a=a||{},this.objectListDirty&&(this._buildObjectList(),this.objectListDirty=!1,this.stateOrderDirty=!0),this.stateOrderDirty&&(this._makeStateSortKeys(),this.stateOrderDirty=!1,this.stateSortDirty=!0),this.stateSortDirty&&(this._stateSort(),this.stateSortDirty=!1,this.drawListDirty=!0),this.drawListDirty&&(this._buildDrawList(),this.imageDirty=!0),(this.imageDirty||a.force)&&(this._doDrawList({clear:a.clear!==!1}),this.imageDirty=!1,this.pickBufDirty=!0)},SceneJS_Display.prototype._buildObjectList=function(){this._objectListLen=0;for(var a in this._objects)this._objects.hasOwnProperty(a)&&(this._objectList[this._objectListLen++]=this._objects[a])},SceneJS_Display.prototype._makeStateSortKeys=function(){for(var a,b=0,c=this._objectListLen;c>b;b++)a=this._objectList[b],a.program?a.sortKey=1e12*(a.stage.priority+1)+1e9*(a.flags.transparent?2:1)+1e6*(a.layer.priority+1)+1e3*(a.program.id+1)+a.texture.stateId:a.sortKey=-1},SceneJS_Display.prototype._stateSort=function(){this._objectList.length=this._objectListLen,this._objectList.sort(this._stateSortObjects)},SceneJS_Display.prototype._stateSortObjects=function(a,b){return a.sortKey-b.sortKey},SceneJS_Display.prototype._logObjectList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._objectListLen+" objects");for(var a=0,b=this._objectListLen;b>a;a++){var c=this._objectList[a];console.log("SceneJS_Display : object["+a+"] sortKey = "+c.sortKey)}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._buildDrawList=function(){this._lastStateId=this._lastStateId||[],this._lastPickStateId=this._lastPickStateId||[];for(var a=0;23>a;a++)this._lastStateId[a]=null,this._lastPickStateId[a]=null;this._drawListLen=0,this._pickDrawListLen=0;var b,c,d,e,f,g={},h=[],i=[];this._tagSelector&&(c=this._tagSelector.mask,d=this._tagSelector.regex),this._objectDrawList=this._objectDrawList||[],this._objectDrawListLen=0;for(var a=0,j=this._objectListLen;j>a;a++)if(b=this._objectList[a],b.enable.enabled!==!1&&(f=b.flags,f.enabled!==!1&&b.layer.enabled&&(!c||(e=b.tag,!e.tag||(e.mask!=c&&(e.mask=c,e.matches=d.test(e.tag)),e.matches)))))if(b.renderTarget.targets)for(var k,l,m,n=b.renderTarget.targets,o=0,p=n.length;p>o;o++)k=n[o],l=k.coreId,m=g[l],m||(m=[],g[l]=m,h.push(m),i.push(this._chunkFactory.getChunk(k.stateId,"renderTarget",b.program,k))),m.push(b);else this._objectDrawList[this._objectDrawListLen++]=b;for(var m,k,b,q,a=0,j=h.length;j>a;a++){m=h[a],k=i[a],this._appendRenderTargetChunk(k);for(var o=0,p=m.length;p>o;o++)b=m[o],q=b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q)}b&&this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1,"renderTarget",b.program,{}));for(var a=0,j=this._objectDrawListLen;j>a;a++)b=this._objectDrawList[a],q=!b.stage||b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q);this.drawListDirty=!1},SceneJS_Display.prototype._appendRenderTargetChunk=function(a){this._drawList[this._drawListLen++]=a},SceneJS_Display.prototype._appendObjectToDrawLists=function(a,b){for(var c,d=a.chunks,e=a.flags.picking,f=0,g=d.length;g>f;f++)c=d[f],c&&(c.draw&&(c.unique||this._lastStateId[f]!=c.id)&&(this._drawList[this._drawListLen++]=c,this._lastStateId[f]=c.id),c.pick&&b!==!1&&e&&(c.unique||this._lastPickStateId[f]!=c.id)&&(this._pickDrawList[this._pickDrawListLen++]=c,this._lastPickStateId[f]=c.id))},SceneJS_Display.prototype._logDrawList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._drawListLen+" draw list chunks");for(var a=0,b=this._drawListLen;b>a;a++){var c=this._drawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._logPickList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._pickDrawListLen+" pick list chunks");for(var a=0,b=this._pickDrawListLen;b>a;a++){var c=this._pickDrawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype.pick=function(a){var b=this._canvas.canvas,c=this._canvas.ssaaMultiplier,d=null,e=a.canvasX*c,f=a.canvasY*c,g=this.pickBuf;g||(g=this.pickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.pickBufDirty=!0),this.render(),g.bind(),this.pickBufDirty&&(g.clear(),this._doDrawList({pick:!0,clear:!0}),this._canvas.gl.finish(),this.pickBufDirty=!1,this.rayPickBufDirty=!0);var h=g.read(e,f),i=h[0]+256*h[1]+65536*h[2],j=i>=1?i-1:-1;g.unbind();var k=this._frameCtx.pickNames[j];if(k&&(d={name:k.name,path:k.path,nodeId:k.nodeId,canvasPos:[e,f]},a.rayPick)){var l=this.rayPickBuf;l||(l=this.rayPickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.rayPickBufDirty=!0),l.bind(),this.rayPickBufDirty&&(l.clear(),this._doDrawList({pick:!0,rayPick:!0,clear:!0}),this.rayPickBufDirty=!1),h=l.read(e,f),l.unbind();var m=this._unpackDepth(h),n=b.width,o=b.height,p=(e-n/2)/(n/2),q=-(f-o/2)/(o/2),r=this._frameCtx.cameraMat,s=this._frameCtx.viewMat,t=SceneJS_math_mulMat4(r,s,[]),u=SceneJS_math_inverseMat4(t,[]),v=SceneJS_math_transformVector4(u,[p,q,-1,1]);v=SceneJS_math_mulVec4Scalar(v,1/v[3]);var w=SceneJS_math_transformVector4(u,[p,q,1,1]);w=SceneJS_math_mulVec4Scalar(w,1/w[3]);var x=SceneJS_math_subVec3(w,v,[]),y=SceneJS_math_addVec3(v,SceneJS_math_mulVec4Scalar(x,m,[]),[]);d.worldPos=y}return d},SceneJS_Display.prototype.readPixels=function(a,b){this._readPixelBuf||(this._readPixelBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas})),this._readPixelBuf.bind(),this._readPixelBuf.clear(),this.render({force:!0});for(var c,d,e=0;b>e;e++)c=a[e]||(a[e]={}),d=this._readPixelBuf.read(c.x,c.y),c.r=d[0],c.g=d[1],c.b=d[2],c.a=d[3];this._readPixelBuf.unbind()},SceneJS_Display.prototype._unpackDepth=function(a){var b=[a[0]/256,a[1]/256,a[2]/256,a[3]/256],c=[1/16777216,1/65536,1/256,1];return SceneJS_math_dotVector4(b,c)},SceneJS_Display.prototype._doDrawList=function(a){var b=this._canvas.gl,c=this._frameCtx;c.renderTarget=null,c.targetIndex=0,c.renderBuf=null,c.viewMat=null,c.modelMat=null,c.cameraMat=null,c.renderer=null,c.depthbufEnabled=null,c.clearDepth=null,c.depthFunc=b.LESS,c.scissorTestEnabled=!1,c.blendEnabled=!1,c.backfaces=!0,c.frontface="ccw",c.pick=!!a.pick,c.rayPick=!!a.rayPick,c.pickIndex=0,c.textureUnit=0,c.lineWidth=1,c.transparent=!1,c.ambientColor=this._ambientColor,c.aspect=this._canvas.canvas.width/this._canvas.canvas.height,this._canvas.UINT_INDEX_ENABLED&&b.getExtension("OES_element_index_uint");var d=b.getExtension("OES_vertex_array_object");if(c.VAO=d?d:null,b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),this.transparent?b.clearColor(0,0,0,0):b.clearColor(this._ambientColor[0],this._ambientColor[1],this._ambientColor[2],1),a.clear&&b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),b.frontFace(b.CCW),b.disable(b.CULL_FACE),b.disable(b.BLEND),a.pick)for(var e=0,f=this._pickDrawListLen;f>e;e++)this._pickDrawList[e].pick(c);else for(var e=0,f=this._drawListLen;f>e;e++)this._drawList[e].draw(c);if(b.flush(),c.renderBuf&&c.renderBuf.unbind(),c.VAO){c.VAO.bindVertexArrayOES(null);for(var e=0;10>e;e++)b.disableVertexAttribArray(e)}},SceneJS_Display.prototype.destroy=function(){this._programFactory.destroy()};var SceneJS_ProgramSourceFactory=new function(){function a(a){if(a.renderTarget&&a.renderTarget.targets)for(var b=a.renderTarget.targets,c=0,d=b.length;d>c;c++)if("depth"===b[c].bufType)return!0;return!1}this._sourceCache={},this.getSource=function(a,b){var c=this._sourceCache[a];return c?(c.useCount++,c):this._sourceCache[a]=new SceneJS_ProgramSource(a,this._composePickingVertexShader(b),this._composePickingFragmentShader(b),this._composeRenderingVertexShader(b),this._composeRenderingFragmentShader(b))},this.putSource=function(a){var b=this._sourceCache[a];b&&0==--b.useCount&&(this._sourceCache[b.hash]=null)},this._composePickingVertexShader=function(a){var b=!!a.morphGeometry.targets,c=["precision mediump float;","attribute vec3 SCENEJS_aVertex;","uniform mat4 SCENEJS_uMMatrix;","uniform mat4 SCENEJS_uVMatrix;","uniform mat4 SCENEJS_uVNMatrix;","uniform mat4 SCENEJS_uPMatrix;"];return c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),b&&(c.push("uniform float SCENEJS_uMorphFactor;"),a.morphGeometry.targets[0].vertexBuf&&c.push("attribute vec3 SCENEJS_aMorphVertex;")),c.push("void main(void) {"),c.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "),b&&a.morphGeometry.targets[0].vertexBuf&&c.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "),c.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "),c.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"),c.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"),c.push("}"),c},this._composePickingFragmentShader=function(a){var b=a.clips.clips.length>0,c=["precision mediump float;"];if(c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),c.push("uniform bool SCENEJS_uRayPickMode;"),c.push("uniform vec3 SCENEJS_uPickColor;"),c.push("uniform float SCENEJS_uZNear;"),c.push("uniform float SCENEJS_uZFar;"),c.push("uniform bool SCENEJS_uClipping;"),b)for(var d=0;d 0.0) { discard; }"),c.push("}")}return c.push(" if (SCENEJS_uRayPickMode) {"),c.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"),c.push(" gl_FragColor = packDepth(zNormalizedDepth); "),c.push(" } else {"),c.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "),c.push(" }"),c.push("}"),c},this._isTexturing=function(a){if(a.texture.layers&&a.texture.layers.length>0){if(a.geometry.uvBuf||a.geometry.uvBuf2)return!0;if(a.morphGeometry.targets&&(a.morphGeometry.targets[0].uvBuf||a.morphGeometry.targets[0].uvBuf2))return!0}return!1},this._isCubeMapping=function(a){return a.flags.reflective&&a.cubemap.layers&&a.cubemap.layers.length>0&&a.geometry.normalBuf},this._hasNormals=function(a){return a.geometry.normalBuf?!0:a.morphGeometry.targets&&a.morphGeometry.targets[0].normalBuf?!0:!1},this._hasTangents=function(a){if(a.texture){var b=a.texture.layers;if(!b)return!1;for(var c=0,d=b.length;d>c;c++)if("normals"==b[c].applyTo)return!0}return!1},this._composeRenderingVertexShader=function(a){var b=a.shader.shaders||{};if(b.vertex&&b.vertex.code&&""!=b.vertex.code&&SceneJS._isEmpty(b.vertex.hooks))return[b.vertex.code];var c=b.vertex||{},d=c.hooks||{},e=b.fragment||{},f=e.hooks||{},g=this._isTexturing(a),h=this._hasNormals(a),i=this._hasTangents(a),j=a.clips.clips.length>0,k=!!a.morphGeometry.targets,l=["precision mediump float;"];if(l.push("uniform mat4 SCENEJS_uMMatrix;"),l.push("uniform mat4 SCENEJS_uVMatrix;"),l.push("uniform mat4 SCENEJS_uPMatrix;"),l.push("attribute vec3 SCENEJS_aVertex;"),l.push("uniform vec3 SCENEJS_uWorldEye;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("attribute vec3 SCENEJS_aNormal;"),l.push("uniform mat4 SCENEJS_uMNMatrix;"),l.push("uniform mat4 SCENEJS_uVNMatrix;"),l.push("varying vec3 SCENEJS_vViewNormal;"),i&&l.push("attribute vec4 SCENEJS_aTangent;");for(var m=0;m0,l=["\n"];if(l.push("precision mediump float;"),k&&l.push("varying vec4 SCENEJS_vWorldVertex;"),l.push("varying vec4 SCENEJS_vViewVertex;"),l.push("uniform float SCENEJS_uZNear;"),l.push("uniform float SCENEJS_uZFar;"),k)for(var m=0;mm;m++)n=b.texture.layers[m],l.push("uniform sampler2D SCENEJS_uSampler"+m+";"),n.matrix&&l.push("uniform mat4 SCENEJS_uLayer"+m+"Matrix;"),l.push("uniform float SCENEJS_uLayer"+m+"BlendFactor;")}if(h&&g)for(var n,m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("uniform samplerCube SCENEJS_uCubeMapSampler"+m+";"),l.push("uniform float SCENEJS_uCubeMapIntensity"+m+";");if(l.push("uniform bool SCENEJS_uClipping;"),l.push("uniform bool SCENEJS_uSolid;"),l.push("uniform bool SCENEJS_uDepthMode;"),l.push("uniform bool SCENEJS_uTransparent;"),b.geometry.colorBuf&&l.push("varying vec4 SCENEJS_vColor;"),l.push("uniform vec3 SCENEJS_uAmbientColor;"),l.push("uniform vec3 SCENEJS_uMaterialColor;"),l.push("uniform float SCENEJS_uMaterialAlpha;"),l.push("uniform float SCENEJS_uMaterialEmit;"),l.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"),l.push("uniform float SCENEJS_uMaterialSpecular;"),l.push("uniform float SCENEJS_uMaterialShine;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("varying vec3 SCENEJS_vViewNormal;");for(var p,m=0;m 0.0) { discard; }"),l.push("}")}h&&i&&(l.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"),l.push(" if (a < 0.0) {"),l.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"),l.push(" return;"),l.push(" }")),l.push(" vec3 ambient= SCENEJS_uAmbientColor;"),f&&b.geometry.uvBuf&&e.texturePos&&l.push(e.texturePos+"(SCENEJS_vUVCoord);"),e.viewPos&&l.push(e.viewPos+"(SCENEJS_vViewVertex);"),h&&e.viewNormal&&l.push(e.viewNormal+"(SCENEJS_vViewNormal);"),b.geometry.colorBuf?l.push(" vec3 color = SCENEJS_vColor.rgb;"):l.push(" vec3 color = SCENEJS_uMaterialColor;"),l.push(" float alpha = SCENEJS_uMaterialAlpha;"),l.push(" float emit = SCENEJS_uMaterialEmit;"),l.push(" float specular = SCENEJS_uMaterialSpecular;"),l.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"),l.push(" float shine = SCENEJS_uMaterialShine;"),e.materialBaseColor&&l.push("color="+e.materialBaseColor+"(color);"),e.materialAlpha&&l.push("alpha="+e.materialAlpha+"(alpha);"),e.materialEmit&&l.push("emit="+e.materialEmit+"(emit);"),e.materialSpecular&&l.push("specular="+e.materialSpecular+"(specular);"),e.materialSpecularColor&&l.push("specularColor="+e.materialSpecularColor+"(specularColor);"),e.materialShine&&l.push("shine="+e.materialShine+"(shine);"),h&&(l.push(" float attenuation = 1.0;"),j?l.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"):l.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"));var n;if(f){l.push(" vec4 texturePos;"),l.push(" vec2 textureCoord=vec2(0.0,0.0);");for(var m=0,o=b.texture.layers.length;o>m;m++){if(n=b.texture.layers[m],"normal"==n.applyFrom&&h){if(!b.geometry.normalBuf){SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors");continue}l.push("texturePos=vec4(viewNormalVec.xyz, 1.0);")}if("uv"==n.applyFrom){if(!b.geometry.uvBuf){SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);")}if("uv2"==n.applyFrom){if(!b.geometry.uvBuf2){SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates");continue}l.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);")}n.matrix?l.push("textureCoord=(SCENEJS_uLayer"+m+"Matrix * texturePos).xy;"):l.push("textureCoord=texturePos.xy;"),"alpha"==n.applyTo&&("multiply"==n.blendMode?l.push("alpha = alpha * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"):"add"==n.blendMode&&l.push("alpha = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * alpha) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);")),"baseColor"==n.applyTo&&("multiply"==n.blendMode?l.push("color = color * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"):l.push("color = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * color) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);")),"emit"==n.applyTo&&("multiply"==n.blendMode?l.push("emit = emit * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("emit = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * emit) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"specular"==n.applyTo&&h&&("multiply"==n.blendMode?l.push("specular = specular * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("specular = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * specular) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"shine"==n.applyTo&&("multiply"==n.blendMode?l.push("shine = shine * (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):l.push("shine = ((1.0 - SCENEJS_uLayer"+m+"BlendFactor) * shine) + (SCENEJS_uLayer"+m+"BlendFactor * texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"normals"==n.applyTo&&h&&l.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler"+m+", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);")}}if(h&&g){l.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"),l.push("envLookup.y = envLookup.y * -1.0;"),l.push("vec4 envColor;");for(var m=0,o=b.cubemap.layers.length;o>m;m++)n=b.cubemap.layers[m],l.push("envColor = textureCube(SCENEJS_uCubeMapSampler"+m+", envLookup);"),l.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity"+m+");")}if(l.push(" vec4 fragColor;"),h){l.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"),l.push(" vec3 viewLightVec;"),l.push(" float dotN;"),l.push(" float lightDist;");for(var p,m=0,o=b.lights.lights.length;o>m;m++)p=b.lights.lights[m],"ambient"!=p.mode&&(l.push("viewLightVec = SCENEJS_vViewLightVecAndDist"+m+".xyz;"),"point"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),l.push("lightDist = SCENEJS_vViewLightVecAndDist"+m+".w;"),l.push("attenuation = 1.0 - ( SCENEJS_uLightAttenuation"+m+"[0] + SCENEJS_uLightAttenuation"+m+"[1] * lightDist + SCENEJS_uLightAttenuation"+m+"[2] * lightDist * lightDist);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+" * attenuation;"),p.specular&&l.push(" specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;")),"dir"==p.mode&&(l.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),p.diffuse&&l.push(" lightValue += dotN * SCENEJS_uLightColor"+m+";"),p.specular&&l.push("specularValue += specularColor * SCENEJS_uLightColor"+m+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);")));l.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);")}else l.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);");return e.pixelColor&&l.push("fragColor="+e.pixelColor+"(fragColor);"),a(b)?(l.push(" if (SCENEJS_uDepthMode) {"),l.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"),l.push(" const vec4 bias = vec4(1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 1.0 / 255.0,"),l.push(" 0.0);"),l.push(" float r = depth;"),l.push(" float g = fract(r * 255.0);"),l.push(" float b = fract(g * 255.0);"),l.push(" float a = fract(b * 255.0);"),l.push(" vec4 colour = vec4(r, g, b, a);"),l.push(" gl_FragColor = colour - (colour.yzww * bias);"),l.push(" } else {"),l.push(" gl_FragColor = fragColor;"),l.push(" };")):l.push(" gl_FragColor = fragColor;"),l.push("}"),l}},SceneJS_ProgramSource=function(a,b,c,d,e){this.hash=a,this.pickVertexSrc=b,this.pickFragmentSrc=c,this.drawVertexSrc=d,this.drawFragmentSrc=e,this.useCount=0},SceneJS_ProgramFactory=function(a){this._canvas=a.canvas,this._programs={},this._nextProgramId=0};SceneJS_ProgramFactory.prototype.getProgram=function(a,b){var c=this._programs[a];if(!c){var d=SceneJS_ProgramSourceFactory.getSource(a,b);c=new SceneJS_Program(this._nextProgramId++,a,d,this._canvas.gl),this._programs[a]=c}return c.useCount++,c},SceneJS_ProgramFactory.prototype.putProgram=function(a){--a.useCount<=0&&(a.draw.destroy(),a.pick.destroy(),SceneJS_ProgramSourceFactory.putSource(a.hash),delete this._programs[a.hash])},SceneJS_ProgramFactory.prototype.webglRestored=function(){var a,b=this._canvas.gl;for(var c in this._programs)this._programs.hasOwnProperty(c)&&(a=this._programs[c],a&&a.build&&a.build(b))},SceneJS_ProgramFactory.prototype.destroy=function(){};var SceneJS_Program=function(a,b,c,d){this.id=a,this.hash=c.hash,this.source=c,this.gl=d,this.UINT_INDEX_ENABLED=!!d.getExtension("OES_element_index_uint"),this.draw=null,this.pick=null,this.useCount=0,this.build(d)};SceneJS_Program.prototype.build=function(a){this.gl=a,this.draw=new SceneJS._webgl.Program(a,[this.source.drawVertexSrc.join("\n")],[this.source.drawFragmentSrc.join("\n")]),this.pick=new SceneJS._webgl.Program(a,[this.source.pickVertexSrc.join("\n")],[this.source.pickFragmentSrc.join("\n")])};var SceneJS_ObjectFactory=function(){};SceneJS_ObjectFactory.prototype._freeObjects=[],SceneJS_ObjectFactory.prototype._numFreeObjects=0,SceneJS_ObjectFactory.prototype.getObject=function(a){ -var b;return this._numFreeObjects>0?(b=this._freeObjects[--this._numFreeObjects],b.id=a,b):new SceneJS_Object(a)},SceneJS_ObjectFactory.prototype.putObject=function(a){this._freeObjects[this._numFreeObjects++]=a};var SceneJS_Object=function(a){this.id=a,this.hash=null,this.sortKey=null,this.chunks=[],this.chunksLen=0,this.program=null,this.layer=null,this.texture=null,this.flags=null,this.tag=null};SceneJS.RenderContext=function(a){this._frameCtx=a},SceneJS.RenderContext.prototype.getCameraMatrix=function(){return this._frameCtx.cameraMat},SceneJS.RenderContext.prototype.getViewMatrix=function(){return this._frameCtx.viewMat},SceneJS.RenderContext.prototype.getModelMatrix=function(){return this._frameCtx.modelMat},SceneJS.RenderContext.prototype.getCanvasPos=function(a){this.getProjPos(a);var b=this._frameCtx.canvas.canvas,c=this._frameCtx.canvas.ssaaMultiplier,d=b.width/c,e=b.height/c,f=this._pc,g=f[0]/f[3]*d*.5,h=f[1]/f[3]*e*.5;return{x:g+.5*d,y:e-h-.5*e}},SceneJS.RenderContext.prototype.getCameraPos=function(a){return this.getProjPos(a),this._camPos=SceneJS_math_normalizeVec3(this._pc,[0,0,0]),{x:this._camPos[0],y:this._camPos[1],z:this._camPos[2]}},SceneJS.RenderContext.prototype.getProjPos=function(a){return this.getViewPos(a),this._pc=SceneJS_math_transformPoint3(this._frameCtx.cameraMat,this._vc),{x:this._pc[0],y:this._pc[1],z:this._pc[2],w:this._pc[3]}},SceneJS.RenderContext.prototype.getViewPos=function(a){return this.getWorldPos(a),this._vc=SceneJS_math_transformPoint3(this._frameCtx.viewMat,this._wc),{x:this._vc[0],y:this._vc[1],z:this._vc[2],w:this._vc[3]}},SceneJS.RenderContext.prototype.getWorldPos=function(a){return this._wc=SceneJS_math_transformPoint3(this._frameCtx.modelMat,a||[0,0,0]),{x:this._wc[0],y:this._wc[1],z:this._wc[2],w:this._wc[3]}};var SceneJS_Chunk=function(){};SceneJS_Chunk.prototype.init=function(a,b,c,d){this.id=a,this.program=b,this.core=c,this.core2=d,this.build&&this.build()};var SceneJS_ChunkFactory=function(){this._chunks={},this.chunkTypes=SceneJS_ChunkFactory.chunkTypes};SceneJS_ChunkFactory.chunkTypes={},SceneJS_ChunkFactory._freeChunks={},SceneJS_ChunkFactory.createChunkType=function(a){if(!a.type)throw"'type' expected in params";var b=SceneJS_Chunk,c=function(){this.useCount=0,this.init.apply(this,arguments)};return c.prototype=new b,c.prototype.constructor=c,a.drawAndPick&&(a.draw=a.pick=a.drawAndPick),SceneJS_ChunkFactory.chunkTypes[a.type]=c,SceneJS._apply(a,c.prototype),SceneJS_ChunkFactory._freeChunks[a.type]={chunks:[],chunksLen:0},c},SceneJS_ChunkFactory.prototype.getChunk=function(a,b,c,d,e){var f=SceneJS_ChunkFactory.chunkTypes[b];if(!f)throw"chunk type not supported: '"+b+"'";var g=this._chunks[a];if(g)return g.useCount++,g;var h=SceneJS_ChunkFactory._freeChunks[b];return h.chunksLen>0&&(g=h.chunks[--h.chunksLen]),g?g.init(a,c,d,e):g=new f(a,c,d,e),g.type=b,g.useCount=1,this._chunks[a]=g,g},SceneJS_ChunkFactory.prototype.putChunk=function(a){if(0!=a.useCount&&--a.useCount<=0){a.recycle&&a.recycle(),delete this._chunks[a.id];var b=SceneJS_ChunkFactory._freeChunks[a.type];b.chunks[b.chunksLen++]=a}},SceneJS_ChunkFactory.prototype.webglRestored=function(){var a;for(var b in this._chunks)this._chunks.hasOwnProperty(b)&&(a=this._chunks[b],a&&a.build&&a.build())},SceneJS_ChunkFactory.createChunkType({type:"camera",build:function(){this._uPMatrixDraw=this.program.draw.getUniform("SCENEJS_uPMatrix"),this._uZNearDraw=this.program.draw.getUniform("SCENEJS_uZNear"),this._uZFarDraw=this.program.draw.getUniform("SCENEJS_uZFar"),this._uPMatrixPick=this.program.pick.getUniform("SCENEJS_uPMatrix"),this._uZNearPick=this.program.pick.getUniform("SCENEJS_uZNear"),this._uZFarPick=this.program.pick.getUniform("SCENEJS_uZFar")},draw:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixDraw&&this._uPMatrixDraw.setValue(this.core.mat),this._uZNearDraw&&this._uZNearDraw.setValue(this.core.optics.near),this._uZFarDraw&&this._uZFarDraw.setValue(this.core.optics.far),a.cameraMat=this.core.mat},pick:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixPick&&this._uPMatrixPick.setValue(this.core.mat),a.rayPick&&(this._uZNearPick&&this._uZNearPick.setValue(this.core.optics.near),this._uZFarPick&&this._uZFarPick.setValue(this.core.optics.far)),a.cameraMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"clips",build:function(){this._draw=this._draw||[];for(var a=this.program.draw,b=0,c=this.core.clips.length;c>b;b++)this._draw[b]={uClipMode:a.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:a.getUniform("SCENEJS_uClipNormalAndDist"+b)};this._pick=this._pick||[];for(var d=this.program.pick,b=0,c=this.core.clips.length;c>b;b++)this._pick[b]={uClipMode:d.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:d.getUniform("SCENEJS_uClipNormalAndDist"+b)}},drawAndPick:function(a){for(var b,c,d,e=a.pick?this._pick:this._draw,f=this.core.clips,g=(this.program.gl,0),h=f.length;h>g;g++)a.pick?(b=e[g].uClipMode,c=e[g].uClipNormalAndDist):(b=e[g].uClipMode,c=e[g].uClipNormalAndDist),b&&c&&(d=f[g],"inside"==d.mode?(b.setValue(2),c.setValue(d.normalAndDist)):"outside"==d.mode?(b.setValue(1),c.setValue(d.normalAndDist)):b.setValue(0))}}),SceneJS_ChunkFactory.createChunkType({type:"draw",unique:!0,build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode")},drawAndPick:function(a){var b=this.program.gl,c=this.program.UINT_INDEX_ENABLED?b.UNSIGNED_INT:b.UNSIGNED_SHORT;a.pick?this._depthModePick&&this._depthModePick.setValue(a.depthMode):this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),b.drawElements(this.core.primitive,this.core.indexBuf.numItems,c,0)}}),SceneJS_ChunkFactory.createChunkType({type:"flags",build:function(){var a=this.program.draw;this._uClippingDraw=a.getUniform("SCENEJS_uClipping"),this._uSolidDraw=a.getUniform("SCENEJS_uSolid");var b=this.program.pick;this._uClippingPick=b.getUniform("SCENEJS_uClipping")},drawAndPick:function(a){var b=this.program.gl,c=this.core.backfaces;a.backfaces!=c&&(c?b.disable(b.CULL_FACE):b.enable(b.CULL_FACE),a.backfaces=c);var d=this.core.frontface;a.frontface!=d&&("ccw"==d?b.frontFace(b.CCW):b.frontFace(b.CW),a.frontface=d);var e=this.core.transparent;a.transparent!=e&&(a.pick||(e?(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA),a.blendEnabled=!0):(b.disable(b.BLEND),a.blendEnabled=!1)),a.transparent=e),a.pick?this._uClippingPick&&this._uClippingPick.setValue(this.core.clipping):(this._uClippingDraw&&this._uClippingDraw.setValue(this.core.clipping),this._uSolidDraw&&this._uSolidDraw.setValue(this.core.solid))}}),SceneJS_ChunkFactory.createChunkType({type:"renderTarget",programGlobal:!0,draw:function(a){var b=this.program.gl;a.renderBuf&&(b.flush(),a.renderBuf.unbind(),a.renderBuf=null);var c=this.core.renderBuf;return c?(c.bind(),a.depthMode="depth"===this.core.bufType,a.depthMode||a.blendEnabled&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA)),b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),b.clearColor(a.ambientColor[0],a.ambientColor[1],a.ambientColor[2],1),b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),void(a.renderBuf=c)):void(a.depthMode=!1)}}),SceneJS_ChunkFactory.createChunkType({type:"geometry",build:function(){var a=this.program.draw;this._aVertexDraw=a.getAttribute("SCENEJS_aVertex"),this._aNormalDraw=a.getAttribute("SCENEJS_aNormal"),this._aUVDraw=a.getAttribute("SCENEJS_aUVCoord"),this._aUV2Draw=a.getAttribute("SCENEJS_aUVCoord2"),this._aTangentDraw=a.getAttribute("SCENEJS_aTangent"),this._aColorDraw=a.getAttribute("SCENEJS_aVertexColor"),this._aMorphVertexDraw=a.getAttribute("SCENEJS_aMorphVertex"),this._aMorphNormalDraw=a.getAttribute("SCENEJS_aMorphNormal"),this._uMorphFactorDraw=a.getUniform("SCENEJS_uMorphFactor");var b=this.program.pick;this._aVertexPick=b.getAttribute("SCENEJS_aVertex"),this._aMorphVertexPick=b.getAttribute("SCENEJS_aMorphVertex"),this._uMorphFactorPick=b.getUniform("SCENEJS_uMorphFactor"),this.VAO=null,this.VAOMorphKey1=0,this.VAOMorphKey2=0,this.VAOHasInterleavedBuf=!1},recycle:function(){if(this.VAO){var a=this.program.gl.getExtension("OES_vertex_array_object");a.deleteVertexArrayOES(this.VAO),this.VAO=null}},morphDraw:function(){this.VAOMorphKey1=this.core.key1,this.VAOMorphKey2=this.core.key2;var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexDraw?(this._aVertexDraw.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexDraw.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aMorphNormalDraw?(this._aNormalDraw.bindFloatArrayBuffer(a.normalBuf),this._aMorphNormalDraw.bindFloatArrayBuffer(b.normalBuf)):this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this.setDrawMorphFactor()},setDrawMorphFactor:function(){this._uMorphFactorDraw&&this._uMorphFactorDraw.setValue*this.core.factor},draw:function(a){var b=this.core.targets&&this.core.targets.length,c=this.core2.interleavedBuf&&!this.core2.interleavedBuf.dirty;if(this.VAO){if(a.VAO.bindVertexArrayOES(this.VAO),b){if(this.VAOMorphKey1==this.core.key1&&this.VAOMorphKey2==this.core.key2)return void this.setDrawMorphFactor()}else if(c||!this.VAOHasInterleavedBuf)return}else if(a.VAO){a.VAO.bindVertexArrayOES(null),this.VAO=a.VAO.createVertexArrayOES(),a.VAO.bindVertexArrayOES(this.VAO);this.program.gl}b?this.morphDraw():c?(this.VAOHasInterleavedBuf=!0,this.core2.interleavedBuf.bind(),this._aVertexDraw&&this._aVertexDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedPositionOffset),this._aNormalDraw&&this._aNormalDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedNormalOffset),this._aUVDraw&&this._aUVDraw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUVOffset),this._aUV2Draw&&this._aUV2Draw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUV2Offset),this._aColorDraw&&this._aColorDraw.bindInterleavedFloatArrayBuffer(4,this.core2.interleavedStride,this.core2.interleavedColorOffset),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())):(this.VAOHasInterleavedBuf=!1,this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())),this.core2.indexBuf.bind()},morphPick:function(){var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexPick?(this._aVertexPick.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexPick.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this._uMorphFactorPick&&this._uMorphFactorPick.setValue(this.core.factor)},pick:function(a){this.core.targets&&this.core.targets.length?this.morphPick():this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this.core2.indexBuf.bind()}}),SceneJS_ChunkFactory.createChunkType({type:"lights",build:function(){this._uAmbientColor=this._uAmbientColor||[],this._uLightColor=this._uLightColor||[],this._uLightDir=this._uLightDir||[],this._uLightPos=this._uLightPos||[],this._uLightCutOff=this._uLightCutOff||[],this._uLightSpotExp=this._uLightSpotExp||[],this._uLightAttenuation=this._uLightAttenuation||[];for(var a=this.core.lights,b=this.program,c=0,d=a.length;d>c;c++)switch(a[c].mode){case"ambient":this._uAmbientColor[c]=b.draw.getUniform("SCENEJS_uAmbientColor");break;case"dir":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=null,this._uLightDir[c]=b.draw.getUniform("SCENEJS_uLightDir"+c);break;case"point":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=b.draw.getUniform("SCENEJS_uLightPos"+c),this._uLightDir[c]=null,this._uLightAttenuation[c]=b.draw.getUniform("SCENEJS_uLightAttenuation"+c)}},draw:function(a){a.dirty&&this.build();for(var b,c=this.core.lights,d=(this.program.gl,0),e=c.length;e>d;d++)b=c[d],this._uAmbientColor[d]?this._uAmbientColor[d].setValue(b.color):(this._uLightColor[d]&&this._uLightColor[d].setValue(b.color),this._uLightPos[d]&&(this._uLightPos[d].setValue(b.pos),this._uLightAttenuation[d]&&this._uLightAttenuation[d].setValue(b.attenuation)),this._uLightDir[d]&&this._uLightDir[d].setValue(b.dir))}}),SceneJS_ChunkFactory.createChunkType({type:"listeners",programGlobal:!0,build:function(){},draw:function(a){for(var b=this.core.listeners,c=a.renderListenerCtx,d=b.length-1;d>=0;d--)if(b[d](c)===!0)return!0}}),SceneJS_ChunkFactory.createChunkType({type:"lookAt",build:function(){this._uvMatrixDraw=this.program.draw.getUniform("SCENEJS_uVMatrix"),this._uVNMatrixDraw=this.program.draw.getUniform("SCENEJS_uVNMatrix"),this._uWorldEyeDraw=this.program.draw.getUniform("SCENEJS_uWorldEye"),this._uvMatrixPick=this.program.pick.getUniform("SCENEJS_uVMatrix")},draw:function(a){this.core.dirty&&this.core.rebuild();this.program.gl;this._uvMatrixDraw&&this._uvMatrixDraw.setValue(this.core.mat),this._uVNMatrixDraw&&this._uVNMatrixDraw.setValue(this.core.normalMat),this._uWorldEyeDraw&&this._uWorldEyeDraw.setValue(this.core.lookAt.eye),a.viewMat=this.core.mat},pick:function(a){this.program.gl;this._uvMatrixPick&&this._uvMatrixPick.setValue(this.core.mat),a.viewMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"material",build:function(){var a=this.program.draw;this._uMaterialBaseColor=a.getUniform("SCENEJS_uMaterialColor"),this._uMaterialSpecularColor=a.getUniform("SCENEJS_uMaterialSpecularColor"),this._uMaterialSpecular=a.getUniform("SCENEJS_uMaterialSpecular"),this._uMaterialShine=a.getUniform("SCENEJS_uMaterialShine"),this._uMaterialEmit=a.getUniform("SCENEJS_uMaterialEmit"),this._uMaterialAlpha=a.getUniform("SCENEJS_uMaterialAlpha")},draw:function(){this.program.gl;this._uMaterialBaseColor&&this._uMaterialBaseColor.setValue(this.core.baseColor),this._uMaterialSpecularColor&&this._uMaterialSpecularColor.setValue(this.core.specularColor),this._uMaterialSpecular&&this._uMaterialSpecular.setValue(this.core.specular),this._uMaterialShine&&this._uMaterialShine.setValue(this.core.shine),this._uMaterialEmit&&this._uMaterialEmit.setValue(this.core.emit),this._uMaterialAlpha&&this._uMaterialAlpha.setValue(this.core.alpha)}}),SceneJS_ChunkFactory.createChunkType({type:"name",build:function(){this._uPickColor=this.program.pick.getUniform("SCENEJS_uPickColor")},pick:function(a){if(this._uPickColor&&this.core.name){a.pickNames[a.pickIndex++]=this.core;var b=a.pickIndex>>16&255,c=a.pickIndex>>8&255,d=255&a.pickIndex;this._uPickColor.setValue([d/255,c/255,b/255])}}}),SceneJS_ChunkFactory.createChunkType({type:"program",build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode"),this._rayPickMode=this.program.pick.getUniform("SCENEJS_uRayPickMode")},draw:function(a){var b=this.program.draw;b.bind(),a.textureUnit=0;var c=this.program.gl;if(this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),!a.VAO)for(var d=0;10>d;d++)c.disableVertexAttribArray(d);a.drawProgram=this.program.draw},pick:function(a){var b=this.program.pick;b.bind();var c=this.program.gl;this._rayPickMode&&this._rayPickMode.setValue(a.rayPick),this._depthModePick&&this._depthModePick.setValue(a.depthMode),a.textureUnit=0;for(var d=0;10>d;d++)c.disableVertexAttribArray(d)}}),SceneJS_ChunkFactory.createChunkType({type:"renderer",build:function(){},drawAndPick:function(a){if(this.core.props){var b=this.program.gl;a.renderer&&(a.renderer.props.restoreProps(b),a.renderer=this.core),this.core.props.setProps(b)}}}),SceneJS_ChunkFactory.createChunkType({type:"depthBuffer",programGlobal:!0,drawAndPick:function(a){var b=this.program.gl,c=this.core.enabled;a.depthbufEnabled!=c&&(c?b.enable(b.DEPTH_TEST):b.disable(b.DEPTH_TEST),a.depthbufEnabled=c);var d=this.core.clearDepth;a.clearDepth!=d&&(b.clearDepth(d),a.clearDepth=d);var e=this.core.depthFunc;a.depthFunc!=e&&(b.depthFunc(e),a.depthFunc=e),this.core.clear&&b.clear(b.DEPTH_BUFFER_BIT)}}),SceneJS_ChunkFactory.createChunkType({type:"colorBuffer",programGlobal:!0,build:function(){},drawAndPick:function(a){if(!a.transparent){var b=this.core.blendEnabled,c=this.program.gl;a.blendEnabled!=b&&(b?c.enable(c.BLEND):c.disable(c.BLEND),a.blendEnabled=b);var d=this.core.colorMask;c.colorMask(d.r,d.g,d.b,d.a)}}}),SceneJS_ChunkFactory.createChunkType({type:"view",programGlobal:!0,build:function(){},drawAndPick:function(a){var b=this.core.scissorTestEnabled;if(a.scissorTestEnabled!=b){var c=this.program.gl;b?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST),a.scissorTestEnabled=b}}}),SceneJS_ChunkFactory.createChunkType({type:"shader",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"shaderParams",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"style",programGlobal:!0,drawAndPick:function(a){var b=this.core.lineWidth;if(a.lineWidth!=b){var c=this.program.gl;c.lineWidth(b),a.lineWidth=b}}}),SceneJS_ChunkFactory.createChunkType({type:"texture",build:function(){this._uTexSampler=this._uTexSampler||[],this._uTexMatrix=this._uTexMatrix||[],this._uTexBlendFactor=this._uTexBlendFactor||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uTexSampler[d]="SCENEJS_uSampler"+d,this._uTexMatrix[d]=c.getUniform("SCENEJS_uLayer"+d+"Matrix"),this._uTexBlendFactor[d]=c.getUniform("SCENEJS_uLayer"+d+"BlendFactor")},draw:function(a){a.textureUnit=0;var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uTexSampler[e]&&c.texture&&(d.bindTexture(this._uTexSampler[e],c.texture,a.textureUnit++),c._matrixDirty&&c.buildMatrix&&c.buildMatrix.call(c),this._uTexMatrix[e]&&this._uTexMatrix[e].setValue(c.matrixAsArray),this._uTexBlendFactor[e]&&this._uTexBlendFactor[e].setValue(c.blendFactor));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"cubemap",build:function(){this._uCubeMapSampler=this._uCubeMapSampler||[],this._uCubeMapIntensity=this._uCubeMapIntensity||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uCubeMapSampler[d]="SCENEJS_uCubeMapSampler"+d,this._uCubeMapIntensity[d]=c.getUniform("SCENEJS_uCubeMapIntensity"+d)},draw:function(a){var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uCubeMapSampler[e]&&c.texture&&(d.bindTexture(this._uCubeMapSampler[e],c.texture,a.textureUnit++),this._uCubeMapIntensity[e]&&this._uCubeMapIntensity[e].setValue(c.intensity));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"xform",build:function(){var a=this.program.draw;this._uMatLocationDraw=a.getUniform("SCENEJS_uMMatrix"),this._uNormalMatLocationDraw=a.getUniform("SCENEJS_uMNMatrix");var b=this.program.pick;this._uMatLocationPick=b.getUniform("SCENEJS_uMMatrix")},draw:function(a){(SceneJS_configsModule.configs.forceXFormCoreRebuild===!0||this.core.dirty&&this.core.build)&&this.core.build();this.program.gl;this._uMatLocationDraw&&this._uMatLocationDraw.setValue(this.core.mat),this._uNormalMatLocationDraw&&this._uNormalMatLocationDraw.setValue(this.core.normalMat),a.modelMat=this.core.mat},pick:function(a){this.core.dirty&&this.core.build();this.program.gl;this._uMatLocationPick&&this._uMatLocationPick.setValue(this.core.mat),a.modelMat=this.core.mat}}); \ No newline at end of file +if(!g)throw"no typePath config";this._loadScript(g+"/node/"+b+".js",function(){SceneJS_sceneStatusModule.taskFailed(f)})}},SceneJS_NodeFactory.prototype._loadScript=function(a,b){var c=document.createElement("script");c.type="text/javascript",c.src=a,c.onerror=b,document.getElementsByTagName("head")[0].appendChild(c)},SceneJS_NodeFactory.prototype.putNode=function(a){this.nodes.removeItem(a.id)},function(){function a(a){var b=a.optics;if("ortho"==b.type?a.matrix=SceneJS_math_orthoMat4c(b.left,b.right,b.bottom,b.top,b.near,b.far):"frustum"==b.type?a.matrix=SceneJS_math_frustumMatrix4(b.left,b.right,b.bottom,b.top,b.near,b.far):"perspective"==b.type&&(a.matrix=SceneJS_math_perspectiveMatrix4(b.fovy*Math.PI/180,b.aspect,b.near,b.far)),a.pan){var c=a.pan,d=SceneJS_math_translationMat4v([c.x||0,c.y||0,c.z||0]);a.matrix=SceneJS_math_mulMat4(d,a.matrix,[])}a.mat?a.mat.set(a.matrix):a.mat=new Float32Array(a.matrix)}var b=SceneJS_math_perspectiveMatrix4(45,1,.1,1e4),c=new Float32Array(b),d={type:"camera",stateId:SceneJS._baseStateId++,matrix:b,mat:c,optics:{type:"perspective",fovy:45,aspect:1,near:.1,far:1e4},checkAspect:function(b,c){b.optics.aspect!=c&&(b.optics.aspect=c,a(this))}},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.projTransform=d,f=0}),SceneJS.Camera=SceneJS_NodeFactory.createNodeType("camera"),SceneJS.Camera.prototype._init=function(b){if(1==this._core.useCount){b.optics=b.optics||{};var c=this.getScene().getCanvas();b.optics.aspect=c.width/c.height,this.setOptics(b.optics),b.pan&&this.setPan(b.pan);var d=this;this._canvasSizeSub=this.getScene().on("canvasSize",function(b){d._core.optics.aspect=b.aspect,a(d._core),d._engine.display.imageDirty=!0})}},SceneJS.Camera.getDefaultMatrix=function(){return c},SceneJS.Camera.prototype.setOptics=function(b){var c=this._core;if(b){var d=b.type||c.optics.type||"perspective";if("ortho"==d)c.optics=SceneJS._applyIf(SceneJS_math_ORTHO_OBJ,{type:d,left:b.left,bottom:b.bottom,near:b.near,right:b.right,top:b.top,far:b.far});else if("frustum"==d)c.optics={type:d,left:b.left||-1,bottom:b.bottom||-1,near:b.near||.1,right:b.right||1,top:b.top||1,far:b.far||1e4};else{if("perspective"!=d)throw b.type?SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not supported - supported types are 'perspective', 'frustum' and 'ortho'"):SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Camera configuration invalid: optics type not specified - supported types are 'perspective', 'frustum' and 'ortho'");c.optics={type:d,fovy:b.fovy||60,aspect:void 0==b.aspect?1:b.aspect,near:b.near||.1,far:b.far||1e4}}}else c.optics={type:"perspective",fovy:60,aspect:1,near:.1,far:1e4};this._core.optics.pan=b.pan,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.setPan=function(b){this._core.pan=b,a(this._core),this.publish("matrix",this._core.matrix),this._engine.display.imageDirty=!0},SceneJS.Camera.prototype.getOptics=function(){var a={};for(var b in this._core.optics)this._core.optics.hasOwnProperty(b)&&(a[b]=this._core.optics[b]);return a},SceneJS.Camera.prototype.getMatrix=function(){return this._core.matrix.slice(0)},SceneJS.Camera.prototype._compile=function(a){this._engine.display.projTransform=e[f++]=this._core,this._compileNodes(a),this._engine.display.projTransform=--f>0?e[f-1]:d},SceneJS.Camera.prototype._destroy=function(){this.getScene().off(this._canvasSizeSub)}}(),function(){var a={type:"clips",stateId:SceneJS._baseStateId++,empty:!0,hash:"",clips:[]},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.clips=a,c=0}),SceneJS.Clips=SceneJS_NodeFactory.createNodeType("clips"),SceneJS.Clips.prototype._init=function(a){if(1==this._core.useCount){var b=a.clips;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"clips node attribute missing : 'clips'");this._core.clips=this._core.clips||[];for(var c=0,d=b.length;d>c;c++)this._setClip(c,b[c])}},SceneJS.Clips.prototype.setClips=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.clips.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'clips': index out of range ("+this._core.clips.length+" clips defined)");this._setClip(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Clips.prototype._setClip=function(a,b){var c=this._core.clips[a]||(this._core.clips[a]={});c.normalAndDist=[b.x||0,b.y||0,b.z||0,b.dist||0];var d=b.mode||c.mode||"disabled";if("inside"!=d&&"outside"!=d&&"disabled"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"clips node invalid value for property 'mode': should be 'inside' or 'outside' or 'disabled'");c.mode=d,this._core.hash=null},SceneJS.Clips.prototype._compile=function(d){this._core.hash||(this._core.hash=this._core.clips.length),this._engine.display.clips=b[c++]=this._core,this._compileNodes(d),this._engine.display.clips=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"enable",enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.enable=a,c=0}),SceneJS.Enable=SceneJS_NodeFactory.createNodeType("enable"),SceneJS.Enable.prototype._init=function(a){1==this._core.useCount&&(this._core.enabled=!0,void 0!=a.enabled&&this.setEnabled(a.enabled))},SceneJS.Enable.prototype.setEnabled=function(a){return a!==this._core.enabled&&(this._core.enabled=a,this._engine.display.drawListDirty=!0,this.publish("enabled",a)),this},SceneJS.Enable.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Enable.prototype._compile=function(d){this._engine.display.enable=b[c++]=this._core,this._compileNodes(d),this._engine.display.enable=--c>0?b[c-1]:a}}(),function(){var a={stateId:SceneJS._baseStateId++,type:"flags",picking:!0,clipping:!0,enabled:!0,transparent:!1,backfaces:!0,frontface:"ccw",reflective:!0,solid:!1,hash:"refl;;"},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.flags=a,c=0}),SceneJS.Flags=SceneJS_NodeFactory.createNodeType("flags"),SceneJS.Flags.prototype._init=function(a){1==this._core.useCount&&(this._core.picking=!0,this._core.clipping=!0,this._core.enabled=!0,this._core.transparent=!1,this._core.backfaces=!0,this._core.frontface="ccw",this._core.reflective=!0,this._core.solid=!1,a.flags&&this.setFlags(a.flags))},SceneJS.Flags.prototype.setFlags=function(a){var b=this._core;return void 0!=a.picking&&(b.picking=!!a.picking,this._engine.display.drawListDirty=!0),void 0!=a.clipping&&(b.clipping=!!a.clipping,this._engine.display.imageDirty=!0),void 0!=a.enabled&&(b.enabled=!!a.enabled,this._engine.display.drawListDirty=!0),void 0!=a.transparent&&(b.transparent=!!a.transparent,this._engine.display.stateSortDirty=!0),void 0!=a.backfaces&&(b.backfaces=!!a.backfaces,this._engine.display.imageDirty=!0),void 0!=a.frontface&&(b.frontface=a.frontface,this._engine.display.imageDirty=!0),void 0!=a.reflective&&(b.reflective=a.reflective,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),void 0!=a.solid&&(b.solid=a.solid,b.hash=b.reflective?"refl":"",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.addFlags=function(a){return this.setFlags(a)},SceneJS.Flags.prototype.getFlags=function(){var a=this._core;return{picking:a.picking,clipping:a.clipping,enabled:a.enabled,transparent:a.transparent,backfaces:a.backfaces,frontface:a.frontface,reflective:a.reflective,solid:a.solid}},SceneJS.Flags.prototype.setPicking=function(a){return a=!!a,this._core.picking!=a&&(this._core.picking=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getPicking=function(){return this._core.picking},SceneJS.Flags.prototype.setClipping=function(a){return a=!!a,this._core.clipping!=a&&(this._core.clipping=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getClipping=function(){return this._core.clipping},SceneJS.Flags.prototype.setEnabled=function(a){return a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0),this},SceneJS.Flags.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Flags.prototype.setTransparent=function(a){return a=!!a,this._core.transparent!=a&&(this._core.transparent=a,this._engine.display.stateOrderDirty=!0),this},SceneJS.Flags.prototype.getTransparent=function(){return this._core.transparent},SceneJS.Flags.prototype.setBackfaces=function(a){return a=!!a,this._core.backfaces!=a&&(this._core.backfaces=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getBackfaces=function(){return this._core.backfaces},SceneJS.Flags.prototype.setFrontface=function(a){return this._core.frontface!=a&&(this._core.frontface=a,this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getFrontface=function(){return this._core.frontface},SceneJS.Flags.prototype.setReflective=function(a){return a=!!a,this._core.reflective!=a&&(this._core.reflective=a,this._core.hash=(a?"refl":"")+this._core.solid?";s":";;",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getReflective=function(){return this._core.reflective},SceneJS.Flags.prototype.setSolid=function(a){return a=!!a,this._core.solid!=a&&(this._core.solid=a,this._core.hash=(this._core.reflective?"refl":"")+a?";s;":";;",this._engine.branchDirty(this),this._engine.display.imageDirty=!0),this},SceneJS.Flags.prototype.getSolid=function(){return this._core.solid},SceneJS.Flags.prototype._compile=function(d){this._engine.display.flags=b[c++]=this._core,this._compileNodes(d),this._engine.display.flags=--c>0?b[c-1]:a}}(),new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._core.renderBuf.webglRestored()}),SceneJS.ColorTarget=SceneJS_NodeFactory.createNodeType("colorTarget"),SceneJS.ColorTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="color",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.ColorTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.ColorTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a={type:"renderTarget",stateId:SceneJS._baseStateId++,targets:null},b={},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.renderTarget=a,d=0}),SceneJS_events.addListener(SceneJS_events.WEBGL_CONTEXT_RESTORED,function(){for(var a in b)b.hasOwnProperty(a)&&b[a]._buildNodeCore()}),SceneJS.DepthTarget=SceneJS_NodeFactory.createNodeType("depthTarget"),SceneJS.DepthTarget.prototype._init=function(a){b[this._core.coreId]=this,this._core.bufType="depth",this._core.renderBuf=new SceneJS._webgl.RenderBuffer({canvas:this._engine.canvas})},SceneJS.DepthTarget.prototype._compile=function(b){this.__core||(this.__core=this._engine._coreFactory.getCore("renderTarget"));var e=this._engine.display.renderTarget;this._core.empty||(this.__core.targets=e&&e.targets?e.targets.concat([this._core]):[this._core]),c[d++]=this.__core,this._engine.display.renderTarget=this.__core,this._compileNodes(b),this._engine.display.renderTarget=--d>0?c[d-1]:a},SceneJS.DepthTarget.prototype._destroy=function(){this._core&&(this._core.renderBuf&&this._core.renderBuf.destroy(),delete b[this._core.coreId])}},new function(){var a=[],b=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){b=0}),SceneJS.Geometry=SceneJS_NodeFactory.createNodeType("geometry"),SceneJS.Geometry.prototype._init=function(a){if(1==this._core.useCount){this._initNodeCore(a,{origin:a.origin,scale:a.scale,autoNormals:"auto"==a.normals}),this._buildNodeCore(this._engine.canvas.gl,this._core);var b=this;this._core.webglRestored=function(){b._buildNodeCore(b._engine.canvas.gl,b._core)}}},SceneJS.Geometry.prototype._initNodeCore=function(a,b){var c=this;b=b||{};var d=a.primitive||"triangles",e=this._core,f=this._engine.canvas.UINT_INDEX_ENABLED?Uint32Array:Uint16Array;e.primitive=this._getPrimitiveType(d),a.normals&&"triangles"==d&&("auto"===a.normals||a.normals===!0)&&a.positions&&a.indices&&this._buildNormals(a),e.arrays={positions:a.positions?new Float32Array(b.scale||b.origin?this._applyOptions(a.positions,b):a.positions):void 0,normals:a.normals?new Float32Array(a.normals):void 0,uv:a.uv?new Float32Array(a.uv):void 0,uv2:a.uv2?new Float32Array(a.uv2):void 0,colors:a.colors?new Float32Array(a.colors):void 0,indices:a.indices?new f(a.indices):void 0},delete a.positions,delete a.normals,delete a.uv,delete a.uv2,delete a.indices,delete a.colors,e.getTangentBuf=function(){if(e.tangentBuf)return e.tangentBuf;var a=e.arrays;if(a.positions&&a.indices&&a.uv){var b=c._engine.canvas.gl,d=new Float32Array(c._buildTangents(a));e.arrays.tangents=d;var f=b.STATIC_DRAW;return e.tangentBuf=new SceneJS._webgl.ArrayBuffer(b,b.ARRAY_BUFFER,d,d.length,3,f)}}},SceneJS.Geometry.prototype._getPrimitiveType=function(a){var b=this._engine.canvas.gl;switch(a){case"points":return b.POINTS;case"lines":return b.LINES;case"line-loop":return b.LINE_LOOP;case"line-strip":return b.LINE_STRIP;case"triangles":return b.TRIANGLES;case"triangle-strip":return b.TRIANGLE_STRIP;case"triangle-fan":return b.TRIANGLE_FAN;default:throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"geometry primitive unsupported: '"+a+"' - supported types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'")}},SceneJS.Geometry.prototype._applyOptions=function(a,b){var c=a.slice?a.slice(0):new Float32Array(a);if(b.scale)for(var d=void 0!=b.scale.x?b.scale.x:1,e=void 0!=b.scale.y?b.scale.y:1,f=void 0!=b.scale.z?b.scale.z:1,g=0,h=c.length;h>g;g+=3)c[g]*=d,c[g+1]*=e,c[g+2]*=f;if(b.origin)for(var i=void 0!=b.origin.x?b.origin.x:0,j=void 0!=b.origin.y?b.origin.y:0,k=void 0!=b.origin.z?b.origin.z:0,g=0,h=c.length;h>g;g+=3)c[g]-=i,c[g+1]-=j,c[g+2]-=k;return c};var c=function(a){a.vertexBuf&&(a.vertexBuf.destroy(),a.vertexBuf=null),a.normalBuf&&(a.normalBuf.destroy(),a.normalBuf=null),a.uvBuf&&(a.uvBuf.destroy(),a.uvBuf=null),a.uvBuf2&&(a.uvBuf2.destroy(),a.uvBuf2=null),a.colorBuf&&(a.colorBuf.destroy(),a.colorBuf=null),a.tangentBuf&&(a.tangentBuf.destroy(),a.tangentBuf=null),a.indexBuf&&(a.indexBuf.destroy(),a.indexBuf=null),a.interleavedBuf&&(a.interleavedBuf.destroy(),a.interleavedBuf=null)};SceneJS.Geometry.prototype._buildNodeCore=function(a,b){var d=a.STATIC_DRAW;try{var e=b.arrays,f=SceneJS.getConfigs("enableInterleaving")!==!1,g=0,h=0,i=[],j=[],k=function(a,b){return 0==g?g=a.length/b:a.length/b!=g&&(f=!1),i.push(a),j.push(b),h+=b,4*(h-b)};if(e.positions&&(f&&(b.interleavedPositionOffset=k(e.positions,3)),b.vertexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.positions,e.positions.length,3,d)),e.normals&&(f&&(b.interleavedNormalOffset=k(e.normals,3)),b.normalBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.normals,e.normals.length,3,d)),e.uv&&(f&&(b.interleavedUVOffset=k(e.uv,2)),b.uvBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv,e.uv.length,2,d)),e.uv2&&(f&&(b.interleavedUV2Offset=k(e.uv2,2)),b.uvBuf2=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.uv2,e.uv2.length,2,d)),e.colors&&(f&&(b.interleavedColorOffset=k(e.colors,4)),b.colorBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,e.colors,e.colors.length,4,d)),e.indices&&(b.indexBuf=new SceneJS._webgl.ArrayBuffer(a,a.ELEMENT_ARRAY_BUFFER,e.indices,e.indices.length,1,d)),h>0&&f){for(var l=[],m=i.length,n=0;g>n;++n)for(var o=0;m>o;++o)for(var p=j[o],q=0;p>q;++q)l.push(i[o][n*p+q]);b.interleavedStride=4*h,b.interleavedBuf=new SceneJS._webgl.ArrayBuffer(a,a.ARRAY_BUFFER,new Float32Array(l),l.length,h,d),b.interleavedBuf.dirty=!1}}catch(r){throw c(b),SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate geometry: "+r)}},SceneJS.Geometry.prototype._updateArray=function(a,b,c){var d=a.length,e=b.length;e+c>d&&(e-=e+c-d);for(var f=c,g=0;e>g;f++,g++)a[f]=b[g]},SceneJS.Geometry.prototype._buildNormals=function(a){for(var b,c,d,e,f,g,h=a.positions,i=a.indices,j=new Array(h.length/3),k=0,l=i.length-3;l>k;k+=3){b=i[k+0],c=i[k+1],d=i[k+2],e=[h[3*b+0],h[3*b+1],h[3*b+2]],f=[h[3*c+0],h[3*c+1],h[3*c+2]],g=[h[3*d+0],h[3*d+1],h[3*d+2]],f=SceneJS_math_subVec4(f,e,[0,0,0,0]),g=SceneJS_math_subVec4(g,e,[0,0,0,0]);var m=SceneJS_math_normalizeVec4(SceneJS_math_cross3Vec4(f,g,[0,0,0,0]),[0,0,0,0]);j[b]||(j[b]=[]),j[c]||(j[c]=[]),j[d]||(j[d]=[]),j[b].push(m),j[c].push(m),j[d].push(m)}for(var n=new Array(h.length),k=0,l=j.length;l>k;k++){for(var o=j[k].length,p=0,q=0,r=0,s=0;o>s;s++)p+=j[k][s][0],q+=j[k][s][1],r+=j[k][s][2];n[3*k+0]=p/o,n[3*k+1]=q/o,n[3*k+2]=r/o}a.normals=n},SceneJS.Geometry.prototype._buildTangents=function(a){for(var b=a.positions,c=a.indices,d=a.uv,e=[],f=0;ft;t++){var u=c[f+t];"undefined"!=typeof e[u]?e[u]=SceneJS_math_addVec3(e[u],s,[]):e[u]=s}}for(var v=[],w=0;wf;f+=3)c=b[f],d=b[f+1],e=b[f+2],cthis._boundary.xmax&&(this._boundary.xmax=c),d>this._boundary.ymax&&(this._boundary.ymax=d),e>this._boundary.zmax&&(this._boundary.zmax=e);return this._boundary},SceneJS.Geometry.prototype._compile=function(c){if(this._core._loading)return void this._compileNodes(c);var d=this._core;d.vertexBuf||(d=this._inheritVBOs(d)),d.indexBuf?(d.hash=[d.normalBuf?"t":"f",d.arrays&&d.arrays.tangents?"t":"f",d.uvBuf?"t":"f",d.uvBuf2?"t":"f",d.colorBuf?"t":"f",d.primitive].join(""),d.stateId=this._core.stateId,d.type="geometry",this._engine.display.geometry=a[b++]=d,SceneJS_events.fireEvent(SceneJS_events.OBJECT_COMPILING,{display:this._engine.display}),this._engine.display.buildObject(this.id)):a[b++]=this._core,this._compileNodes(c),b--},SceneJS.Geometry.prototype._inheritVBOs=function(c){for(var d={primitive:c.primitive,boundary:c.boundary,normalBuf:c.normalBuf,uvBuf:c.uvBuf,uvBuf2:c.uvBuf2,colorBuf:c.colorBuf,interleavedBuf:c.interleavedBuf,indexBuf:c.indexBuf,interleavedStride:c.interleavedStride,interleavedPositionOffset:c.interleavedPositionOffset,interleavedNormalOffset:c.interleavedNormalOffset,interleavedUVOffset:c.interleavedUVOffset,interleavedUV2Offset:c.interleavedUV2Offset,interleavedColorOffset:c.interleavedColorOffset},e=b-1;e>=0;e--)if(a[e].vertexBuf)return d.vertexBuf=a[e].vertexBuf,d.boundary=a[e].boundary,d.normalBuf=a[e].normalBuf,d.uvBuf=a[e].uvBuf,d.uvBuf2=a[e].uvBuf2,d.colorBuf=a[e].colorBuf,d.interleavedBuf=a[e].interleavedBuf,d.interleavedStride=a[e].interleavedStride,d.interleavedPositionOffset=a[e].interleavedPositionOffset,d.interleavedNormalOffset=a[e].interleavedNormalOffset,d.interleavedUVOffset=a[e].interleavedUVOffset,d.interleavedUV2Offset=a[e].interleavedUV2Offset,d.interleavedColorOffset=a[e].interleavedColorOffset,d;return d},SceneJS.Geometry.prototype._destroy=function(){this._engine.display.removeObject(this.id),1==this._core.useCount&&(this._destroyNodeCore(),this._source&&this._source.destroy&&this._source.destroy())},SceneJS.Geometry.prototype._destroyNodeCore=function(){document.getElementById(this._engine.canvas.canvasId)&&c(this._core)}},function(){var a={type:"stage",stateId:SceneJS._baseStateId++,priority:0,pickable:!0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.stage=a,c=0}),SceneJS.Stage=SceneJS_NodeFactory.createNodeType("stage"),SceneJS.Stage.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1,this._core.pickable=!!a.pickable)},SceneJS.Stage.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Stage.prototype.getPriority=function(){return this._core.priority},SceneJS.Stage.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Stage.prototype._compile=function(d){this._engine.display.stage=b[c++]=this._core,this._compileNodes(d),this._engine.display.stage=--c>0?b[c-1]:a}}(),function(){var a={type:"layer",stateId:SceneJS._baseStateId++,priority:0,enabled:!0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.layer=a,c=0}),SceneJS.Layer=SceneJS_NodeFactory.createNodeType("layer"),SceneJS.Layer.prototype._init=function(a){1==this._core.useCount&&(this._core.priority=a.priority||0,this._core.enabled=a.enabled!==!1)},SceneJS.Layer.prototype.setPriority=function(a){a=a||0,this._core.priority!=a&&(this._core.priority=a,this._engine.display.stateOrderDirty=!0)},SceneJS.Layer.prototype.getPriority=function(){return this._core.priority},SceneJS.Layer.prototype.setEnabled=function(a){a=!!a,this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.getEnabled=function(){return this._core.enabled},SceneJS.Layer.prototype.setClearDepth=function(a){a=a||0,this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.drawListDirty=!0)},SceneJS.Layer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Layer.prototype._compile=function(d){this._engine.display.layer=b[c++]=this._core,this._compileNodes(d),this._engine.display.layer=--c>0?b[c-1]:a}}(),SceneJS.Library=SceneJS_NodeFactory.createNodeType("library"),SceneJS.Library.prototype._compile=function(a){},function(){function a(a){if(a.lights&&a.lights.length>0){for(var b,c=a.lights,d=[],e=0,f=c.length;f>e;e++)b=c[e],d.push(b.mode),b.specular&&d.push("s"),b.diffuse&&d.push("d"),d.push("world"==b.space?"w":"v");a.hash=d.join("")}else a.hash=""}var b={type:"lights",stateId:SceneJS._baseStateId++,hash:null,empty:!1,lights:[{mode:"ambient",color:[.7,.7,.8],diffuse:!0,specular:!1},{mode:"dir",color:[1,1,1],diffuse:!0,specular:!0,dir:[-.5,-.5,-1],space:"view"},{mode:"dir",color:[1,1,1],diffuse:!1,specular:!0,dir:[1,-.9,-.7],space:"view"}]};a(b);var c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.lights=b,d=0}),SceneJS.Lights=SceneJS_NodeFactory.createNodeType("lights"),SceneJS.Lights.prototype._init=function(a){if(1==this._core.useCount){var b=a.lights;if(!b)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"lights node attribute missing : 'lights'");this._core.lights=this._core.lights||[];for(var c=0,d=b.length;d>c;c++)this._initLight(c,b[c])}},SceneJS.Lights.prototype._initLight=function(a,b){var c=[];this._core.lights[a]=c;var d=b.mode||"dir";if("dir"!=d&&"point"!=d&&"ambient"!=d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");var e=b.pos,f=b.dir,g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],c.mode=d,c.diffuse="ambient"==d?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==d?!1:void 0!=b.specular?b.specular:!0,c.pos=b.pos?[e.x||0,e.y||0,e.z||0]:[0,0,0],c.dir=b.dir?[f.x||0,f.y||0,f.z||0]:[0,0,1],c.attenuation=[void 0!=b.constantAttenuation?b.constantAttenuation:0,b.linearAttenuation||0,b.quadraticAttenuation||0];var h=b.space;if(h){if("view"!=h&&"world"!=h)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+h+"' - should be 'view' or 'world'")}else h="world";c.space=h,this._core.hash=null},SceneJS.Lights.prototype.setLights=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.lights.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid argument to set 'lights': index out of range ("+this._core.lights.length+" lights defined)");this._setLight(b,a[c]||{})}this._engine.branchDirty(this)},SceneJS.Lights.prototype._setLight=function(a,b){var c=this._core.lights[a],d=!1,e=!1;if(b.mode&&b.mode!=c.mode){var f=b.mode;if("dir"!=f&&"point"!=f&&"ambient"!=f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Light mode not supported - should be 'dir' or 'point' or 'ambient'");c.mode=f,c.diffuse="ambient"==f?!0:void 0!=b.diffuse?b.diffuse:!0,c.specular="ambient"==f?!1:void 0!=b.specular?b.specular:!0,e=!0}if(b.color){var g=b.color;c.color=[void 0!=g.r?g.r:1,void 0!=g.g?g.g:1,void 0!=g.b?g.b:1],d=!0}var h=b.pos;h&&(c.pos=[h.x||0,h.y||0,h.z||0],d=!0);var i=b.dir;if(i&&(c.dir=[i.x||0,i.y||0,i.z||0],d=!0),void 0!=b.constantAttenuation&&(c.attenuation[0]=b.constantAttenuation,d=!0),void 0!=b.linearAttenuation&&(c.attenuation[1]=b.linearAttenuation,d=!0),void 0!=b.quadraticAttenuation&&(c.attenuation[2]=b.quadraticAttenuation,d=!0),b.space&&b.space!=c.space){var j=b.space;if("view"!=j&&"world"!=j)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"lights node invalid value for property 'space': '"+j+"' - should be 'view' or 'world'");c.space=j,this._core.hash=null,e=!0}void 0!=b.specular&&b.specular!=c.specular&&(c.specular=b.specular,e=!0),void 0!=b.diffuse&&b.diffuse!=c.diffuse&&(c.diffuse=b.diffuse,e=!0),e?this._engine.branchDirty(this):d&&(this._engine.display.imageDirty=!0),this._core.hash=null},SceneJS.Lights.prototype._compile=function(e){this._core.hash||a(this._core),this._engine.display.lights=c[d++]=this._core,this._compileNodes(e),this._engine.display.lights=--d>0?c[d-1]:b}}(),function(){var a=SceneJS_math_lookAtMat4c(0,0,10,0,0,0,0,1,0),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4())),d=new Float32Array(c),e={type:"lookAt",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,lookAt:SceneJS_math_LOOKAT_ARRAYS},f=[],g=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.viewTransform=e,g=0}),SceneJS.Lookat=SceneJS_NodeFactory.createNodeType("lookAt"),SceneJS.Lookat.prototype._init=function(a){if(this._mat=null,this._xf={type:"lookat"},1==this._core.useCount){this._core.eyeX=0,this._core.eyeY=0,this._core.eyeZ=10,this._core.lookX=0,this._core.lookY=0,this._core.lookZ=0,this._core.upX=0,this._core.upY=1,this._core.upZ=0,a.eye||a.look||a.up?(this.setEye(a.eye),this.setLook(a.look),this.setUp(a.up)):(this.setEye({x:0,y:0,z:10}),this.setLook({x:0,y:0,z:0}),this.setUp({x:0,y:1,z:0}));var b=this._core,c=this;this._core.rebuild=function(){b.matrix=SceneJS_math_lookAtMat4c(b.eyeX,b.eyeY,b.eyeZ,b.lookX,b.lookY,b.lookZ,b.upX,b.upY,b.upZ),b.lookAt={eye:[b.eyeX,b.eyeY,b.eyeZ],look:[b.lookX,b.lookY,b.lookZ],up:[b.upX,b.upY,b.upZ]},b.mat?(b.mat.set(b.matrix),b.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))):(b.mat=new Float32Array(b.matrix),b.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b.matrix,SceneJS_math_mat4())))),c.publish("matrix",b.matrix),b.dirty=!1},this._core.dirty=!0,this._tick=this.getScene().on("tick",function(){c._core.dirty&&c._core.rebuild()})}},SceneJS.Lookat.getDefaultMatrix=function(){return b},SceneJS.Lookat.prototype.setEye=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.eyeX=a.x),void 0!=a.y&&null!=a.y&&(this._core.eyeY=a.y),void 0!=a.z&&null!=a.z&&(this._core.eyeZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEye=function(a){return a=a||{},this._core.eyeX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.eyeY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.eyeZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeX=function(a){return this._core.eyeX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0, +this},SceneJS.Lookat.prototype.setEyeY=function(a){return this._core.eyeY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setEyeZ=function(a){return this._core.eyeZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeX=function(a){return this._core.eyeX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeY=function(a){return this._core.eyeY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incEyeZ=function(a){return this._core.eyeZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getEye=function(){return{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ}},SceneJS.Lookat.prototype.setLook=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.lookX=a.x),void 0!=a.y&&null!=a.y&&(this._core.lookY=a.y),void 0!=a.z&&null!=a.z&&(this._core.lookZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLook=function(a){return a=a||{},this._core.lookX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.lookY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.lookZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookX=function(a){return this._core.lookX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookY=function(a){return this._core.lookY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setLookZ=function(a){return this._core.lookZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookX=function(a){return this._core.lookX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookY=function(a){return this._core.lookY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incLookZ=function(a){return this._core.lookZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getLook=function(){return{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ}},SceneJS.Lookat.prototype.setUp=function(a){return a=a||{},void 0!=a.x&&null!=a.x&&(this._core.upX=a.x),void 0!=a.y&&null!=a.y&&(this._core.upY=a.y),void 0!=a.z&&null!=a.z&&(this._core.upZ=a.z),this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUp=function(a){return a=a||{},this._core.upX+=void 0!=a.x&&null!=a.x?a.x:0,this._core.upY+=void 0!=a.y&&null!=a.y?a.y:0,this._core.upZ+=void 0!=a.z&&null!=a.z?a.z:0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpX=function(a){return this._core.upX=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpY=function(a){return this._core.upY=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.setUpZ=function(a){return this._core.upZ=a||0,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpX=function(a){return this._core.upX+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpY=function(a){return this._core.upY+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.incUpZ=function(a){return this._core.upZ+=a,this._core.dirty=!0,this._engine.display.imageDirty=!0,this},SceneJS.Lookat.prototype.getUp=function(){return{x:this._core.upX,y:this._core.upY,z:this._core.upZ}},SceneJS.Lookat.prototype.getMatrix=function(){return this._core.dirty&&this._core.rebuild(),this._core.matrix.slice(0)},SceneJS.Lookat.prototype.getAttributes=function(){return{look:{x:this._core.lookX,y:this._core.lookY,z:this._core.lookZ},eye:{x:this._core.eyeX,y:this._core.eyeY,z:this._core.eyeZ},up:{x:this._core.upX,y:this._core.upY,z:this._core.upZ}}},SceneJS.Lookat.prototype._compile=function(a){this._engine.display.viewTransform=f[g++]=this._core,this._compileNodes(a),this._engine.display.viewTransform=--g>0?f[g-1]:e},SceneJS.Lookat.prototype._destroy=function(){this.getScene().off(this._tick)}}(),new function(){var a={type:"material",stateId:SceneJS._baseStateId++,baseColor:[1,1,1],specularColor:[1,1,1],specular:1,shine:70,alpha:1,emit:0},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.material=a,c=0}),SceneJS.Material=SceneJS_NodeFactory.createNodeType("material"),SceneJS.Material.prototype._init=function(a){1==this._core.useCount&&(this.setBaseColor(a.color||a.baseColor),this.setSpecularColor(a.specularColor),this.setSpecular(a.specular),this.setShine(a.shine),this.setEmit(a.emit),this.setAlpha(a.alpha))},SceneJS.Material.prototype.setBaseColor=function(b){var c=a.baseColor;return this._core.baseColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.baseColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.setColor=SceneJS.Material.prototype.setBaseColor,SceneJS.Material.prototype.getBaseColor=function(){return{r:this._core.baseColor[0],g:this._core.baseColor[1],b:this._core.baseColor[2]}},SceneJS.Material.prototype.getColor=SceneJS.Material.prototype.getBaseColor,SceneJS.Material.prototype.setSpecularColor=function(b){var c=a.specularColor;return this._core.specularColor=b?[void 0!=b.r&&null!=b.r?b.r:c[0],void 0!=b.g&&null!=b.g?b.g:c[1],void 0!=b.b&&null!=b.b?b.b:c[2]]:a.specularColor,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecularColor=function(){return{r:this._core.specularColor[0],g:this._core.specularColor[1],b:this._core.specularColor[2]}},SceneJS.Material.prototype.setSpecular=function(b){return this._core.specular=void 0!=b&&null!=b?b:a.specular,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getSpecular=function(){return this._core.specular},SceneJS.Material.prototype.setShine=function(b){return this._core.shine=void 0!=b&&null!=b?b:a.shine,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getShine=function(){return this._core.shine},SceneJS.Material.prototype.setEmit=function(b){return this._core.emit=void 0!=b&&null!=b?b:a.emit,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getEmit=function(){return this._core.emit},SceneJS.Material.prototype.setAlpha=function(b){return this._core.alpha=void 0!=b&&null!=b?b:a.alpha,this._engine.display.imageDirty=!0,this},SceneJS.Material.prototype.getAlpha=function(){return this._core.alpha},SceneJS.Material.prototype._compile=function(d){this._engine.display.material=b[c++]=this._core,this._compileNodes(d),this._engine.display.material=--c>0?b[c-1]:a}},new function(){var a={type:"morphGeometry",stateId:SceneJS._baseStateId++,hash:"",morph:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.morphGeometry=a,c=0}),SceneJS.MorphGeometry=SceneJS_NodeFactory.createNodeType("morphGeometry"),SceneJS.MorphGeometry.prototype._init=function(a){if(1==this._core.useCount){if(this._sourceConfigs=a.source,this._source=null,a.source){if(!a.source.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry config expected: source.type");var b=this;SceneJS.Plugins.getPlugin("morphGeometry",this._sourceConfigs.type,function(c){if(!c)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: no support for source type '"+b._sourceConfigs.type+"' - need to include plugin for self source type, or install a custom source service with SceneJS.Plugins.addPlugin(SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN, '"+b._sourceConfigs.type+"', ).");if(!c.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'getSource' method not found on MorphGeoFactoryService (SceneJS.Plugins.MORPH_GEO_SOURCE_PLUGIN)");if(b._source=c.getSource(),!b._source.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"morphGeometry: 'subscribe' method not found on source provided by plugin type '"+a.source.type+"'");var d=!1;b._source.subscribe(function(a){if(d){if(a.targets)for(var c,e,f,g=a.targets,h=b._core.targets,i=0,j=g.length;j>i;i++)c=g[i],e=c.targetIndex,f=h[e],c.positions&&f.vertexBuf&&(f.vertexBuf.bind(),f.vertexBuf.setData(c.positions,0));b._display.imageDirty=!0}else b._buildNodeCore(a),b._core._loading=!1,b._fireEvent("loaded"),b._engine.branchDirty(b),d=!0}),b._core._loading=!0,b._fireEvent("loading"),b._source.configure(b._sourceConfigs)})}else a.create instanceof Function?this._buildNodeCore(a.create()):this._buildNodeCore(a);this._core.webglRestored=function(){},this.setFactor(a.factor)}this._core.factor=a.factor||0,this._core.clamp=!!a.clamp},SceneJS.MorphGeometry.prototype._buildNodeCore=function(a){var b=a.targets||[];if(b.length<2)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node should have at least two targets");var c=a.keys||[];if(c.length!=b.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"morphGeometry node mismatch in number of keys and targets");var d=this._core,e=this._engine.canvas.gl,f=e.STATIC_DRAW;d.keys=c,d.targets=[],d.key1=0,d.key2=1;for(var g,h,i,j,k,l=0,m=b.length;m>l;l++)k=b[l],!g&&k.positions&&(g=k.positions),!h&&k.normals&&(h=k.normals),!i&&k.uv&&(i=k.uv),!j&&k.uv2&&(j=k.uv2);try{for(var n,o,l=0,m=b.length;m>l;l++)k=b[l],n={},o=k.positions||g,o&&(n.positions="Float32Array"==typeof o?o:new Float32Array(o),n.vertexBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.positions,o.length,3,f),g=o),o=k.normals||h,o&&(n.normals="Float32Array"==typeof o?o:new Float32Array(o),n.normalBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.normals,o.length,3,f),h=o),o=k.uv||i,o&&(n.uv="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv,o.length,2,f),i=o),o=k.uv2||j,o&&(n.uv2="Float32Array"==typeof o?o:new Float32Array(o),n.uvBuf2=new SceneJS._webgl.ArrayBuffer(e,e.ARRAY_BUFFER,n.uv2,o.length,2,f),j=o),d.targets.push(n)}catch(p){for(var l=0,m=d.targets.length;m>l;l++)n=d.targets[l],n.vertexBuf&&n.vertexBuf.destroy(),n.normalBuf&&n.normalBuf.destroy(),n.uvBuf&&n.uvBuf.destroy(),n.uvBuf2&&n.uvBuf2.destroy();throw SceneJS_error.fatalError(SceneJS.errors.ERROR,"Failed to allocate VBO(s) for morphGeometry: "+p)}},SceneJS.MorphGeometry.prototype.setSource=function(a){this._sourceConfigs=a;var b=this._source;b&&b.configure(a)},SceneJS.MorphGeometry.prototype.getSource=function(){return this._sourceConfigs},SceneJS.MorphGeometry.prototype.setFactor=function(a){a=a||0;var b=this._core,c=b.keys,d=b.key1,e=b.key2,f=b.factor;if(ac[c.length-1])d=c.length-2,e=d+1;else{for(;c[d]>a;)d--,e--;for(;c[e]0?b[c-1]:a},SceneJS.MorphGeometry.prototype._makeHash=function(){var a=this._core;if(a.targets.length>0){var b=a.targets[0],c="t",d="f";a.hash=[b.vertexBuf?c:d,b.normalBuf?c:d,b.uvBuf?c:d,b.uvBuf2?c:d].join("")}else a.hash=""},SceneJS.MorphGeometry.prototype._destroy=function(){if(1==this._core.useCount){if(document.getElementById(this._engine.canvas.canvasId))for(var a,b=this._core,c=0,d=b.targets.length;d>c;c++)a=b.targets[c],a.vertexBuf&&a.vertexBuf.destroy(),a.normalBuf&&a.normalBuf.destroy(),a.uvBuf&&a.uvBuf.destroy(),a.uvBuf2&&a.uvBuf2.destroy();this._source&&this._source.destroy&&this._source.destroy()}}},function(){var a={type:"name",stateId:SceneJS._baseStateId++,name:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.name=a,c=0}),SceneJS.Name=SceneJS_NodeFactory.createNodeType("name"),SceneJS.Name.prototype._init=function(a){this.setName(a.name),this._core.nodeId=this.id},SceneJS.Name.prototype.setName=function(a){this._core.name=a||"unnamed",this._engine.branchDirty(this)},SceneJS.Name.prototype.getName=function(){return this._core.name},SceneJS.Name.prototype._compile=function(d){this._engine.display.name=b[c++]=this._core;for(var e,f=[],g=0;c>g;g++)e=b[g].name,e&&f.push(e);this._core.path=f.join("."),this._compileNodes(d),this._engine.display.name=--c>0?b[c-1]:a}}(),new function(){function a(a){var c;if(f>0){c={};for(var d in a)a.hasOwnProperty(d)&&void 0!=a[d]&&(c[d]=g(d))}return b(a.props),{props:a,setProps:function(b){h(b,a)},restoreProps:function(a){c&&i(a,c)}}}function b(a){var b;for(var c in a)a.hasOwnProperty(c)&&(b=a[c],void 0!=b&&null!=b&&(k[c]?a[c]=k[c](null,b):l[c]&&(a[c]=l[c](null,b))))}var c,d={type:"renderer",stateId:SceneJS._baseStateId++,props:null},e=[],f=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){c=a.engine.canvas,f=0,a.engine.display.renderer=e[f++]=d});var g=function(a){for(var b,c,d=f-1;d>=0;d--)if(b=e[d].props,b&&(c=b[a],void 0!=c&&null!=c))return b[a];return null},h=function(a,b){for(var c in b)if(b.hasOwnProperty(c)){var d=k[c];d&&d(a,b[c])}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor),b.clear&&l.clear(a,b.clear)},i=function(a,b){var c;for(var d in b)if(b.hasOwnProperty(d)&&(c=b[d],void 0!=c&&null!=c)){var e=k[d];e&&e(a,c)}b.viewport&&l.viewport(a,b.viewport),b.scissor&&l.clear(a,b.scissor)},j=function(a,b){if(!b)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Null SceneJS.State node config: "'+b+'"');var c=SceneJS._webgl.enumMap[b];if(!c)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,'Unrecognised SceneJS.State node config value: "'+b+'"');var d=a[c];if(!d)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"This browser's WebGL does not support renderer node config value: \""+b+'"');return d},k={enableBlend:function(a,b){return a?void(b?a.enable(a.BLEND):a.disable(a.BLEND)):((null==b||void 0==b)&&(b=!1),b)},blendColor:function(a,b){return a?void a.blendColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},blendEquation:function(a,b){return a?void a.blendEquation(a,j(a,b)):b||"funcAdd"},blendEquationSeparate:function(a,b){return a?void a.blendEquation(j(a,b.rgb),j(a,b.alpha)):(b=b||{},{rgb:b.rgb||"funcAdd",alpha:b.alpha||"funcAdd"})},blendFunc:function(a,b){return a?void a.blendFunc(j(a,b.sfactor||"srcAlpha"),j(a,b.dfactor||"oneMinusSrcAlpha")):(b=b||{},{sfactor:b.sfactor||"srcAlpha",dfactor:b.dfactor||"oneMinusSrcAlpha"})},blendFuncSeparate:function(a,b){return a?void a.blendFuncSeparate(j(a,b.srcRGB||"zero"),j(a,b.dstRGB||"zero"),j(a,b.srcAlpha||"zero"),j(a,b.dstAlpha||"zero")):(b=b||{},{srcRGB:b.srcRGB||"zero",dstRGB:b.dstRGB||"zero",srcAlpha:b.srcAlpha||"zero",dstAlpha:b.dstAlpha||"zero"})},clearColor:function(a,b){return a?void a.clearColor(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},clearDepth:function(a,b){return a?void a.clearDepth(b):null==b||void 0==b?1:b},clearStencil:function(a,b){return a?void a.clearStencil(b):b||0},colorMask:function(a,b){return a?void a.colorMask(b.r,b.g,b.b,b.a):(b=b||{},{r:b.r||0,g:b.g||0,b:b.b||0,a:void 0==b.a||null==b.a?1:b.a})},enableCullFace:function(a,b){return a?void(b?a.enable(a.CULL_FACE):a.disable(a.CULL_FACE)):b},cullFace:function(a,b){return a?void a.cullFace(j(a,b)):b||"back"},enableDepthTest:function(a,b){return a?void(b?a.enable(a.DEPTH_TEST):a.disable(a.DEPTH_TEST)):((null==b||void 0==b)&&(b=!0),b)},depthFunc:function(a,b){return a?void a.depthFunc(j(a,b)):b||"less"},enableDepthMask:function(a,b){return a?void a.depthMask(b):((null==b||void 0==b)&&(b=!0),b)},depthRange:function(a,b){return a?void a.depthRange(b.zNear,b.zFar):(b=b||{},{zNear:void 0==b.zNear||null==b.zNear?0:b.zNear,zFar:void 0==b.zFar||null==b.zFar?1:b.zFar})},frontFace:function(a,b){return a?void a.frontFace(j(a,b)):b||"ccw"},lineWidth:function(a,b){return a?void a.lineWidth(b):b||1},enableScissorTest:function(a,b){return a?void(b?a.enable(a.SCISSOR_TEST):(b=!1,a.disable(a.SCISSOR_TEST))):b}},l={viewport:function(a,b){return a?void a.viewport(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||1,y:b.y||1,width:b.width||c.canvas.width,height:b.height||c.canvas.height})},scissor:function(a,b){return a?void a.scissor(b.x,b.y,b.width,b.height):(b=b||{},{x:b.x||0,y:b.y||0,width:b.width||1,height:b.height||1})},clear:function(a,b){if(!a)return b=b||{};var c;b.color&&(c=a.COLOR_BUFFER_BIT),b.depth&&(c|=a.DEPTH_BUFFER_BIT),b.stencil&&(c|=a.STENCIL_BUFFER_BIT)}};SceneJS.Renderer=SceneJS_NodeFactory.createNodeType("renderer"),SceneJS.Renderer.prototype._init=function(a){if(1==this._core.useCount){for(var b in a)a.hasOwnProperty(b)&&(this._core[b]=a[b]);this._core.dirty=!0}},SceneJS.Renderer.prototype.setViewport=function(a){this._core.viewport=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getViewport=function(){return this._core.viewport?{x:this._core.viewport.x,y:this._core.viewport.y,width:this._core.viewport.width,height:this._core.viewport.height}:void 0},SceneJS.Renderer.prototype.setScissor=function(a){this._core.scissor=a?{x:a.x||1,y:a.y||1,width:a.width||1e3,height:a.height||1e3}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getScissor=function(){return this._core.scissor?{x:this._core.scissor.x,y:this._core.scissor.y,width:this._core.scissor.width,height:this._core.scissor.height}:void 0},SceneJS.Renderer.prototype.setClear=function(a){this._core.clear=a?{r:a.r||0,g:a.g||0,b:a.b||0}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getClear=function(){return this._core.clear?{r:this._core.clear.r,g:this._core.clear.g,b:this._core.clear.b}:null},SceneJS.Renderer.prototype.setEnableBlend=function(a){this._core.enableBlend=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getEnableBlend=function(){return this._core.enableBlend},SceneJS.Renderer.prototype.setBlendColor=function(a){this._core.blendColor=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendColor=function(){return this._core.blendColor?{r:this._core.blendColor.r,g:this._core.blendColor.g,b:this._core.blendColor.b,a:this._core.blendColor.a}:void 0},SceneJS.Renderer.prototype.setBlendEquation=function(a){this._core.blendEquation=a,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquation=function(){return this._core.blendEquation},SceneJS.Renderer.prototype.setBlendEquationSeparate=function(a){this._core.blendEquationSeparate=a?{rgb:a.rgb||"funcAdd",alpha:a.alpha||"funcAdd"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendEquationSeparate=function(){return this._core.blendEquationSeparate?{rgb:this._core.rgb,alpha:this._core.alpha}:void 0},SceneJS.Renderer.prototype.setBlendFunc=function(a){this._core.blendFunc=a?{sfactor:a.sfactor||"srcAlpha",dfactor:a.dfactor||"one"}:void 0,this._core.dirty=!0,this._engine.display.imageDirty=!0},SceneJS.Renderer.prototype.getBlendFunc=function(){return this._core.blendFunc?{sfactor:this._core.sfactor,dfactor:this._core.dfactor}:void 0},SceneJS.Renderer.prototype.setBlendFuncSeparate=function(a){this._core.blendFuncSeparate=a?{srcRGB:a.srcRGB||"zero",dstRGB:a.dstRGB||"zero",srcAlpha:a.srcAlpha||"zero",dstAlpha:a.dstAlpha||"zero"}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getBlendFuncSeparate=function(){return this._core.blendFuncSeparate?{srcRGB:this._core.blendFuncSeparate.srcRGB,dstRGB:this._core.blendFuncSeparate.dstRGB,srcAlpha:this._core.blendFuncSeparate.srcAlpha,dstAlpha:this._core.blendFuncSeparate.dstAlpha}:void 0},SceneJS.Renderer.prototype.setEnableCullFace=function(a){this._core.enableCullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableCullFace=function(){return this._core.enableCullFace},SceneJS.Renderer.prototype.setCullFace=function(a){this._core.cullFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getCullFace=function(){return this._core.cullFace},SceneJS.Renderer.prototype.setEnableDepthTest=function(a){this._core.enableDepthTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthTest=function(){return this._core.enableDepthTest},SceneJS.Renderer.prototype.setDepthFunc=function(a){this._core.depthFunc=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthFunc=function(){return this._core.depthFunc},SceneJS.Renderer.prototype.setEnableDepthMask=function(a){this._core.enableDepthMask=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableDepthMask=function(){return this._core.enableDepthMask},SceneJS.Renderer.prototype.setClearDepth=function(a){this._core.clearDepth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.Renderer.prototype.setDepthRange=function(a){this._core.depthRange=a?{zNear:void 0==a.zNear||null==a.zNear?0:a.zNear,zFar:void 0==a.zFar||null==a.zFar?1:a.zFar}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getDepthRange=function(){return this._core.depthRange?{zNear:this._core.depthRange.zNear,zFar:this._core.depthRange.zFar}:void 0},SceneJS.Renderer.prototype.setFrontFace=function(a){this._core.frontFace=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getFrontFace=function(){return this._core.frontFace},SceneJS.Renderer.prototype.setLineWidth=function(a){this._core.lineWidth=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Renderer.prototype.setEnableScissorTest=function(a){this._core.enableScissorTest=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getEnableScissorTest=function(){return this._core.enableScissorTest},SceneJS.Renderer.prototype.setClearStencil=function(a){this._core.clearStencil=a,this._core.dirty=!0},SceneJS.Renderer.prototype.getClearStencil=function(){return this._core.clearStencil},SceneJS.Renderer.prototype.setColorMask=function(a){this._core.colorMask=a?{r:a.r||0,g:a.g||0,b:a.b||0,a:void 0==a.a||null==a.a?1:a.a}:void 0,this._core.dirty=!0},SceneJS.Renderer.prototype.getColorMask=function(){return this._core.colorMask?{r:this._core.colorMask.r,g:this._core.colorMask.g,b:this._core.colorMask.b,a:this._core.colorMask.a}:void 0},SceneJS.Renderer.prototype._compile=function(b){this._core.dirty&&(this._core.props=a(this._core),this._core.dirty=!1),this._engine.display.renderer=e[f++]=this._core,this._compileNodes(b),this._engine.display.renderer=--f>0?e[f-1]:d}},function(){var a={less:"LESS",equal:"EQUAL",lequal:"LEQUAL",greater:"GREATER",notequal:"NOTEQUAL",gequal:"GEQUAL"},b={type:"depthBuffer",stateId:SceneJS._baseStateId++,enabled:!0,clearDepth:1,depthFunc:null,_depthFuncName:"less"},c=[],d=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){null===b.depthFunc&&(b.depthFunc=a.engine.canvas.gl.LESS),a.engine.display.depthBuffer=b,d=0}),SceneJS.DepthBuf=SceneJS_NodeFactory.createNodeType("depthBuffer"),SceneJS.DepthBuf.prototype._init=function(a){void 0!=a.enabled?this.setEnabled(a.enabled):1==this._core.useCount&&this.setEnabled(!0),void 0!=a.clearDepth?this.setClearDepth(a.clearDepth):1==this._core.useCount&&this.setClearDepth(1),void 0!=a.depthFunc?this.setDepthFunc(a.depthFunc):1==this._core.useCount&&this.setDepthFunc("less"),void 0!=a.clear?this.setClear(a.clear):1==this._core.useCount&&this.setClear(!0)},SceneJS.DepthBuf.prototype.setEnabled=function(a){return this._core.enabled!=a&&(this._core.enabled=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getEnabled=function(){return this._core.enabled},SceneJS.DepthBuf.prototype.setClear=function(a){return this._core.clear!=a&&(this._core.clear=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClear=function(){return this._core.clear},SceneJS.DepthBuf.prototype.setClearDepth=function(a){return this._core.clearDepth!=a&&(this._core.clearDepth=a,this._engine.display.imageDirty=!0),this},SceneJS.DepthBuf.prototype.getClearDepth=function(){return this._core.clearDepth},SceneJS.DepthBuf.prototype.setDepthFunc=function(b){if(this._core._depthFuncName!=b){var c=a[b];if(void 0==c)throw"unsupported value for 'clearFunc' attribute on depthBuffer node: '"+b+"' - supported values are 'less', 'equal', 'lequal', 'greater', 'notequal' and 'gequal'";this._core.depthFunc=this._engine.canvas.gl[c],this._core._depthFuncName=b,this._engine.display.imageDirty=!0}return this},SceneJS.DepthBuf.prototype.getDepthFunc=function(){return this._core._depthFuncName},SceneJS.DepthBuf.prototype._compile=function(a){this._engine.display.depthBuffer=c[d++]=this._core,this._compileNodes(a),this._engine.display.depthBuffer=--d>0?c[d-1]:b}}(),function(){var a={type:"colorBuffer",stateId:SceneJS._baseStateId++,blendEnabled:!1,colorMask:{r:!0,g:!0,b:!0,a:!0}},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.colorBuffer=a,c=0}),SceneJS.ColorBuffer=SceneJS_NodeFactory.createNodeType("colorBuffer"),SceneJS.ColorBuffer.prototype._init=function(a){void 0!=a.blendEnabled?this.setBlendEnabled(a.blendEnabled):1==this._core.useCount&&this.setBlendEnabled(!1),this.setColorMask(a)},SceneJS.ColorBuffer.prototype.setBlendEnabled=function(a){this._core.blendEnabled!=a&&(this._core.blendEnabled=a,this._engine.display.imageDirty=!0),this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getBlendEnabled=function(){return this._core.blendEnabled},SceneJS.ColorBuffer.prototype.setColorMask=function(a){this._core.colorMask={r:void 0!=a.r&&null!=a.r?a.r:!0,g:void 0!=a.g&&null!=a.g?a.g:!0,b:void 0!=a.b&&null!=a.b?a.b:!0,a:void 0!=a.a&&null!=a.a?a.a:!0},this._engine.display.imageDirty=!0},SceneJS.ColorBuffer.prototype.getColorMask=function(){return this._core.colorMask},SceneJS.ColorBuffer.prototype._compile=function(d){this._engine.display.colorBuffer=b[c++]=this._core,this._compileNodes(d),this._engine.display.colorBuffer=--c>0?b[c-1]:a,this._engine.display.imageDirty=!0}}(),function(){var a={type:"view",stateId:SceneJS._baseStateId++,scissorTestEnabled:!1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.view=a,c=0}),SceneJS.View=SceneJS_NodeFactory.createNodeType("view"),SceneJS.View.prototype._init=function(a){void 0!=a.scissorTestEnabled?this.setScissorTestEnabled(a.scissorTestEnabled):1==this._core.useCount&&this.setScissorTestEnabled(!1)},SceneJS.View.prototype.setScissorTestEnabled=function(a){return this._core.scissorTestEnabled!=a&&(this._core.scissorTestEnabled=a,this._engine.display.imageDirty=!0),this},SceneJS.View.prototype.getScissorTestEnabled=function(){return this._core.scissorTestEnabled},SceneJS.View.prototype._compile=function(d){this._engine.display.view=b[c++]=this._core,this._compileNodes(d),this._engine.display.view=--c>0?b[c-1]:a}}(),SceneJS.Scene=SceneJS_NodeFactory.createNodeType("scene"),SceneJS.Scene.prototype._init=function(a){a.tagMask&&this.setTagMask(a.tagMask),this._tagSelector=null,this.transparent=a.transparent===!0},SceneJS.Scene.prototype.loseWebGLContext=function(){this._engine.loseWebGLContext()},SceneJS.Scene.prototype.getCanvas=function(){return this._engine.canvas.canvas},SceneJS.Scene.prototype.getGL=function(){return this._engine.canvas.gl},SceneJS.Scene.prototype.getZBufferDepth=function(){var a=this._engine.canvas.gl;return a.getParameter(a.DEPTH_BITS)},SceneJS.Scene.prototype.setSSAAMultiplier=function(a){return this._engine.canvas.setSSAAMultiplier(a)},SceneJS.Scene.prototype.setTagMask=function(a){a=a||"XXXXXXXXXXXXXXXXXXXXXXXXXX",this._tagSelector||(this._tagSelector={}),this._tagSelector.mask=a,this._tagSelector.regex=a?new RegExp(a):null,this._engine.display.selectTags(this._tagSelector)},SceneJS.Scene.prototype.getTagMask=function(){return this._tagSelector?this._tagSelector.mask:null},SceneJS.Scene.prototype.setNumPasses=function(a){this._engine.setNumPasses(a)},SceneJS.Scene.prototype.renderFrame=function(a){return this._engine.renderFrame(a)},SceneJS.Scene.prototype.needFrame=function(){this._engine.display.imageDirty=!0},SceneJS.Scene.prototype.start=function(a){this._engine.start(a)},SceneJS.Scene.prototype.setFPS=function(a){this._engine.fps=a},SceneJS.Scene.prototype.pause=function(a){this._engine.pause(a)},SceneJS.Scene.prototype.isRunning=function(){return this._engine.running},SceneJS.Scene.prototype.pick=function(a,b,c){var d=this._engine.pick(a,b,c);return this.renderFrame({force:!0}),d?(this.publish("pick",d),d):void this.publish("nopick")},SceneJS.Scene.prototype.readPixels=function(a,b){return this._engine.readPixels(a,b)},SceneJS.Scene.prototype._destroy=function(){this.destroyed||(delete SceneJS._engines[this.id],SceneJS._engineIds.removeItem(this.id),this.destroyed=!0)},SceneJS.Scene.prototype.isActive=function(){return!this._engine.destroyed},SceneJS.Scene.prototype.stop=function(){this._engine.stop()},SceneJS.Scene.prototype.containsNode=function(a){return!!this._engine.findNode(a)},SceneJS.Scene.prototype.findNodes=function(a){return this._engine.findNodes(a)},SceneJS.Scene.prototype.findNode=function(a,b){return this.getNode(a,b)},SceneJS.Scene.prototype.getNode=function(a,b){var c=this._engine.findNode(a);return c?(b&&b(c),c):b?void this.once("nodes/"+a,b):null},SceneJS.Scene.prototype.hasCore=function(a,b){return this._engine.hasCore(a,b)},SceneJS.Scene.prototype.getStatus=function(){var a=SceneJS_sceneStatusModule.sceneStatus[this.id];return a?SceneJS._shallowClone(a):{destroyed:!0}},new function(){function a(a){for(var b,c,d={},e=0;i>e;e++){b=a[e];for(c in b)b.hasOwnProperty(c)&&(d[c]=b[c])}return d}var b={type:"shader",stateId:SceneJS._baseStateId++,hash:"",empty:!0,shader:{}},c=[],d=[],e=[],f=[],g=[],h=[],i=0,j=!0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.shader=b,i=0,j=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(k){if(j){if(i>0){var l={type:"shader",stateId:c[i-1],hash:c.slice(0,i).join("."),shaders:{fragment:{code:f.slice(0,i).join(""),hooks:a(g)},vertex:{code:d.slice(0,i).join(""),hooks:a(e)}},paramsStack:h.slice(0,i)};k.display.shader=l}else k.display.shader=b;j=!1}}),SceneJS.Shader=SceneJS_NodeFactory.createNodeType("shader"),SceneJS.Shader.prototype._init=function(a){1==this._core.useCount&&(this._setShaders(a.shaders),this.setParams(a.params))},SceneJS.Shader.prototype._setShaders=function(a){a=a||[],this._core.shaders={};for(var b,c=0,d=a.length;d>c;c++){if(b=a[c],!b.stage)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"shader 'stage' attribute expected");var e;b.code&&(e=SceneJS._isArray(b.code)?b.code.join(""):b.code),this._core.shaders[b.stage]={code:e,hooks:b.hooks}}},SceneJS.Shader.prototype.setParams=function(a){a=a||{};var b=this._core.params;b||(b=this._core.params={});for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.Shader.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.Shader.prototype._compile=function(a){ +c[i]=this._core.coreId;var b=this._core.shaders,k=b.fragment||{},l=b.vertex||{};f[i]=k.code||"",g[i]=k.hooks||{},d[i]=l.code||"",e[i]=l.hooks||{},h[i]=this._core.params||{},i++,j=!0,this._compileNodes(a),i--,j=!0}},new function(){var a,b={type:"shaderParams",stateId:SceneJS._baseStateId++,empty:!0},c=[],d=[],e=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(c){c.engine.display.shaderParams=b,e=0,a=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(f){if(a){if(e>0){var g={type:"shaderParams",stateId:c[e-1],paramsStack:d.slice(0,e)};f.display.shaderParams=g}else f.display.shaderParams=b;a=!1}}),SceneJS.ShaderParams=SceneJS_NodeFactory.createNodeType("shaderParams"),SceneJS.ShaderParams.prototype._init=function(a){1==this._core.useCount&&this.setParams(a.params)},SceneJS.ShaderParams.prototype.setParams=function(a){a=a||{};var b=this._core;b.params||(b.params={});for(var c in a)a.hasOwnProperty(c)&&(b.params[c]=a[c]);this._engine.display.imageDirty=!0},SceneJS.ShaderParams.prototype.getParams=function(){var a=this._core.params;if(!a)return{};var b={};for(var c in a)a.hasOwnProperty(c)&&(b[c]=a[c]);return b},SceneJS.ShaderParams.prototype._compile=function(b){c[e]=this._core.coreId,d[e]=this._core.params,e++,a=!0,this._compileNodes(b),e--,a=!0}},function(){var a={type:"style",stateId:SceneJS._baseStateId++,lineWidth:1},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.style=a,c=0}),SceneJS.Style=SceneJS_NodeFactory.createNodeType("style"),SceneJS.Style.prototype._init=function(a){void 0!=a.lineWidth&&this.setLineWidth(a.lineWidth)},SceneJS.Style.prototype.setLineWidth=function(a){return this._core.lineWidth!=a&&(this._core.lineWidth=a,this._engine.display.imageDirty=!0),this},SceneJS.Style.prototype.getLineWidth=function(){return this._core.lineWidth},SceneJS.Style.prototype._compile=function(d){this._engine.display.style=b[c++]=this._core,this._compileNodes(d),this._engine.display.style=--c>0?b[c-1]:a}}(),function(){var a={type:"tag",stateId:SceneJS._baseStateId++,tag:null},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.tag=a,c=0}),SceneJS.Tag=SceneJS_NodeFactory.createNodeType("tag"),SceneJS.Tag.prototype._init=function(a){if(1==this._core.useCount){if(!a.tag)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"tag node attribute missing : 'tag'");this.setTag(a.tag)}},SceneJS.Tag.prototype.setTag=function(a){var b=this._core;b.tag=a,b.pattern=null,b.matched=!1,this._engine.display.drawListDirty=!0},SceneJS.Tag.prototype.getTag=function(){return this._core.tag},SceneJS.Tag.prototype._compile=function(d){this._engine.display.tag=b[c++]=this._core,this._compileNodes(d),this._engine.display.tag=--c>0?b[c-1]:a}}(),new function(){var a={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.texture=a,c=0}),SceneJS.Texture=SceneJS_NodeFactory.createNodeType("_texture"),SceneJS.Texture.prototype._init=function(a){if(1==this._core.useCount){this._core.layers=[],this._core.params={};var b=void 0==a.waitForLoad?!0:a.waitForLoad;if(!a.layers)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers missing");if(!SceneJS._isArray(a.layers))throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layers should be an array");for(var c,d=this._engine.canvas.gl,e=0;ec;c++)h._loadLayerTexture(b,a[c])}}},SceneJS.Texture.prototype._loadLayerTexture=function(a,b){var c=this,d=b.source;if(d){if(!d.type)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"texture layer config expected: source.type");SceneJS.Plugins.getPlugin("texture",d.type,function(e){if(!e.getSource)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'getSource' method missing on plugin for texture source type '"+d.type+"'.");var f=e.getSource({gl:a});if(!f.subscribe)throw SceneJS_error.fatalError(SceneJS.errors.PLUGIN_INVALID,"texture: 'subscribe' method missing on plugin for texture source type '"+d.type+"'");var g=SceneJS_sceneStatusModule.taskStarted(c,"Loading texture");f.subscribe(function(){var d=!1;return function(e){d?c._engine.display.imageDirty=!0:(d=!0,c._setLayerTexture(a,b,e),SceneJS_sceneStatusModule.taskFinished(g))}}()),f.configure&&f.configure(d),b._source=f})}else{var e=b.uri||b.src,f=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),g=new Image;g.onload=function(){var d=a.createTexture();a.bindTexture(a.TEXTURE_2D,d);var e=SceneJS_configsModule.configs.maxTextureSize;e&&(g=SceneJS._webgl.clampImageSize(g,e)),a.texImage2D(a.TEXTURE_2D,0,a.RGBA,a.RGBA,a.UNSIGNED_BYTE,c._ensureImageSizePowerOfTwo(g)),c._setLayerTexture(a,b,d),SceneJS_sceneStatusModule.taskFinished(f),c._engine.display.imageDirty=!0},g.onerror=function(){SceneJS_sceneStatusModule.taskFailed(f)},0==e.indexOf("data")?g.src=e:(g.crossOrigin="Anonymous",g.src=e)}},SceneJS.Texture.prototype._ensureImageSizePowerOfTwo=function(a){if(!this._isPowerOfTwo(a.width)||!this._isPowerOfTwo(a.height)){var b=document.createElement("canvas");b.width=this._nextHighestPowerOfTwo(a.width),b.height=this._nextHighestPowerOfTwo(a.height);var c=b.getContext("2d");c.drawImage(a,0,0,a.width,a.height,0,0,b.width,b.height),a=b,a.crossOrigin=""}return a},SceneJS.Texture.prototype._isPowerOfTwo=function(a){return 0==(a&a-1)},SceneJS.Texture.prototype._nextHighestPowerOfTwo=function(a){--a;for(var b=1;32>b;b<<=1)a|=a>>b;return a+1},SceneJS.Texture.prototype._setLayerTexture=function(a,b,c){b.texture=new SceneJS._webgl.Texture2D(a,{texture:c,minFilter:this._getGLOption("minFilter",a,b,a.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",a,b,a.LINEAR),wrapS:this._getGLOption("wrapS",a,b,a.REPEAT),wrapT:this._getGLOption("wrapT",a,b,a.REPEAT),isDepth:this._getOption(b.isDepth,!1),depthMode:this._getGLOption("depthMode",a,b,a.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",a,b,a.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",a,b,a.LEQUAL),flipY:this._getOption(b.flipY,!0),width:this._getOption(b.width,1),height:this._getOption(b.height,1),internalFormat:this._getGLOption("internalFormat",a,b,a.LEQUAL),sourceFormat:this._getGLOption("sourceType",a,b,a.ALPHA),sourceType:this._getGLOption("sourceType",a,b,a.UNSIGNED_BYTE),update:null}),this.destroyed&&b.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._getGLOption=function(a,b,c,d){var e=c[a];if(void 0==e)return d;var f=SceneJS._webgl.enumMap[e];if(void 0==f)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+e+"'");var g=b[f];return g},SceneJS.Texture.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.Texture.prototype.setLayer=function(a){if(void 0==a.index||null==a.index)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index null or undefined");if(a.index<0||a.index>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(parseInt(a.index),a),this._engine.display.imageDirty=!0},SceneJS.Texture.prototype.setLayers=function(a){var b;for(var c in a)if(a.hasOwnProperty(c)&&(void 0!=c||null!=c)){if(b=parseInt(c),0>b||b>=this._core.layers.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Invalid texture set layer argument: index out of range ("+this._core.layers.length+" layers defined)");this._setLayer(b,a[c]||{})}this._engine.display.imageDirty=!0},SceneJS.Texture.prototype._setLayer=function(a,b){b=b||{};var c=this._core.layers[a];if(void 0!=b.blendFactor&&null!=b.blendFactor&&(c.blendFactor=b.blendFactor),b.source){var d=c._source;d&&d.configure&&d.configure(b.source)}(b.translate||b.rotate||b.scale)&&this._setLayerTransform(b,c)},SceneJS.Texture.prototype._setLayerTransform=function(a,b){var c,d;if(a.translate){var e=a.translate;void 0!=e.x&&(b.translate.x=e.x),void 0!=e.y&&(b.translate.y=e.y),c=SceneJS_math_translationMat4v([e.x||0,e.y||0,0])}if(a.scale){var f=a.scale;void 0!=f.x&&(b.scale.x=f.x),void 0!=f.y&&(b.scale.y=f.y),d=SceneJS_math_scalingMat4v([f.x||1,f.y||1,1]),c=c?SceneJS_math_mulMat4(c,d):d}if(a.rotate){var g=a.rotate;void 0!=g.z&&(b.rotate.z=g.z||0),d=SceneJS_math_rotationMat4v(.0174532925*g.z,[0,0,1]),c=c?SceneJS_math_mulMat4(c,d):d}c&&(b.matrix=c,b.matrixAsArray?b.matrixAsArray.set(b.matrix):b.matrixAsArray=new Float32Array(b.matrix),b.matrixAsArray=new Float32Array(b.matrix))},SceneJS.Texture.prototype._compile=function(d){this._core.hash||this._makeHash(),this._engine.display.texture=b[c++]=this._core,this._compileNodes(d),this._engine.display.texture=--c>0?b[c-1]:a},SceneJS.Texture.prototype._makeHash=function(){var a,b=this._core;if(b.layers&&b.layers.length>0){for(var c,d=b.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");a=e.join("")}else a="";b.hash!=a&&(b.hash=a)},SceneJS.Texture.prototype._destroy=function(){if(1==this._core.useCount)for(var a,b,c=this._core.layers,d=0,e=c.length;e>d;d++)a=c[d],a.texture&&a.texture.destroy(),b=a._source,b&&b.destroy&&b.destroy()}},new function(){function a(){var a,b;(0!=this.translate.x||0!=this.translate.y)&&(a=SceneJS_math_translationMat4v([this.translate.x||0,this.translate.y||0,0])),(1!=this.scale.x||1!=this.scale.y)&&(b=SceneJS_math_scalingMat4v([this.scale.x||1,this.scale.y||1,1]),a=a?SceneJS_math_mulMat4(a,b):b),0!=this.rotate&&(b=SceneJS_math_rotationMat4v(.0174532925*this.rotate,[0,0,1]),a=a?SceneJS_math_mulMat4(a,b):b),a&&(this.matrix=a,this.matrixAsArray?this.matrixAsArray.set(this.matrix):this.matrixAsArray=new Float32Array(this.matrix)),this._matrixDirty=!1}var b={type:"texture",stateId:SceneJS._baseStateId++,empty:!0,hash:""};SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(a){a.engine.display.texture=b,d=0});var c=[],d=0;SceneJS.TextureMap=SceneJS_NodeFactory.createNodeType("texture"),SceneJS.TextureMap.prototype._init=function(b){var c=this;if(1==this._core.useCount){if(b.applyFrom&&"uv"!=b.applyFrom&&"uv2"!=b.applyFrom&&"normal"!=b.applyFrom&&"geometry"!=b.applyFrom)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyFrom value is unsupported - should be either 'uv', 'uv2', 'normal' or 'geometry'");if(b.applyTo&&"baseColor"!=b.applyTo&&"color"!=b.applyTo&&"specular"!=b.applyTo&&"emit"!=b.applyTo&&"alpha"!=b.applyTo&&"normals"!=b.applyTo&&"shine"!=b.applyTo)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture applyTo value is unsupported - should be either 'color', 'baseColor', 'specular' or 'normals'");if(b.blendMode&&"add"!=b.blendMode&&"multiply"!=b.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"texture layer blendMode value is unsupported - should be either 'add' or 'multiply'");"color"==b.applyTo&&(b.applyTo="baseColor"),SceneJS._apply({waitForLoad:void 0==b.waitForLoad?!0:b.waitForLoad,texture:null,applyFrom:b.applyFrom?b.applyFrom:"uv",applyTo:b.applyTo?b.applyTo:"baseColor",blendMode:b.blendMode?b.blendMode:"multiply",blendFactor:void 0!=b.blendFactor&&null!=b.blendFactor?b.blendFactor:1,translate:b.translate?SceneJS._apply(b.translate,{x:0,y:0}):{x:0,y:0},scale:b.scale?SceneJS._apply(b.scale,{x:1,y:1}):{x:1,y:1},rotate:b.rotate||0,matrix:null,_matrixDirty:!0,buildMatrix:a},this._core),a.call(this._core),b.src?(this._core.src=b.src,this._loadTexture(b.src)):b.image?(this._core.image=b.image,this._initTexture(b.image)):b.target&&this.getScene().getNode(b.target,function(a){c.setTarget(a)}),this._core.webglRestored=function(){c._core.image?c._initTexture(c._core.image):c._core.src?c._loadTexture(c._core.src):c._core.target}}},SceneJS.TextureMap.prototype._loadTexture=function(a){var b=this,c=SceneJS_sceneStatusModule.taskStarted(this,"Loading texture"),d=new Image;d.onload=function(){b._initTexture(d),SceneJS_sceneStatusModule.taskFinished(c),b._engine.display.imageDirty=!0},d.onerror=function(){SceneJS_sceneStatusModule.taskFailed(c)},0==a.indexOf("data")?d.src=a:(d.crossOrigin="Anonymous",d.src=a)},SceneJS.TextureMap.prototype._initTexture=function(a){var b=this._engine.canvas.gl,c=b.createTexture();b.bindTexture(b.TEXTURE_2D,c);var d=SceneJS_configsModule.configs.maxTextureSize;d&&(a=SceneJS._webgl.clampImageSize(a,d)),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(a)),this._core.image=a,this._core.texture=new SceneJS._webgl.Texture2D(b,{texture:c,minFilter:this._getGLOption("minFilter",b.LINEAR_MIPMAP_NEAREST),magFilter:this._getGLOption("magFilter",b.LINEAR),wrapS:this._getGLOption("wrapS",b.REPEAT),wrapT:this._getGLOption("wrapT",b.REPEAT),isDepth:this._getOption(this._core.isDepth,!1),depthMode:this._getGLOption("depthMode",b.LUMINANCE),depthCompareMode:this._getGLOption("depthCompareMode",b.COMPARE_R_TO_TEXTURE),depthCompareFunc:this._getGLOption("depthCompareFunc",b.LEQUAL),flipY:this._getOption(this._core.flipY,!0),width:this._getOption(this._core.width,1),height:this._getOption(this._core.height,1),internalFormat:this._getGLOption("internalFormat",b.ALPHA),sourceFormat:this._getGLOption("sourceFormat",b.ALPHA),sourceType:this._getGLOption("sourceType",b.UNSIGNED_BYTE),update:null}),this.destroyed&&this._core.texture.destroy(),this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype._getGLOption=function(a,b){var c=this._engine.canvas.gl,d=this._core[a];if(void 0==d)return b;var e=SceneJS._webgl.enumMap[d];if(void 0==e)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"Unrecognised value for texture node property '"+a+"' value: '"+d+"'");return c[e]},SceneJS.TextureMap.prototype._getOption=function(a,b){return void 0==a?b:a},SceneJS.TextureMap.prototype.setSrc=function(a){this._core.image=null,this._core.src=a,this._core.target=null,this._loadTexture(a)},SceneJS.TextureMap.prototype.setImage=function(a){this._core.image=a,this._core.src=null,this._core.target=null,this._initTexture(a)},SceneJS.TextureMap.prototype.setTarget=function(a){return"colorTarget"!=a.type&&"depthTarget"!=a.type?void console.log("Target node type not compatible: "+a.type):(delete this._core.src,this._core.target=a,this._core.src=null,this._core.image=null,this._core.texture=a._core.renderBuf.getTexture(),this._core.texture.bufType=a._core.bufType,void(this._engine.display.imageDirty=!0))},SceneJS.TextureMap.prototype.setBlendFactor=function(a){this._core.blendFactor=a,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getBlendFactor=function(){return this._core.blendFactor},SceneJS.TextureMap.prototype.setTranslate=function(a){this._core.translate||(this._core.translate={x:0,y:0}),this._core.translate.x=a.x,this._core.translate.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getTranslate=function(){return this._core.translate},SceneJS.TextureMap.prototype.setScale=function(a){this._core.scale||(this._core.scale={x:0,y:0}),this._core.scale.x=a.x,this._core.scale.y=a.y,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getScale=function(){return this._core.scale},SceneJS.TextureMap.prototype.setRotate=function(a){this._core.rotate=a,this._core._matrixDirty=!0,this._engine.display.imageDirty=!0},SceneJS.TextureMap.prototype.getRotate=function(){return this._core.rotate},SceneJS.TextureMap.prototype.getMatrix=function(){return this._core._matrixDirty&&this._core.buildMatrix.call(this.core)(),this.core.matrix},SceneJS.TextureMap.prototype._compile=function(a){this.__core||(this.__core=this._engine._coreFactory.getCore("texture"));var e=this._engine.display.texture;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),c[d++]=this.__core,this._engine.display.texture=this.__core,this._compileNodes(a),this._engine.display.texture=--d>0?c[d-1]:b},SceneJS.TextureMap.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyFrom),e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode),c.matrix&&e.push("/anim");b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.TextureMap.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&!this._core.target&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}},function(){var a={type:"cubemap",stateId:SceneJS._baseStateId++,empty:!0,texture:null,hash:""},b=[],c=0;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(b){b.engine.display.cubemap=a,c=0}),SceneJS.Reflect=SceneJS_NodeFactory.createNodeType("reflect"),SceneJS.Reflect.prototype._init=function(a){if(1==this._core.useCount){if(this._core.hash="y",a.blendMode&&"add"!=a.blendMode&&"multiply"!=a.blendMode)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"reflection blendMode value is unsupported - should be either 'add' or 'multiply'");this._core.blendMode=a.blendMode||"multiply",this._core.intensity=void 0!=a.intensity&&null!=a.intensity?a.intensity:1,this._core.applyTo="reflect";for(var b=this,c=this._engine.canvas.gl,d=c.createTexture(),e=[c.TEXTURE_CUBE_MAP_POSITIVE_X,c.TEXTURE_CUBE_MAP_NEGATIVE_X,c.TEXTURE_CUBE_MAP_POSITIVE_Y,c.TEXTURE_CUBE_MAP_NEGATIVE_Y,c.TEXTURE_CUBE_MAP_POSITIVE_Z,c.TEXTURE_CUBE_MAP_NEGATIVE_Z],f=[],g=SceneJS_sceneStatusModule.taskStarted(this,"Loading reflection texture"),h=!1,i=0;ii;i++)c.texImage2D(e[i],0,c.RGBA,c.RGBA,c.UNSIGNED_BYTE,SceneJS._webgl.ensureImageSizePowerOfTwo(f[i]));b._core.texture=new SceneJS._webgl.Texture2D(c,{texture:d,target:c.TEXTURE_CUBE_MAP,minFilter:c.LINEAR,magFilter:c.LINEAR,wrapS:c.CLAMP_TO_EDGE,wrapT:c.CLAMP_TO_EDGE}),SceneJS_sceneStatusModule.taskFinished(g),b._engine.display.imageDirty=!0}}}(),j.onerror=function(){h=!0,SceneJS_sceneStatusModule.taskFailed(g)},j.src=a.src[i]}}},SceneJS.Reflect.prototype._compile=function(d){this.__core||(this.__core=this._engine._coreFactory.getCore("cubemap"));var e=this._engine.display.cubemap;this._core.empty||(this.__core.layers=e&&e.layers?e.layers.concat([this._core]):[this._core]),this._makeHash(this.__core),b[c++]=this.__core,this._engine.display.cubemap=this.__core,this._compileNodes(d),this._engine.display.cubemap=--c>0?b[c-1]:a},SceneJS.Reflect.prototype._makeHash=function(a){var b;if(a.layers&&a.layers.length>0){for(var c,d=a.layers,e=[],f=0,g=d.length;g>f;f++)c=d[f],e.push("/"),e.push(c.applyTo),e.push("/"),e.push(c.blendMode);b=e.join("")}else b="";a.hash!=b&&(a.hash=b)},SceneJS.Reflect.prototype._destroy=function(){1==this._core.useCount&&this._core.texture&&(this._core.texture.destroy(),this._core.texture=null),this._core&&this._engine._coreFactory.putCore(this._core)}}(),SceneJS.XForm=SceneJS_NodeFactory.createNodeType("xform"),SceneJS.XForm.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.XForm.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.XForm.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.XForm.prototype.setElements=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.XForm elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.XForm.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Matrix=SceneJS_NodeFactory.createNodeType("matrix"),SceneJS.Matrix.prototype._init=function(a){1==this._core.useCount&&(SceneJS_modelXFormStack.buildCore(this._core),this.setElements(a.elements))},SceneJS.Matrix.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Matrix.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Matrix.prototype.setMatrix=function(a){if(a=a||SceneJS_math_identityMat4(),16!=a.length)throw SceneJS_error.fatalError(SceneJS.errors.ILLEGAL_NODE_CONFIG,"SceneJS.Matrix elements should number 16");var b=this._core;if(b.matrix)for(var c=0;16>c;c++)b.matrix[c]=a[c];else b.matrix=a;return b.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Matrix.prototype.setElements=SceneJS.Matrix.prototype.setMatrix,SceneJS.Matrix.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Rotate=SceneJS_NodeFactory.createNodeType("rotate"),SceneJS.Rotate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setAngle(a.angle),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_rotationMat4v(b.angle*Math.PI/180,[b.x,b.y,b.z])}}},SceneJS.Rotate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Rotate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Rotate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for rotate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.setAngle=function(a){this._core.angle=a||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getAngle=function(){return this._core.angle},SceneJS.Rotate.prototype.setXYZ=function(a){a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Rotate.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getX=function(){return this._core.x},SceneJS.Rotate.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getY=function(){return this._core.y},SceneJS.Rotate.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype.getZ=function(){return this._core.z},SceneJS.Rotate.prototype.incAngle=function(a){this._core.angle+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Rotate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Translate=SceneJS_NodeFactory.createNodeType("translate"),SceneJS.Translate.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_translationMat4v([b.x,b.y,b.z],b.matrix)}}},SceneJS.Translate.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Translate.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Translate.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for translate node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Translate.prototype.setXYZ=function(a){return a=a||{},this._core.x=a.x||0,this._core.y=a.y||0,this._core.z=a.z||0,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Translate.prototype.setX=function(a){return this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setY=function(a){return this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.setZ=function(a){return this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incX=function(a){return this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incY=function(a){return this._core.y+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.incZ=function(a){return this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0,this},SceneJS.Translate.prototype.getX=function(){return this._core.x},SceneJS.Translate.prototype.getY=function(){return this._core.y},SceneJS.Translate.prototype.getZ=function(){return this._core.z},SceneJS.Translate.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()},SceneJS.Scale=SceneJS_NodeFactory.createNodeType("scale"),SceneJS.Scale.prototype._init=function(a){if(1==this._core.useCount){SceneJS_modelXFormStack.buildCore(this._core),this.setMultOrder(a.multOrder),this.setXYZ({x:a.x,y:a.y,z:a.z});var b=this._core;this._core.buildMatrix=function(){b.matrix=SceneJS_math_scalingMat4v([b.x,b.y,b.z])}}},SceneJS.Scale.prototype.getModelMatrix=function(){return this._core.dirty&&this._core.build(),this._core.matrix},SceneJS.Scale.prototype.getWorldMatrix=function(){return this._core.dirty&&this._core.build(),Array.apply([],this._core.mat)},SceneJS.Scale.prototype.setMultOrder=function(a){if(a=a||"post","post"!=a&&"pre"!=a)throw SceneJS_error.fatalError(SceneJS.errors.NODE_CONFIG_EXPECTED,"Illegal multOrder for scale node - '"+a+"' should be 'pre' or 'post'");this._core.multOrder=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setXYZ=function(a){a=a||{},this._core.x=void 0==a.x?1:a.x,this._core.y=void 0==a.y?1:a.y,this._core.z=void 0==a.z?1:a.z,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getXYZ=function(){return{x:this._core.x,y:this._core.y,z:this._core.z}},SceneJS.Scale.prototype.setX=function(a){this._core.x=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setY=function(a){this._core.y=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.setZ=function(a){this._core.z=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.getX=function(){return this._core.x},SceneJS.Scale.prototype.getY=function(){return this._core.y},SceneJS.Scale.prototype.getZ=function(){return this._core.z},SceneJS.Scale.prototype.incX=function(a){this._core.x+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype.incY=function(a){this._core.y+=a,this._core.matrixDirty=!0},SceneJS.Scale.prototype.incZ=function(a){this._core.z+=a,this._core.setDirty(),this._engine.display.imageDirty=!0},SceneJS.Scale.prototype._compile=function(a){SceneJS_modelXFormStack.push(this._core),this._compileNodes(a),SceneJS_modelXFormStack.pop()};var SceneJS_modelXFormStack=new function(){var a=SceneJS_math_identityMat4(),b=new Float32Array(a),c=SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(SceneJS_math_identityMat4(),SceneJS_math_mat4())),d=new Float32Array(c),e={type:"xform",stateId:SceneJS._baseStateId++,matrix:a,mat:b,normalMatrix:c,normalMat:d,parent:null,cores:[],numCores:0,dirty:!1,matrixDirty:!1},f=[],g=0;this.top=e;var h,i=this;SceneJS_events.addListener(SceneJS_events.SCENE_COMPILING,function(){g=0,i.top=e,h=!0}),SceneJS_events.addListener(SceneJS_events.OBJECT_COMPILING,function(a){h&&(g>0?a.display.modelTransform=f[g-1]:a.display.modelTransform=e,h=!1)}),this.buildCore=function(a){function b(a){a.dirty=!0,a.matrixDirty=!0;for(var c=0,d=a.numCores;d>c;c++)b(a.cores[c])}a.parent=null,a.cores=[],a.numCores=0,a.matrixDirty=!1,a.matrix=SceneJS_math_identityMat4(),a.mat=new Float32Array(a.matrix),a.normalMat=new Float32Array(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(a.matrix,SceneJS_math_mat4()))),a.dirty=!1,a.setDirty=function(){a.matrixDirty=!0,a.dirty,b(a)},a.build=function(){a.matrixDirty&&(a.buildMatrix&&a.buildMatrix(),a.matrixDirty=!1);var b,c=a.parent;if(c)for(b=a.matrix.slice(0);c;)c.matrixDirty&&(c.buildMatrix&&c.buildMatrix(),c.mat.set(c.matrix),c.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(c.matrix,SceneJS_math_mat4()))),c.matrixDirty=!1),SceneJS_math_mulMat4(c.matrix,b,b),!c.dirty,c=c.parent;else b=a.matrix;a.mat.set(b),a.normalMat.set(SceneJS_math_transposeMat4(SceneJS_math_inverseMat4(b,SceneJS_math_mat4()))),a.dirty=!1}},this.push=function(a){f[g++]=a,a.parent=this.top,a.dirty=!0,this.top&&(this.top.cores[this.top.numCores++]=a),a.numCores=0,this.top=a,h=!0},this.pop=function(){this.top=--g>0?f[g-1]:e,h=!0}};SceneJS.Types=new function(){this.addType=function(a,b){SceneJS_NodeFactory.createNodeType(a,b,function(a){var c;for(var d in b)if(b.hasOwnProperty(d))switch(c=b[d],d){case"init":case"construct":!function(){var c=b[d];a.prototype._init=function(a){c.call(this,a)},a.prototype._fromPlugin=!0}();break;case"destroy":case"destruct":a.prototype._destroy=c;break;default:a.prototype[d]=c}})},this.hasType=function(a){return!!SceneJS_NodeFactory.nodeTypes[a]}};var SceneJS_Display=function(a){this._canvas=a.canvas, +this._programFactory=new SceneJS_ProgramFactory({canvas:a.canvas}),this._chunkFactory=new SceneJS_ChunkFactory,this.transparent=a.transparent===!0,this.enable=null,this.flags=null,this.layer=null,this.stage=null,this.renderer=null,this.depthBuffer=null,this.colorBuffer=null,this.view=null,this.lights=null,this.material=null,this.texture=null,this.cubemap=null,this.modelTransform=null,this.viewTransform=null,this.projTransform=null,this.renderTarget=null,this.clips=null,this.morphGeometry=null,this.name=null,this.tag=null,this.renderListeners=null,this.shader=null,this.shaderParams=null,this.style=null,this.geometry=null,this._objectFactory=new SceneJS_ObjectFactory,this._objects={},this._ambientColor=[0,0,0,1],this._objectList=[],this._objectListLen=0,this._drawList=[],this._drawListLen=0,this._pickDrawList=[],this._pickDrawListLen=0,this._targetList=[],this._targetListLen=0,this._frameCtx={pickNames:[],canvas:this._canvas,VAO:null},this._frameCtx.renderListenerCtx=new SceneJS.RenderContext(this._frameCtx),this.objectListDirty=!0,this.stateOrderDirty=!0,this.stateSortDirty=!0,this.drawListDirty=!0,this.imageDirty=!0,this.pickBufDirty=!0,this.rayPickBufDirty=!0};SceneJS_Display.prototype.webglRestored=function(){this._programFactory.webglRestored(),this._chunkFactory.webglRestored();var a=this._canvas.gl;this.pickBuf&&this.pickBuf.webglRestored(a),this.rayPickBuf&&this.rayPickBuf.webglRestored(a),this.imageDirty=!0},SceneJS_Display.prototype.buildObject=function(a){var b=this._objects[a];b||(b=this._objects[a]=this._objectFactory.getObject(a),this.objectListDirty=!0),b.stage=this.stage,b.layer=this.layer,b.renderTarget=this.renderTarget,b.texture=this.texture,b.cubemap=this.cubemap,b.geometry=this.geometry,b.enable=this.enable,b.flags=this.flags,b.tag=this.tag;var c=[this.geometry.hash,this.shader.hash,this.clips.hash,this.morphGeometry.hash,this.texture.hash,this.cubemap.hash,this.lights.hash,this.flags.hash].join(";");b.program&&c==b.hash||(b.program&&this._programFactory.putProgram(b.program),b.program=this._programFactory.getProgram(c,this),b.hash=c),this._setChunk(b,0,"program"),this._setChunk(b,1,"xform",this.modelTransform),this._setChunk(b,2,"lookAt",this.viewTransform),this._setChunk(b,3,"camera",this.projTransform),this._setChunk(b,4,"flags",this.flags),this._setChunk(b,5,"shader",this.shader),this._setChunk(b,6,"shaderParams",this.shaderParams),this._setChunk(b,7,"style",this.style),this._setChunk(b,8,"depthBuffer",this.depthBuffer),this._setChunk(b,9,"colorBuffer",this.colorBuffer),this._setChunk(b,10,"view",this.view),this._setChunk(b,11,"name",this.name),this._setChunk(b,12,"lights",this.lights),this._setChunk(b,13,"material",this.material),this._setChunk(b,14,"texture",this.texture),this._setChunk(b,15,"cubemap",this.cubemap),this._setChunk(b,16,"clips",this.clips),this._setChunk(b,17,"renderer",this.renderer),this._setChunk(b,18,"geometry",this.morphGeometry,this.geometry),this._setChunk(b,19,"listeners",this.renderListeners),this._setChunk(b,20,"draw",this.geometry)},SceneJS_Display.prototype._setChunk=function(a,b,c,d,e){var f,g=this._chunkFactory.chunkTypes[c];if(d){if(d.empty){var h=a.chunks[b];return h&&this._chunkFactory.putChunk(h),void(a.chunks[b]=null)}f=g.prototype.programGlobal?"_"+d.stateId:"p"+a.program.id+"_"+d.stateId,e&&(f+="__"+e.stateId)}else f="p"+a.program.id;f=b+"__"+f;var h=a.chunks[b];if(h){if(h.id==f)return;this._chunkFactory.putChunk(h)}a.chunks[b]=this._chunkFactory.getChunk(f,c,a.program,d,e),"lights"==c&&this._setAmbient(d)},SceneJS_Display.prototype._setAmbient=function(a){for(var b,c=a.lights,d=0,e=c.length;e>d;d++)b=c[d],"ambient"==b.mode&&(this._ambientColor[0]=b.color[0],this._ambientColor[1]=b.color[1],this._ambientColor[2]=b.color[2])},SceneJS_Display.prototype.removeObject=function(a){var b=this._objects[a];b&&(this._programFactory.putProgram(b.program),b.program=null,b.hash=null,this._objectFactory.putObject(b),delete this._objects[a],this.objectListDirty=!0)},SceneJS_Display.prototype.selectTags=function(a){this._tagSelector=a,this.drawListDirty=!0},SceneJS_Display.prototype.render=function(a){a=a||{},this.objectListDirty&&(this._buildObjectList(),this.objectListDirty=!1,this.stateOrderDirty=!0),this.stateOrderDirty&&(this._makeStateSortKeys(),this.stateOrderDirty=!1,this.stateSortDirty=!0),this.stateSortDirty&&(this._stateSort(),this.stateSortDirty=!1,this.drawListDirty=!0),this.drawListDirty&&(this._buildDrawList(),this.imageDirty=!0),(this.imageDirty||a.force)&&(this._doDrawList({clear:a.clear!==!1}),this.imageDirty=!1,this.pickBufDirty=!0)},SceneJS_Display.prototype._buildObjectList=function(){this._objectListLen=0;for(var a in this._objects)this._objects.hasOwnProperty(a)&&(this._objectList[this._objectListLen++]=this._objects[a])},SceneJS_Display.prototype._makeStateSortKeys=function(){for(var a,b=0,c=this._objectListLen;c>b;b++)a=this._objectList[b],a.program?a.sortKey=1e12*(a.stage.priority+1)+1e9*(a.flags.transparent?2:1)+1e6*(a.layer.priority+1)+1e3*(a.program.id+1)+a.texture.stateId:a.sortKey=-1},SceneJS_Display.prototype._stateSort=function(){this._objectList.length=this._objectListLen,this._objectList.sort(this._stateSortObjects)},SceneJS_Display.prototype._stateSortObjects=function(a,b){return a.sortKey-b.sortKey},SceneJS_Display.prototype._logObjectList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._objectListLen+" objects");for(var a=0,b=this._objectListLen;b>a;a++){var c=this._objectList[a];console.log("SceneJS_Display : object["+a+"] sortKey = "+c.sortKey)}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._buildDrawList=function(){this._lastStateId=this._lastStateId||[],this._lastPickStateId=this._lastPickStateId||[];for(var a=0;23>a;a++)this._lastStateId[a]=null,this._lastPickStateId[a]=null;this._drawListLen=0,this._pickDrawListLen=0;var b,c,d,e,f,g={},h=[],i=[];this._tagSelector&&(c=this._tagSelector.mask,d=this._tagSelector.regex),this._objectDrawList=this._objectDrawList||[],this._objectDrawListLen=0;for(var a=0,j=this._objectListLen;j>a;a++)if(b=this._objectList[a],b.enable.enabled!==!1&&(f=b.flags,f.enabled!==!1&&b.layer.enabled&&(!c||(e=b.tag,!e.tag||(e.mask!=c&&(e.mask=c,e.matches=d.test(e.tag)),e.matches)))))if(b.renderTarget.targets)for(var k,l,m,n=b.renderTarget.targets,o=0,p=n.length;p>o;o++)k=n[o],l=k.coreId,m=g[l],m||(m=[],g[l]=m,h.push(m),i.push(this._chunkFactory.getChunk(k.stateId,"renderTarget",b.program,k))),m.push(b);else this._objectDrawList[this._objectDrawListLen++]=b;for(var m,k,b,q,a=0,j=h.length;j>a;a++){m=h[a],k=i[a],this._appendRenderTargetChunk(k);for(var o=0,p=m.length;p>o;o++)b=m[o],q=b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q)}b&&this._appendRenderTargetChunk(this._chunkFactory.getChunk(-1,"renderTarget",b.program,{}));for(var a=0,j=this._objectDrawListLen;j>a;a++)b=this._objectDrawList[a],q=!b.stage||b.stage&&b.stage.pickable,this._appendObjectToDrawLists(b,q);this.drawListDirty=!1},SceneJS_Display.prototype._appendRenderTargetChunk=function(a){this._drawList[this._drawListLen++]=a},SceneJS_Display.prototype._appendObjectToDrawLists=function(a,b){for(var c,d=a.chunks,e=a.flags.picking,f=0,g=d.length;g>f;f++)c=d[f],c&&(c.draw&&(c.unique||this._lastStateId[f]!=c.id)&&(this._drawList[this._drawListLen++]=c,this._lastStateId[f]=c.id),c.pick&&b!==!1&&e&&(c.unique||this._lastPickStateId[f]!=c.id)&&(this._pickDrawList[this._pickDrawListLen++]=c,this._lastPickStateId[f]=c.id))},SceneJS_Display.prototype._logDrawList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._drawListLen+" draw list chunks");for(var a=0,b=this._drawListLen;b>a;a++){var c=this._drawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype._logPickList=function(){console.log("--------------------------------------------------------------------------------------------------"),console.log(this._pickDrawListLen+" pick list chunks");for(var a=0,b=this._pickDrawListLen;b>a;a++){var c=this._pickDrawList[a];switch(console.log("[chunk "+a+"] type = "+c.type),c.type){case"draw":console.log("\n");break;case"renderTarget":console.log(" bufType = "+c.core.bufType)}}console.log("--------------------------------------------------------------------------------------------------")},SceneJS_Display.prototype.pick=function(a){var b=this._canvas.canvas,c=this._canvas.ssaaMultiplier,d=null,e=a.canvasX*c,f=a.canvasY*c,g=this.pickBuf;g||(g=this.pickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.pickBufDirty=!0),this.render(),g.bind(),this.pickBufDirty&&(g.clear(),this._doDrawList({pick:!0,clear:!0}),this._canvas.gl.finish(),this.pickBufDirty=!1,this.rayPickBufDirty=!0);var h=g.read(e,f),i=h[0]+256*h[1]+65536*h[2],j=i>=1?i-1:-1;g.unbind();var k=this._frameCtx.pickNames[j];if(k&&(d={name:k.name,path:k.path,nodeId:k.nodeId,canvasPos:[e,f]},a.rayPick)){var l=this.rayPickBuf;l||(l=this.rayPickBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas}),this.rayPickBufDirty=!0),l.bind(),this.rayPickBufDirty&&(l.clear(),this._doDrawList({pick:!0,rayPick:!0,clear:!0}),this.rayPickBufDirty=!1),h=l.read(e,f),l.unbind();var m=this._unpackDepth(h),n=b.width,o=b.height,p=(e-n/2)/(n/2),q=-(f-o/2)/(o/2),r=this._frameCtx.cameraMat,s=this._frameCtx.viewMat,t=SceneJS_math_mulMat4(r,s,[]),u=SceneJS_math_inverseMat4(t,[]),v=SceneJS_math_transformVector4(u,[p,q,-1,1]);v=SceneJS_math_mulVec4Scalar(v,1/v[3]);var w=SceneJS_math_transformVector4(u,[p,q,1,1]);w=SceneJS_math_mulVec4Scalar(w,1/w[3]);var x=SceneJS_math_subVec3(w,v,[]),y=SceneJS_math_addVec3(v,SceneJS_math_mulVec4Scalar(x,m,[]),[]);d.worldPos=y}return d},SceneJS_Display.prototype.readPixels=function(a,b){this._readPixelBuf||(this._readPixelBuf=new SceneJS._webgl.RenderBuffer({canvas:this._canvas})),this._readPixelBuf.bind(),this._readPixelBuf.clear(),this.render({force:!0});for(var c,d,e=0;b>e;e++)c=a[e]||(a[e]={}),d=this._readPixelBuf.read(c.x,c.y),c.r=d[0],c.g=d[1],c.b=d[2],c.a=d[3];this._readPixelBuf.unbind()},SceneJS_Display.prototype._unpackDepth=function(a){var b=[a[0]/256,a[1]/256,a[2]/256,a[3]/256],c=[1/16777216,1/65536,1/256,1];return SceneJS_math_dotVector4(b,c)},SceneJS_Display.prototype._doDrawList=function(a){var b=this._canvas.gl,c=this._frameCtx;c.renderTarget=null,c.targetIndex=0,c.renderBuf=null,c.viewMat=null,c.modelMat=null,c.cameraMat=null,c.renderer=null,c.depthbufEnabled=null,c.clearDepth=null,c.depthFunc=b.LESS,c.scissorTestEnabled=!1,c.blendEnabled=!1,c.backfaces=!0,c.frontface="ccw",c.pick=!!a.pick,c.rayPick=!!a.rayPick,c.pickIndex=0,c.textureUnit=0,c.lineWidth=1,c.transparent=!1,c.ambientColor=this._ambientColor,c.aspect=this._canvas.canvas.width/this._canvas.canvas.height,this._canvas.UINT_INDEX_ENABLED&&b.getExtension("OES_element_index_uint");var d=b.getExtension("OES_vertex_array_object");if(c.VAO=d?d:null,b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),this.transparent?b.clearColor(0,0,0,0):b.clearColor(this._ambientColor[0],this._ambientColor[1],this._ambientColor[2],1),a.clear&&b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),b.frontFace(b.CCW),b.disable(b.CULL_FACE),b.disable(b.BLEND),a.pick)for(var e=0,f=this._pickDrawListLen;f>e;e++)this._pickDrawList[e].pick(c);else for(var e=0,f=this._drawListLen;f>e;e++)this._drawList[e].draw(c);if(b.flush(),c.renderBuf&&c.renderBuf.unbind(),c.VAO){c.VAO.bindVertexArrayOES(null);for(var e=0;10>e;e++)b.disableVertexAttribArray(e)}},SceneJS_Display.prototype.destroy=function(){this._programFactory.destroy()};var SceneJS_ProgramSourceFactory=new function(){function a(a){if(a.renderTarget&&a.renderTarget.targets)for(var b=a.renderTarget.targets,c=0,d=b.length;d>c;c++)if("depth"===b[c].bufType)return!0;return!1}function b(a){return a.getShaderPrecisionFormat?a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.HIGH_FLOAT).precision>0?"highp":a.getShaderPrecisionFormat(a.FRAGMENT_SHADER,a.MEDIUM_FLOAT).precision>0?"mediump":"lowp":"mediump"}this._sourceCache={},this.getSource=function(a,b){var c=this._sourceCache[a];return c?(c.useCount++,c):this._sourceCache[a]=new SceneJS_ProgramSource(a,this._composePickingVertexShader(b),this._composePickingFragmentShader(b),this._composeRenderingVertexShader(b),this._composeRenderingFragmentShader(b))},this.putSource=function(a){var b=this._sourceCache[a];b&&0==--b.useCount&&(this._sourceCache[b.hash]=null)},this._composePickingVertexShader=function(a){var b=!!a.morphGeometry.targets,c=["attribute vec3 SCENEJS_aVertex;","uniform mat4 SCENEJS_uMMatrix;","uniform mat4 SCENEJS_uVMatrix;","uniform mat4 SCENEJS_uVNMatrix;","uniform mat4 SCENEJS_uPMatrix;"];return c.push("varying vec4 SCENEJS_vWorldVertex;"),c.push("varying vec4 SCENEJS_vViewVertex;"),b&&(c.push("uniform float SCENEJS_uMorphFactor;"),a.morphGeometry.targets[0].vertexBuf&&c.push("attribute vec3 SCENEJS_aMorphVertex;")),c.push("void main(void) {"),c.push(" vec4 tmpVertex=vec4(SCENEJS_aVertex, 1.0); "),b&&a.morphGeometry.targets[0].vertexBuf&&c.push(" tmpVertex = vec4(mix(tmpVertex.xyz, SCENEJS_aMorphVertex, SCENEJS_uMorphFactor), 1.0); "),c.push(" SCENEJS_vWorldVertex = SCENEJS_uMMatrix * tmpVertex; "),c.push(" SCENEJS_vViewVertex = SCENEJS_uVMatrix * SCENEJS_vWorldVertex;"),c.push(" gl_Position = SCENEJS_uPMatrix * SCENEJS_vViewVertex;"),c.push("}"),c},this._composePickingFragmentShader=function(a){var c=a.clips.clips.length>0,d=b(a._canvas.gl),e=["precision "+d+" float;"];if(e.push("varying vec4 SCENEJS_vWorldVertex;"),e.push("varying vec4 SCENEJS_vViewVertex;"),e.push("uniform bool SCENEJS_uRayPickMode;"),e.push("uniform vec3 SCENEJS_uPickColor;"),e.push("uniform float SCENEJS_uZNear;"),e.push("uniform float SCENEJS_uZFar;"),e.push("uniform bool SCENEJS_uClipping;"),c)for(var f=0;f 0.0) { discard; }"),e.push("}")}return e.push(" if (SCENEJS_uRayPickMode) {"),e.push(" float zNormalizedDepth = abs((SCENEJS_uZNear + SCENEJS_vViewVertex.z) / (SCENEJS_uZFar - SCENEJS_uZNear));"),e.push(" gl_FragColor = packDepth(zNormalizedDepth); "),e.push(" } else {"),e.push(" gl_FragColor = vec4(SCENEJS_uPickColor.rgb, 1.0); "),e.push(" }"),e.push("}"),e},this._isTexturing=function(a){if(a.texture.layers&&a.texture.layers.length>0){if(a.geometry.uvBuf||a.geometry.uvBuf2)return!0;if(a.morphGeometry.targets&&(a.morphGeometry.targets[0].uvBuf||a.morphGeometry.targets[0].uvBuf2))return!0}return!1},this._isCubeMapping=function(a){return a.flags.reflective&&a.cubemap.layers&&a.cubemap.layers.length>0&&a.geometry.normalBuf},this._hasNormals=function(a){return a.geometry.normalBuf?!0:a.morphGeometry.targets&&a.morphGeometry.targets[0].normalBuf?!0:!1},this._hasTangents=function(a){if(a.texture){var b=a.texture.layers;if(!b)return!1;for(var c=0,d=b.length;d>c;c++)if("normals"==b[c].applyTo)return!0}return!1},this._composeRenderingVertexShader=function(a){var b=a.shader.shaders||{};if(b.vertex&&b.vertex.code&&""!=b.vertex.code&&SceneJS._isEmpty(b.vertex.hooks))return[b.vertex.code];var c=b.vertex||{},d=c.hooks||{},e=b.fragment||{},f=e.hooks||{},g=this._isTexturing(a),h=this._hasNormals(a),i=this._hasTangents(a),j=a.clips.clips.length>0,k=!!a.morphGeometry.targets,l=[];if(l.push("uniform mat4 SCENEJS_uMMatrix;"),l.push("uniform mat4 SCENEJS_uVMatrix;"),l.push("uniform mat4 SCENEJS_uPMatrix;"),l.push("attribute vec3 SCENEJS_aVertex;"),l.push("uniform vec3 SCENEJS_uWorldEye;"),l.push("varying vec3 SCENEJS_vViewEyeVec;"),h){l.push("attribute vec3 SCENEJS_aNormal;"),l.push("uniform mat4 SCENEJS_uMNMatrix;"),l.push("uniform mat4 SCENEJS_uVNMatrix;"),l.push("varying vec3 SCENEJS_vViewNormal;"),i&&l.push("attribute vec4 SCENEJS_aTangent;");for(var m=0;m0,m=b(c._canvas.gl),n=["\n"];if(n.push("precision "+m+" float;"),l&&n.push("varying vec4 SCENEJS_vWorldVertex;"),n.push("varying vec4 SCENEJS_vViewVertex;"),n.push("uniform float SCENEJS_uZNear;"),n.push("uniform float SCENEJS_uZFar;"),l)for(var o=0;oo;o++)p=c.texture.layers[o],n.push("uniform sampler2D SCENEJS_uSampler"+o+";"),p.matrix&&n.push("uniform mat4 SCENEJS_uLayer"+o+"Matrix;"),n.push("uniform float SCENEJS_uLayer"+o+"BlendFactor;")}if(i&&h)for(var p,o=0,q=c.cubemap.layers.length;q>o;o++)p=c.cubemap.layers[o],n.push("uniform samplerCube SCENEJS_uCubeMapSampler"+o+";"),n.push("uniform float SCENEJS_uCubeMapIntensity"+o+";");if(n.push("uniform bool SCENEJS_uClipping;"),n.push("uniform bool SCENEJS_uSolid;"),n.push("uniform bool SCENEJS_uDepthMode;"),n.push("uniform bool SCENEJS_uTransparent;"),c.geometry.colorBuf&&n.push("varying vec4 SCENEJS_vColor;"),n.push("uniform vec3 SCENEJS_uAmbientColor;"),n.push("uniform vec3 SCENEJS_uMaterialColor;"),n.push("uniform float SCENEJS_uMaterialAlpha;"),n.push("uniform float SCENEJS_uMaterialEmit;"),n.push("uniform vec3 SCENEJS_uMaterialSpecularColor;"),n.push("uniform float SCENEJS_uMaterialSpecular;"),n.push("uniform float SCENEJS_uMaterialShine;"),n.push("varying vec3 SCENEJS_vViewEyeVec;"),i){n.push("varying vec3 SCENEJS_vViewNormal;");for(var r,o=0;o 0.0) { discard; }"),n.push("}")}i&&j&&(n.push(" float a = dot(normalize(SCENEJS_vViewNormal), normalize(SCENEJS_vViewEyeVec));"),n.push(" if (a < 0.0) {"),n.push(" gl_FragColor = vec4(0.4, 0.4, 1.0, 1.0);"),n.push(" return;"),n.push(" }")),n.push(" vec3 ambient= SCENEJS_uAmbientColor;"),g&&c.geometry.uvBuf&&f.texturePos&&n.push(f.texturePos+"(SCENEJS_vUVCoord);"),f.viewPos&&n.push(f.viewPos+"(SCENEJS_vViewVertex);"),i&&f.viewNormal&&n.push(f.viewNormal+"(SCENEJS_vViewNormal);"),c.geometry.colorBuf?n.push(" vec3 color = SCENEJS_vColor.rgb;"):n.push(" vec3 color = SCENEJS_uMaterialColor;"),n.push(" float alpha = SCENEJS_uMaterialAlpha;"),n.push(" float emit = SCENEJS_uMaterialEmit;"),n.push(" float specular = SCENEJS_uMaterialSpecular;"),n.push(" vec3 specularColor = SCENEJS_uMaterialSpecularColor;"),n.push(" float shine = SCENEJS_uMaterialShine;"),f.materialBaseColor&&n.push("color="+f.materialBaseColor+"(color);"),f.materialAlpha&&n.push("alpha="+f.materialAlpha+"(alpha);"),f.materialEmit&&n.push("emit="+f.materialEmit+"(emit);"),f.materialSpecular&&n.push("specular="+f.materialSpecular+"(specular);"),f.materialSpecularColor&&n.push("specularColor="+f.materialSpecularColor+"(specularColor);"),f.materialShine&&n.push("shine="+f.materialShine+"(shine);"),i&&(n.push(" float attenuation = 1.0;"),k?n.push(" vec3 viewNormalVec = vec3(0.0, 1.0, 0.0);"):n.push(" vec3 viewNormalVec = normalize(SCENEJS_vViewNormal);"));var p;if(g){n.push(" vec4 texturePos;"),n.push(" vec2 textureCoord=vec2(0.0,0.0);");for(var o=0,q=c.texture.layers.length;q>o;o++){if(p=c.texture.layers[o],"normal"==p.applyFrom&&i){if(!c.geometry.normalBuf){SceneJS.log.warn("Texture layer applyFrom='normal' but geo has no normal vectors");continue}n.push("texturePos=vec4(viewNormalVec.xyz, 1.0);")}if("uv"==p.applyFrom){if(!c.geometry.uvBuf){SceneJS.log.warn("Texture layer applyTo='uv' but geometry has no UV coordinates");continue}n.push("texturePos = vec4(SCENEJS_vUVCoord.s, SCENEJS_vUVCoord.t, 1.0, 1.0);")}if("uv2"==p.applyFrom){if(!c.geometry.uvBuf2){SceneJS.log.warn("Texture layer applyTo='uv2' but geometry has no UV2 coordinates");continue}n.push("texturePos = vec4(SCENEJS_vUVCoord2.s, SCENEJS_vUVCoord2.t, 1.0, 1.0);")}p.matrix?n.push("textureCoord=(SCENEJS_uLayer"+o+"Matrix * texturePos).xy;"):n.push("textureCoord=texturePos.xy;"),"alpha"==p.applyTo&&("multiply"==p.blendMode?n.push("alpha = alpha * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);"):"add"==p.blendMode&&n.push("alpha = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * alpha) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).b);")),"baseColor"==p.applyTo&&("multiply"==p.blendMode?n.push("color = color * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);"):n.push("color = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * color) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).rgb);")),"emit"==p.applyTo&&("multiply"==p.blendMode?n.push("emit = emit * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):n.push("emit = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * emit) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"specular"==p.applyTo&&i&&("multiply"==p.blendMode?n.push("specular = specular * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):n.push("specular = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * specular) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"shine"==p.applyTo&&("multiply"==p.blendMode?n.push("shine = shine * (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);"):n.push("shine = ((1.0 - SCENEJS_uLayer"+o+"BlendFactor) * shine) + (SCENEJS_uLayer"+o+"BlendFactor * texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, 1.0 - textureCoord.y)).r);")),"normals"==p.applyTo&&i&&n.push("viewNormalVec = normalize(texture2D(SCENEJS_uSampler"+o+", vec2(textureCoord.x, -textureCoord.y)).xyz * 2.0 - 1.0);")}}if(i&&h){n.push("vec3 envLookup = reflect(SCENEJS_vViewEyeVec, viewNormalVec);"),n.push("envLookup.y = envLookup.y * -1.0;"),n.push("vec4 envColor;");for(var o=0,q=c.cubemap.layers.length;q>o;o++)p=c.cubemap.layers[o],n.push("envColor = textureCube(SCENEJS_uCubeMapSampler"+o+", envLookup);"),n.push("color = mix(color, envColor.rgb, specular * SCENEJS_uCubeMapIntensity"+o+");")}if(n.push(" vec4 fragColor;"),i){n.push(" vec3 lightValue = vec3(0.0, 0.0, 0.0);"),n.push(" vec3 specularValue = vec3(0.0, 0.0, 0.0);"),n.push(" vec3 viewLightVec;"),n.push(" float dotN;"),n.push(" float lightDist;");for(var r,o=0,q=c.lights.lights.length;q>o;o++)r=c.lights.lights[o],"ambient"!=r.mode&&(n.push("viewLightVec = SCENEJS_vViewLightVecAndDist"+o+".xyz;"),"point"==r.mode&&(n.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),n.push("lightDist = SCENEJS_vViewLightVecAndDist"+o+".w;"),n.push("attenuation = 1.0 - ( SCENEJS_uLightAttenuation"+o+"[0] + SCENEJS_uLightAttenuation"+o+"[1] * lightDist + SCENEJS_uLightAttenuation"+o+"[2] * lightDist * lightDist);"),r.diffuse&&n.push(" lightValue += dotN * SCENEJS_uLightColor"+o+" * attenuation;"),r.specular&&n.push(" specularValue += specularColor * SCENEJS_uLightColor"+o+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine) * attenuation;")),"dir"==r.mode&&(n.push("dotN = max(dot(normalize(viewNormalVec), normalize(viewLightVec)), 0.0);"),r.diffuse&&n.push(" lightValue += dotN * SCENEJS_uLightColor"+o+";"),r.specular&&n.push("specularValue += specularColor * SCENEJS_uLightColor"+o+" * specular * pow(max(dot(reflect(normalize(-viewLightVec), normalize(-viewNormalVec)), normalize(-SCENEJS_vViewVertex.xyz)), 0.0), shine);")));n.push(" fragColor = vec4((specularValue.rgb + color.rgb * (lightValue.rgb + ambient.rgb)) + (emit * color.rgb), alpha);")}else n.push("fragColor = vec4((color.rgb + (emit * color.rgb)) * (vec3(1.0, 1.0, 1.0) + ambient.rgb), alpha);");return f.pixelColor&&n.push("fragColor="+f.pixelColor+"(fragColor);"),a(c)?(n.push(" if (SCENEJS_uDepthMode) {"),n.push(" float depth = length(SCENEJS_vViewVertex) / (SCENEJS_uZFar - SCENEJS_uZNear);"),n.push(" const vec4 bias = vec4(1.0 / 255.0,"),n.push(" 1.0 / 255.0,"),n.push(" 1.0 / 255.0,"),n.push(" 0.0);"),n.push(" float r = depth;"),n.push(" float g = fract(r * 255.0);"),n.push(" float b = fract(g * 255.0);"),n.push(" float a = fract(b * 255.0);"),n.push(" vec4 colour = vec4(r, g, b, a);"),n.push(" gl_FragColor = colour - (colour.yzww * bias);"),n.push(" } else {"),n.push(" gl_FragColor = fragColor;"),n.push(" };")):n.push(" gl_FragColor = fragColor;"),n.push("}"),n}},SceneJS_ProgramSource=function(a,b,c,d,e){this.hash=a,this.pickVertexSrc=b,this.pickFragmentSrc=c,this.drawVertexSrc=d,this.drawFragmentSrc=e,this.useCount=0},SceneJS_ProgramFactory=function(a){this._canvas=a.canvas,this._programs={},this._nextProgramId=0};SceneJS_ProgramFactory.prototype.getProgram=function(a,b){var c=this._programs[a];if(!c){var d=SceneJS_ProgramSourceFactory.getSource(a,b);c=new SceneJS_Program(this._nextProgramId++,a,d,this._canvas.gl),this._programs[a]=c}return c.useCount++,c},SceneJS_ProgramFactory.prototype.putProgram=function(a){--a.useCount<=0&&(a.draw.destroy(),a.pick.destroy(),SceneJS_ProgramSourceFactory.putSource(a.hash),delete this._programs[a.hash])},SceneJS_ProgramFactory.prototype.webglRestored=function(){var a,b=this._canvas.gl;for(var c in this._programs)this._programs.hasOwnProperty(c)&&(a=this._programs[c],a&&a.build&&a.build(b))},SceneJS_ProgramFactory.prototype.destroy=function(){};var SceneJS_Program=function(a,b,c,d){this.id=a,this.hash=c.hash,this.source=c,this.gl=d,this.UINT_INDEX_ENABLED=!!d.getExtension("OES_element_index_uint"),this.draw=null,this.pick=null,this.useCount=0,this.build(d)};SceneJS_Program.prototype.build=function(a){this.gl=a,this.draw=new SceneJS._webgl.Program(a,[this.source.drawVertexSrc.join("\n")],[this.source.drawFragmentSrc.join("\n")]), +this.pick=new SceneJS._webgl.Program(a,[this.source.pickVertexSrc.join("\n")],[this.source.pickFragmentSrc.join("\n")])};var SceneJS_ObjectFactory=function(){};SceneJS_ObjectFactory.prototype._freeObjects=[],SceneJS_ObjectFactory.prototype._numFreeObjects=0,SceneJS_ObjectFactory.prototype.getObject=function(a){var b;return this._numFreeObjects>0?(b=this._freeObjects[--this._numFreeObjects],b.id=a,b):new SceneJS_Object(a)},SceneJS_ObjectFactory.prototype.putObject=function(a){this._freeObjects[this._numFreeObjects++]=a};var SceneJS_Object=function(a){this.id=a,this.hash=null,this.sortKey=null,this.chunks=[],this.chunksLen=0,this.program=null,this.layer=null,this.texture=null,this.flags=null,this.tag=null};SceneJS.RenderContext=function(a){this._frameCtx=a},SceneJS.RenderContext.prototype.getCameraMatrix=function(){return this._frameCtx.cameraMat},SceneJS.RenderContext.prototype.getViewMatrix=function(){return this._frameCtx.viewMat},SceneJS.RenderContext.prototype.getModelMatrix=function(){return this._frameCtx.modelMat},SceneJS.RenderContext.prototype.getCanvasPos=function(a){this.getProjPos(a);var b=this._frameCtx.canvas.canvas,c=this._frameCtx.canvas.ssaaMultiplier,d=b.width/c,e=b.height/c,f=this._pc,g=f[0]/f[3]*d*.5,h=f[1]/f[3]*e*.5;return{x:g+.5*d,y:e-h-.5*e}},SceneJS.RenderContext.prototype.getCameraPos=function(a){return this.getProjPos(a),this._camPos=SceneJS_math_normalizeVec3(this._pc,[0,0,0]),{x:this._camPos[0],y:this._camPos[1],z:this._camPos[2]}},SceneJS.RenderContext.prototype.getProjPos=function(a){return this.getViewPos(a),this._pc=SceneJS_math_transformPoint3(this._frameCtx.cameraMat,this._vc),{x:this._pc[0],y:this._pc[1],z:this._pc[2],w:this._pc[3]}},SceneJS.RenderContext.prototype.getViewPos=function(a){return this.getWorldPos(a),this._vc=SceneJS_math_transformPoint3(this._frameCtx.viewMat,this._wc),{x:this._vc[0],y:this._vc[1],z:this._vc[2],w:this._vc[3]}},SceneJS.RenderContext.prototype.getWorldPos=function(a){return this._wc=SceneJS_math_transformPoint3(this._frameCtx.modelMat,a||[0,0,0]),{x:this._wc[0],y:this._wc[1],z:this._wc[2],w:this._wc[3]}};var SceneJS_Chunk=function(){};SceneJS_Chunk.prototype.init=function(a,b,c,d){this.id=a,this.program=b,this.core=c,this.core2=d,this.build&&this.build()};var SceneJS_ChunkFactory=function(){this._chunks={},this.chunkTypes=SceneJS_ChunkFactory.chunkTypes};SceneJS_ChunkFactory.chunkTypes={},SceneJS_ChunkFactory._freeChunks={},SceneJS_ChunkFactory.createChunkType=function(a){if(!a.type)throw"'type' expected in params";var b=SceneJS_Chunk,c=function(){this.useCount=0,this.init.apply(this,arguments)};return c.prototype=new b,c.prototype.constructor=c,a.drawAndPick&&(a.draw=a.pick=a.drawAndPick),SceneJS_ChunkFactory.chunkTypes[a.type]=c,SceneJS._apply(a,c.prototype),SceneJS_ChunkFactory._freeChunks[a.type]={chunks:[],chunksLen:0},c},SceneJS_ChunkFactory.prototype.getChunk=function(a,b,c,d,e){var f=SceneJS_ChunkFactory.chunkTypes[b];if(!f)throw"chunk type not supported: '"+b+"'";var g=this._chunks[a];if(g)return g.useCount++,g;var h=SceneJS_ChunkFactory._freeChunks[b];return h.chunksLen>0&&(g=h.chunks[--h.chunksLen]),g?g.init(a,c,d,e):g=new f(a,c,d,e),g.type=b,g.useCount=1,this._chunks[a]=g,g},SceneJS_ChunkFactory.prototype.putChunk=function(a){if(0!=a.useCount&&--a.useCount<=0){a.recycle&&a.recycle(),delete this._chunks[a.id];var b=SceneJS_ChunkFactory._freeChunks[a.type];b.chunks[b.chunksLen++]=a}},SceneJS_ChunkFactory.prototype.webglRestored=function(){var a;for(var b in this._chunks)this._chunks.hasOwnProperty(b)&&(a=this._chunks[b],a&&a.build&&a.build())},SceneJS_ChunkFactory.createChunkType({type:"camera",build:function(){this._uPMatrixDraw=this.program.draw.getUniform("SCENEJS_uPMatrix"),this._uZNearDraw=this.program.draw.getUniform("SCENEJS_uZNear"),this._uZFarDraw=this.program.draw.getUniform("SCENEJS_uZFar"),this._uPMatrixPick=this.program.pick.getUniform("SCENEJS_uPMatrix"),this._uZNearPick=this.program.pick.getUniform("SCENEJS_uZNear"),this._uZFarPick=this.program.pick.getUniform("SCENEJS_uZFar")},draw:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixDraw&&this._uPMatrixDraw.setValue(this.core.mat),this._uZNearDraw&&this._uZNearDraw.setValue(this.core.optics.near),this._uZFarDraw&&this._uZFarDraw.setValue(this.core.optics.far),a.cameraMat=this.core.mat},pick:function(a){this.core.checkAspect&&this.core.checkAspect(this.core,a.aspect);this.program.gl;this._uPMatrixPick&&this._uPMatrixPick.setValue(this.core.mat),a.rayPick&&(this._uZNearPick&&this._uZNearPick.setValue(this.core.optics.near),this._uZFarPick&&this._uZFarPick.setValue(this.core.optics.far)),a.cameraMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"clips",build:function(){this._draw=this._draw||[];for(var a=this.program.draw,b=0,c=this.core.clips.length;c>b;b++)this._draw[b]={uClipMode:a.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:a.getUniform("SCENEJS_uClipNormalAndDist"+b)};this._pick=this._pick||[];for(var d=this.program.pick,b=0,c=this.core.clips.length;c>b;b++)this._pick[b]={uClipMode:d.getUniform("SCENEJS_uClipMode"+b),uClipNormalAndDist:d.getUniform("SCENEJS_uClipNormalAndDist"+b)}},drawAndPick:function(a){for(var b,c,d,e=a.pick?this._pick:this._draw,f=this.core.clips,g=(this.program.gl,0),h=f.length;h>g;g++)a.pick?(b=e[g].uClipMode,c=e[g].uClipNormalAndDist):(b=e[g].uClipMode,c=e[g].uClipNormalAndDist),b&&c&&(d=f[g],"inside"==d.mode?(b.setValue(2),c.setValue(d.normalAndDist)):"outside"==d.mode?(b.setValue(1),c.setValue(d.normalAndDist)):b.setValue(0))}}),SceneJS_ChunkFactory.createChunkType({type:"draw",unique:!0,build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode")},drawAndPick:function(a){var b=this.program.gl,c=this.program.UINT_INDEX_ENABLED?b.UNSIGNED_INT:b.UNSIGNED_SHORT;a.pick?this._depthModePick&&this._depthModePick.setValue(a.depthMode):this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),b.drawElements(this.core.primitive,this.core.indexBuf.numItems,c,0)}}),SceneJS_ChunkFactory.createChunkType({type:"flags",build:function(){var a=this.program.draw;this._uClippingDraw=a.getUniform("SCENEJS_uClipping"),this._uSolidDraw=a.getUniform("SCENEJS_uSolid");var b=this.program.pick;this._uClippingPick=b.getUniform("SCENEJS_uClipping")},drawAndPick:function(a){var b=this.program.gl,c=this.core.backfaces;a.backfaces!=c&&(c?b.disable(b.CULL_FACE):b.enable(b.CULL_FACE),a.backfaces=c);var d=this.core.frontface;a.frontface!=d&&("ccw"==d?b.frontFace(b.CCW):b.frontFace(b.CW),a.frontface=d);var e=this.core.transparent;a.transparent!=e&&(a.pick||(e?(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA),a.blendEnabled=!0):(b.disable(b.BLEND),a.blendEnabled=!1)),a.transparent=e),a.pick?this._uClippingPick&&this._uClippingPick.setValue(this.core.clipping):(this._uClippingDraw&&this._uClippingDraw.setValue(this.core.clipping),this._uSolidDraw&&this._uSolidDraw.setValue(this.core.solid))}}),SceneJS_ChunkFactory.createChunkType({type:"renderTarget",programGlobal:!0,draw:function(a){var b=this.program.gl;a.renderBuf&&(b.flush(),a.renderBuf.unbind(),a.renderBuf=null);var c=this.core.renderBuf;return c?(c.bind(),a.depthMode="depth"===this.core.bufType,a.depthMode||a.blendEnabled&&(b.enable(b.BLEND),b.blendFunc(b.SRC_ALPHA,b.ONE_MINUS_SRC_ALPHA)),b.viewport(0,0,b.drawingBufferWidth,b.drawingBufferHeight),b.clearColor(a.ambientColor[0],a.ambientColor[1],a.ambientColor[2],1),b.clear(b.COLOR_BUFFER_BIT|b.DEPTH_BUFFER_BIT|b.STENCIL_BUFFER_BIT),void(a.renderBuf=c)):void(a.depthMode=!1)}}),SceneJS_ChunkFactory.createChunkType({type:"geometry",build:function(){var a=this.program.draw;this._aVertexDraw=a.getAttribute("SCENEJS_aVertex"),this._aNormalDraw=a.getAttribute("SCENEJS_aNormal"),this._aUVDraw=a.getAttribute("SCENEJS_aUVCoord"),this._aUV2Draw=a.getAttribute("SCENEJS_aUVCoord2"),this._aTangentDraw=a.getAttribute("SCENEJS_aTangent"),this._aColorDraw=a.getAttribute("SCENEJS_aVertexColor"),this._aMorphVertexDraw=a.getAttribute("SCENEJS_aMorphVertex"),this._aMorphNormalDraw=a.getAttribute("SCENEJS_aMorphNormal"),this._uMorphFactorDraw=a.getUniform("SCENEJS_uMorphFactor");var b=this.program.pick;this._aVertexPick=b.getAttribute("SCENEJS_aVertex"),this._aMorphVertexPick=b.getAttribute("SCENEJS_aMorphVertex"),this._uMorphFactorPick=b.getUniform("SCENEJS_uMorphFactor"),this.VAO=null,this.VAOMorphKey1=0,this.VAOMorphKey2=0,this.VAOHasInterleavedBuf=!1},recycle:function(){if(this.VAO){var a=this.program.gl.getExtension("OES_vertex_array_object");a.deleteVertexArrayOES(this.VAO),this.VAO=null}},morphDraw:function(){this.VAOMorphKey1=this.core.key1,this.VAOMorphKey2=this.core.key2;var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexDraw?(this._aVertexDraw.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexDraw.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aMorphNormalDraw?(this._aNormalDraw.bindFloatArrayBuffer(a.normalBuf),this._aMorphNormalDraw.bindFloatArrayBuffer(b.normalBuf)):this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this.setDrawMorphFactor()},setDrawMorphFactor:function(){this._uMorphFactorDraw&&this._uMorphFactorDraw.setValue*this.core.factor},draw:function(a){var b=this.core.targets&&this.core.targets.length,c=this.core2.interleavedBuf&&!this.core2.interleavedBuf.dirty;if(this.VAO){if(a.VAO.bindVertexArrayOES(this.VAO),b){if(this.VAOMorphKey1==this.core.key1&&this.VAOMorphKey2==this.core.key2)return void this.setDrawMorphFactor()}else if(c||!this.VAOHasInterleavedBuf)return}else if(a.VAO){a.VAO.bindVertexArrayOES(null),this.VAO=a.VAO.createVertexArrayOES(),a.VAO.bindVertexArrayOES(this.VAO);this.program.gl}b?this.morphDraw():c?(this.VAOHasInterleavedBuf=!0,this.core2.interleavedBuf.bind(),this._aVertexDraw&&this._aVertexDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedPositionOffset),this._aNormalDraw&&this._aNormalDraw.bindInterleavedFloatArrayBuffer(3,this.core2.interleavedStride,this.core2.interleavedNormalOffset),this._aUVDraw&&this._aUVDraw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUVOffset),this._aUV2Draw&&this._aUV2Draw.bindInterleavedFloatArrayBuffer(2,this.core2.interleavedStride,this.core2.interleavedUV2Offset),this._aColorDraw&&this._aColorDraw.bindInterleavedFloatArrayBuffer(4,this.core2.interleavedStride,this.core2.interleavedColorOffset),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())):(this.VAOHasInterleavedBuf=!1,this._aVertexDraw&&this._aVertexDraw.bindFloatArrayBuffer(this.core2.vertexBuf),this._aNormalDraw&&this._aNormalDraw.bindFloatArrayBuffer(this.core2.normalBuf),this._aUVDraw&&this._aUVDraw.bindFloatArrayBuffer(this.core2.uvBuf),this._aUV2Draw&&this._aUV2Draw.bindFloatArrayBuffer(this.core2.uvBuf2),this._aColorDraw&&this._aColorDraw.bindFloatArrayBuffer(this.core2.colorBuf),this._aTangentDraw&&this._aTangentDraw.bindFloatArrayBuffer(this.core2.tangentBuf||this.core2.getTangentBuf())),this.core2.indexBuf.bind()},morphPick:function(){var a=this.core.targets[this.core.key1],b=this.core.targets[this.core.key2];this._aMorphVertexPick?(this._aVertexPick.bindFloatArrayBuffer(a.vertexBuf),this._aMorphVertexPick.bindFloatArrayBuffer(b.vertexBuf)):this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this._uMorphFactorPick&&this._uMorphFactorPick.setValue(this.core.factor)},pick:function(a){this.core.targets&&this.core.targets.length?this.morphPick():this._aVertexPick&&this._aVertexPick.bindFloatArrayBuffer(this.core2.vertexBuf),this.core2.indexBuf.bind()}}),SceneJS_ChunkFactory.createChunkType({type:"lights",build:function(){this._uAmbientColor=this._uAmbientColor||[],this._uLightColor=this._uLightColor||[],this._uLightDir=this._uLightDir||[],this._uLightPos=this._uLightPos||[],this._uLightCutOff=this._uLightCutOff||[],this._uLightSpotExp=this._uLightSpotExp||[],this._uLightAttenuation=this._uLightAttenuation||[];for(var a=this.core.lights,b=this.program,c=0,d=a.length;d>c;c++)switch(a[c].mode){case"ambient":this._uAmbientColor[c]=b.draw.getUniform("SCENEJS_uAmbientColor");break;case"dir":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=null,this._uLightDir[c]=b.draw.getUniform("SCENEJS_uLightDir"+c);break;case"point":this._uLightColor[c]=b.draw.getUniform("SCENEJS_uLightColor"+c),this._uLightPos[c]=b.draw.getUniform("SCENEJS_uLightPos"+c),this._uLightDir[c]=null,this._uLightAttenuation[c]=b.draw.getUniform("SCENEJS_uLightAttenuation"+c)}},draw:function(a){a.dirty&&this.build();for(var b,c=this.core.lights,d=(this.program.gl,0),e=c.length;e>d;d++)b=c[d],this._uAmbientColor[d]?this._uAmbientColor[d].setValue(b.color):(this._uLightColor[d]&&this._uLightColor[d].setValue(b.color),this._uLightPos[d]&&(this._uLightPos[d].setValue(b.pos),this._uLightAttenuation[d]&&this._uLightAttenuation[d].setValue(b.attenuation)),this._uLightDir[d]&&this._uLightDir[d].setValue(b.dir))}}),SceneJS_ChunkFactory.createChunkType({type:"listeners",programGlobal:!0,build:function(){},draw:function(a){for(var b=this.core.listeners,c=a.renderListenerCtx,d=b.length-1;d>=0;d--)if(b[d](c)===!0)return!0}}),SceneJS_ChunkFactory.createChunkType({type:"lookAt",build:function(){this._uvMatrixDraw=this.program.draw.getUniform("SCENEJS_uVMatrix"),this._uVNMatrixDraw=this.program.draw.getUniform("SCENEJS_uVNMatrix"),this._uWorldEyeDraw=this.program.draw.getUniform("SCENEJS_uWorldEye"),this._uvMatrixPick=this.program.pick.getUniform("SCENEJS_uVMatrix")},draw:function(a){this.core.dirty&&this.core.rebuild();this.program.gl;this._uvMatrixDraw&&this._uvMatrixDraw.setValue(this.core.mat),this._uVNMatrixDraw&&this._uVNMatrixDraw.setValue(this.core.normalMat),this._uWorldEyeDraw&&this._uWorldEyeDraw.setValue(this.core.lookAt.eye),a.viewMat=this.core.mat},pick:function(a){this.program.gl;this._uvMatrixPick&&this._uvMatrixPick.setValue(this.core.mat),a.viewMat=this.core.mat}}),SceneJS_ChunkFactory.createChunkType({type:"material",build:function(){var a=this.program.draw;this._uMaterialBaseColor=a.getUniform("SCENEJS_uMaterialColor"),this._uMaterialSpecularColor=a.getUniform("SCENEJS_uMaterialSpecularColor"),this._uMaterialSpecular=a.getUniform("SCENEJS_uMaterialSpecular"),this._uMaterialShine=a.getUniform("SCENEJS_uMaterialShine"),this._uMaterialEmit=a.getUniform("SCENEJS_uMaterialEmit"),this._uMaterialAlpha=a.getUniform("SCENEJS_uMaterialAlpha")},draw:function(){this.program.gl;this._uMaterialBaseColor&&this._uMaterialBaseColor.setValue(this.core.baseColor),this._uMaterialSpecularColor&&this._uMaterialSpecularColor.setValue(this.core.specularColor),this._uMaterialSpecular&&this._uMaterialSpecular.setValue(this.core.specular),this._uMaterialShine&&this._uMaterialShine.setValue(this.core.shine),this._uMaterialEmit&&this._uMaterialEmit.setValue(this.core.emit),this._uMaterialAlpha&&this._uMaterialAlpha.setValue(this.core.alpha)}}),SceneJS_ChunkFactory.createChunkType({type:"name",build:function(){this._uPickColor=this.program.pick.getUniform("SCENEJS_uPickColor")},pick:function(a){if(this._uPickColor&&this.core.name){a.pickNames[a.pickIndex++]=this.core;var b=a.pickIndex>>16&255,c=a.pickIndex>>8&255,d=255&a.pickIndex;this._uPickColor.setValue([d/255,c/255,b/255])}}}),SceneJS_ChunkFactory.createChunkType({type:"program",build:function(){this._depthModeDraw=this.program.draw.getUniform("SCENEJS_uDepthMode"),this._depthModePick=this.program.pick.getUniform("SCENEJS_uDepthMode"),this._rayPickMode=this.program.pick.getUniform("SCENEJS_uRayPickMode")},draw:function(a){var b=this.program.draw;b.bind(),a.textureUnit=0;var c=this.program.gl;if(this._depthModeDraw&&this._depthModeDraw.setValue(a.depthMode),!a.VAO)for(var d=0;10>d;d++)c.disableVertexAttribArray(d);a.drawProgram=this.program.draw},pick:function(a){var b=this.program.pick;b.bind();var c=this.program.gl;this._rayPickMode&&this._rayPickMode.setValue(a.rayPick),this._depthModePick&&this._depthModePick.setValue(a.depthMode),a.textureUnit=0;for(var d=0;10>d;d++)c.disableVertexAttribArray(d)}}),SceneJS_ChunkFactory.createChunkType({type:"renderer",build:function(){},drawAndPick:function(a){if(this.core.props){var b=this.program.gl;a.renderer&&(a.renderer.props.restoreProps(b),a.renderer=this.core),this.core.props.setProps(b)}}}),SceneJS_ChunkFactory.createChunkType({type:"depthBuffer",programGlobal:!0,drawAndPick:function(a){var b=this.program.gl,c=this.core.enabled;a.depthbufEnabled!=c&&(c?b.enable(b.DEPTH_TEST):b.disable(b.DEPTH_TEST),a.depthbufEnabled=c);var d=this.core.clearDepth;a.clearDepth!=d&&(b.clearDepth(d),a.clearDepth=d);var e=this.core.depthFunc;a.depthFunc!=e&&(b.depthFunc(e),a.depthFunc=e),this.core.clear&&b.clear(b.DEPTH_BUFFER_BIT)}}),SceneJS_ChunkFactory.createChunkType({type:"colorBuffer",programGlobal:!0,build:function(){},drawAndPick:function(a){if(!a.transparent){var b=this.core.blendEnabled,c=this.program.gl;a.blendEnabled!=b&&(b?c.enable(c.BLEND):c.disable(c.BLEND),a.blendEnabled=b);var d=this.core.colorMask;c.colorMask(d.r,d.g,d.b,d.a)}}}),SceneJS_ChunkFactory.createChunkType({type:"view",programGlobal:!0,build:function(){},drawAndPick:function(a){var b=this.core.scissorTestEnabled;if(a.scissorTestEnabled!=b){var c=this.program.gl;b?c.enable(c.SCISSOR_TEST):c.disable(c.SCISSOR_TEST),a.scissorTestEnabled=b}}}),SceneJS_ChunkFactory.createChunkType({type:"shader",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"shaderParams",build:function(){},drawAndPick:function(a){var b=this.core.paramsStack;if(b)for(var c,d,e=a.pick?this.program.pick:this.program.draw,f=0,g=b.length;g>f;f++){c=b[f];for(d in c)c.hasOwnProperty(d)&&e.setUniform(d,c[d])}}}),SceneJS_ChunkFactory.createChunkType({type:"style",programGlobal:!0,drawAndPick:function(a){var b=this.core.lineWidth;if(a.lineWidth!=b){var c=this.program.gl;c.lineWidth(b),a.lineWidth=b}}}),SceneJS_ChunkFactory.createChunkType({type:"texture",build:function(){this._uTexSampler=this._uTexSampler||[],this._uTexMatrix=this._uTexMatrix||[],this._uTexBlendFactor=this._uTexBlendFactor||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uTexSampler[d]="SCENEJS_uSampler"+d,this._uTexMatrix[d]=c.getUniform("SCENEJS_uLayer"+d+"Matrix"),this._uTexBlendFactor[d]=c.getUniform("SCENEJS_uLayer"+d+"BlendFactor")},draw:function(a){a.textureUnit=0;var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uTexSampler[e]&&c.texture&&(d.bindTexture(this._uTexSampler[e],c.texture,a.textureUnit++),c._matrixDirty&&c.buildMatrix&&c.buildMatrix.call(c),this._uTexMatrix[e]&&this._uTexMatrix[e].setValue(c.matrixAsArray),this._uTexBlendFactor[e]&&this._uTexBlendFactor[e].setValue(c.blendFactor));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"cubemap",build:function(){this._uCubeMapSampler=this._uCubeMapSampler||[],this._uCubeMapIntensity=this._uCubeMapIntensity||[];var a=this.core.layers;if(a)for(var b,c=this.program.draw,d=0,e=a.length;e>d;d++)b=a[d],this._uCubeMapSampler[d]="SCENEJS_uCubeMapSampler"+d,this._uCubeMapIntensity[d]=c.getUniform("SCENEJS_uCubeMapIntensity"+d)},draw:function(a){var b=this.core.layers;if(b)for(var c,d=this.program.draw,e=0,f=b.length;f>e;e++)c=b[e],this._uCubeMapSampler[e]&&c.texture&&(d.bindTexture(this._uCubeMapSampler[e],c.texture,a.textureUnit++),this._uCubeMapIntensity[e]&&this._uCubeMapIntensity[e].setValue(c.intensity));a.textureUnit>10&&(a.textureUnit=0)}}),SceneJS_ChunkFactory.createChunkType({type:"xform",build:function(){var a=this.program.draw;this._uMatLocationDraw=a.getUniform("SCENEJS_uMMatrix"),this._uNormalMatLocationDraw=a.getUniform("SCENEJS_uMNMatrix");var b=this.program.pick;this._uMatLocationPick=b.getUniform("SCENEJS_uMMatrix")},draw:function(a){(SceneJS_configsModule.configs.forceXFormCoreRebuild===!0||this.core.dirty&&this.core.build)&&this.core.build();this.program.gl;this._uMatLocationDraw&&this._uMatLocationDraw.setValue(this.core.mat),this._uNormalMatLocationDraw&&this._uNormalMatLocationDraw.setValue(this.core.normalMat),a.modelMat=this.core.mat},pick:function(a){this.core.dirty&&this.core.build();this.program.gl;this._uMatLocationPick&&this._uMatLocationPick.setValue(this.core.mat),a.modelMat=this.core.mat}}); \ No newline at end of file From 55b9c59d35ea635c00e954373211114323b1e3bd Mon Sep 17 00:00:00 2001 From: xeolabs Date: Thu, 11 Jun 2015 11:55:06 +0200 Subject: [PATCH 14/14] Added meter to examples --- examples/benchmarks_10000boxes.html | 37 +++++++++++----------------- examples/benchmarks_400000boxes.html | 19 +++++++++++++- examples/benchmarks_40000boxes.html | 23 ++++++++++------- examples/benchmarks_5000boxes.html | 26 +++++++++---------- 4 files changed, 59 insertions(+), 46 deletions(-) diff --git a/examples/benchmarks_10000boxes.html b/examples/benchmarks_10000boxes.html index 52879734..01f3a213 100644 --- a/examples/benchmarks_10000boxes.html +++ b/examples/benchmarks_10000boxes.html @@ -21,6 +21,11 @@ + +
+ 10000 boxes with unique materials +
+ diff --git a/examples/benchmarks_40000boxes.html b/examples/benchmarks_40000boxes.html index 5bcc4b03..e2dad017 100644 --- a/examples/benchmarks_40000boxes.html +++ b/examples/benchmarks_40000boxes.html @@ -21,6 +21,11 @@ + +
+ 40000 boxes with unique materials +
+