소스 검색

Merge branch 'master' into WinJSApplication

Nicolas Obré 11 년 전
부모
커밋
e24e655698
35개의 변경된 파일1462개의 추가작업 그리고 147개의 파일을 삭제
  1. 4 1
      Babylon/Cameras/babylon.camera.js
  2. 30 1
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  3. 10 0
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  4. 21 7
      Babylon/Materials/babylon.effect.js
  5. 16 4
      Babylon/Materials/babylon.material.js
  6. 14 5
      Babylon/Materials/babylon.shaderMaterial.js
  7. 31 18
      Babylon/Materials/babylon.standardMaterial.js
  8. 4 3
      Babylon/Materials/textures/babylon.renderTargetTexture.js
  9. 32 54
      Babylon/Mesh/babylon.mesh.js
  10. 233 2
      Babylon/Mesh/babylon.mesh.vertexData.js
  11. 6 4
      Babylon/Mesh/babylon.vertexBuffer.js
  12. 1 1
      Babylon/Particles/babylon.particleSystem.js
  13. 239 0
      Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.js
  14. 50 0
      Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPass.js
  15. 138 0
      Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.js
  16. 81 0
      Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.js
  17. 11 0
      Babylon/PostProcess/babylon.displayPassPostProcess.js
  18. 84 0
      Babylon/Rendering/babylon.boundingBoxRenderer.js
  19. 7 0
      Babylon/Shaders/color.fragment.fx
  20. 11 0
      Babylon/Shaders/color.vertex.fx
  21. 11 7
      Babylon/Shaders/default.fragment.fx
  22. 13 0
      Babylon/Shaders/displayPass.fragment.fx
  23. 135 0
      Babylon/Tools/babylon.andOrNotEvaluator.js
  24. 5 0
      Babylon/Tools/babylon.sceneSerializer.js
  25. 101 0
      Babylon/Tools/babylon.tags.js
  26. 14 0
      Babylon/Tools/babylon.tools.js
  27. 36 5
      Babylon/babylon.engine.js
  28. 1 1
      Babylon/babylon.node.js
  29. 65 9
      Babylon/babylon.scene.js
  30. 8 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml
  31. 1 1
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/ourOwnBabylon.js
  32. 0 24
      babylon.1.10.0.js
  33. 28 0
      babylon.1.11.js
  34. 1 0
      readme.md
  35. 20 0
      what's new.md

+ 4 - 1
Babylon/Cameras/babylon.camera.js

@@ -289,16 +289,19 @@ var BABYLON = BABYLON || {};
 
         this._computedViewMatrix.invert();
 
+        this._currentRenderId = this._scene.getRenderId();
         return this._computedViewMatrix;
     };
     
     BABYLON.Camera.prototype._computeViewMatrix = function (force) {
         if (!force && this._isSynchronizedViewMatrix()) {
-            this._currentRenderId = this._scene.getRenderId();
             return this._computedViewMatrix;
         }
 
         this._computedViewMatrix = this._getViewMatrix();
+        if (!this.parent || !this.parent.getWorldMatrix) {
+            this._currentRenderId = this._scene.getRenderId();
+        }
         return this._computedViewMatrix;
     };
 

+ 30 - 1
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -14,6 +14,12 @@ var BABYLON = BABYLON || {};
         this._shadowMap.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.renderParticles = false;
+
+        // Darkness
+        this._darkness = 0.;
+
+        // Darkness
+        this._transparencyShadow = false;        
                 
         // Custom render function
         var that = this;
@@ -42,7 +48,7 @@ var BABYLON = BABYLON || {};
             }
         };
 
-        this._shadowMap.customRenderFunction = function (opaqueSubMeshes, alphaTestSubMeshes) {
+        this._shadowMap.customRenderFunction = function (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes) {
             var index;
             
             for (index = 0; index < opaqueSubMeshes.length; index++) {
@@ -52,6 +58,12 @@ var BABYLON = BABYLON || {};
             for (index = 0; index < alphaTestSubMeshes.length; index++) {
                 renderSubMesh(alphaTestSubMeshes.data[index]);
             }
+
+            if (that._transparencyShadow) {
+                for (index = 0; index < transparentSubMeshes.length; index++) {
+                    renderSubMesh(transparentSubMeshes.data[index]);
+                }                
+            }
         };
         
         // Internals
@@ -126,6 +138,23 @@ var BABYLON = BABYLON || {};
         return this._transformMatrix;
     };
 
+    BABYLON.ShadowGenerator.prototype.getDarkness = function () {
+        return this._darkness;
+    };
+
+    BABYLON.ShadowGenerator.prototype.setDarkness = function (darkness) {
+        if (darkness >= 1.0)
+            this._darkness = 1.0;
+        else if (darkness <= 0.0)   
+            this._darkness = 0.0;
+        else
+            this._darkness = darkness;
+    };
+
+    BABYLON.ShadowGenerator.prototype.setTransparencyShadow = function (hasShadow) {
+        this._transparencyShadow = hasShadow;
+    };
+
     BABYLON.ShadowGenerator.prototype.dispose = function() {
         this._shadowMap.dispose();
     };

+ 10 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -99,6 +99,8 @@ var BABYLON = BABYLON || {};
         material.alpha = parsedMaterial.alpha;
 
         material.id = parsedMaterial.id;
+
+        BABYLON.Tags.AddTagsTo(material, parsedMaterial.tags);
         material.backFaceCulling = parsedMaterial.backFaceCulling;
 
         if (parsedMaterial.diffuseTexture) {
@@ -148,6 +150,8 @@ var BABYLON = BABYLON || {};
 
         multiMaterial.id = parsedMultiMaterial.id;
 
+        BABYLON.Tags.AddTagsTo(multiMaterial, parsedMultiMaterial.tags);
+
         for (var matIndex = 0; matIndex < parsedMultiMaterial.materials.length; matIndex++) {
             var subMatId = parsedMultiMaterial.materials[matIndex];
 
@@ -282,6 +286,8 @@ var BABYLON = BABYLON || {};
 
         light.id = parsedLight.id;
 
+        BABYLON.Tags.AddTagsTo(light, parsedLight.tags);
+
         if (parsedLight.intensity) {
             light.intensity = parsedLight.intensity;
         }
@@ -293,6 +299,8 @@ var BABYLON = BABYLON || {};
         var camera = new BABYLON.FreeCamera(parsedCamera.name, BABYLON.Vector3.FromArray(parsedCamera.position), scene);
         camera.id = parsedCamera.id;
 
+        BABYLON.Tags.AddTagsTo(camera, parsedCamera.tags);
+
         // Parent
         if (parsedCamera.parentId) {
             camera._waitingParentId = parsedCamera.parentId;
@@ -343,6 +351,8 @@ var BABYLON = BABYLON || {};
         var mesh = new BABYLON.Mesh(parsedMesh.name, scene);
         mesh.id = parsedMesh.id;
 
+        BABYLON.Tags.AddTagsTo(mesh, parsedMesh.tags);
+
         mesh.position = BABYLON.Vector3.FromArray(parsedMesh.position);
         if (parsedMesh.rotation) {
             mesh.rotation = BABYLON.Vector3.FromArray(parsedMesh.rotation);

+ 21 - 7
Babylon/Materials/babylon.effect.js

@@ -4,7 +4,7 @@ var BABYLON = BABYLON || {};
 
 (function () {
 
-    BABYLON.Effect = function (baseName, attributesNames, uniformsNames, samplers, engine, defines, optionalDefines) {
+    BABYLON.Effect = function (baseName, attributesNames, uniformsNames, samplers, engine, defines, optionalDefines, onCompiled, onError) {
         this._engine = engine;
         this.name = baseName;
         this.defines = defines;
@@ -14,6 +14,9 @@ var BABYLON = BABYLON || {};
         this._compilationError = "";
         this._attributesNames = attributesNames;
 
+        this.onError = onError;
+        this.onCompiled = onCompiled;
+
         var vertexSource;
         var fragmentSource;
 
@@ -30,12 +33,16 @@ var BABYLON = BABYLON || {};
             that._loadFragmentShader(fragmentSource, function (fragmentCode) {
                 that._prepareEffect(vertexCode, fragmentCode, attributesNames, defines, optionalDefines);
             });
-        });   
+        });
 
         // Cache
         this._valueCache = [];
     };
 
+    // Events
+    BABYLON.Effect.prototype.onCompiled = null;
+    BABYLON.Effect.prototype.onError = null;
+
     // Properties
     BABYLON.Effect.prototype.isReady = function () {
         return this._isReady;
@@ -87,7 +94,7 @@ var BABYLON = BABYLON || {};
             callback(BABYLON.Effect.ShadersStore[vertex + "VertexShader"]);
             return;
         }
-        
+
         var vertexShaderUrl;
 
         if (vertex[0] === ".") {
@@ -113,7 +120,7 @@ var BABYLON = BABYLON || {};
             callback(BABYLON.Effect.ShadersStore[fragment + "PixelShader"]);
             return;
         }
-        
+
         var fragmentShaderUrl;
 
         if (fragment[0] === ".") {
@@ -146,6 +153,9 @@ var BABYLON = BABYLON || {};
             engine.bindSamplers(this);
 
             this._isReady = true;
+            if (this.onCompiled) {
+                this.onCompiled(this);
+            }
         } catch (e) {
             if (!useFallback && optionalDefines) {
                 for (var index = 0; index < optionalDefines.length; index++) {
@@ -157,6 +167,10 @@ var BABYLON = BABYLON || {};
                 console.error("Defines: " + defines);
                 console.error("Optional defines: " + optionalDefines);
                 this._compilationError = e.message;
+
+                if (this.onError) {
+                    this.onError(this, this._compilationError);
+                }
             }
         }
     };
@@ -215,7 +229,7 @@ var BABYLON = BABYLON || {};
         this._valueCache[uniformName][2] = z;
         this._valueCache[uniformName][3] = w;
     };
-    
+
     BABYLON.Effect.prototype.setArray = function (uniformName, array) {
         this._engine.setArray(this.getUniform(uniformName), array);
 
@@ -259,7 +273,7 @@ var BABYLON = BABYLON || {};
 
         return this;
     };
-    
+
     BABYLON.Effect.prototype.setVector2 = function (uniformName, vector2) {
         if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == vector2.x && this._valueCache[uniformName][1] == vector2.y)
             return this;
@@ -279,7 +293,7 @@ var BABYLON = BABYLON || {};
 
         return this;
     };
-    
+
     BABYLON.Effect.prototype.setVector3 = function (uniformName, vector3) {
         if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == vector3.x && this._valueCache[uniformName][1] == vector3.y && this._valueCache[uniformName][2] == vector3.z)
             return this;

+ 16 - 4
Babylon/Materials/babylon.material.js

@@ -20,8 +20,11 @@ var BABYLON = BABYLON || {};
     BABYLON.Material.prototype._effect = null;
     BABYLON.Material.prototype._wasPreviouslyReady = false;
 
+    // Events
+    BABYLON.Effect.prototype.onCompiled = null;
+    BABYLON.Effect.prototype.onError = null;
     BABYLON.Material.prototype.onDispose = null;
-    
+
     // Properties
     BABYLON.Material.prototype.isReady = function (mesh) {
         return true;
@@ -40,6 +43,9 @@ var BABYLON = BABYLON || {};
     };
 
     // Methods   
+    BABYLON.Material.prototype.trackCreation = function (onCompiled, onError) {
+    };
+
     BABYLON.Material.prototype._preBind = function () {
         var engine = this._scene.getEngine();
         
@@ -53,18 +59,24 @@ var BABYLON = BABYLON || {};
     BABYLON.Material.prototype.unbind = function () {
     };
     
-    BABYLON.Material.prototype.baseDispose = function () {
+    BABYLON.Material.prototype.baseDispose = function (forceDisposeEffect) {
         // Remove from scene
         var index = this._scene.materials.indexOf(this);
         this._scene.materials.splice(index, 1);
 
+        // Shader are kept in cache for further use but we can get rid of this by using forceDisposeEffect
+        if (forceDisposeEffect && this._effect) {
+            this._scene.getEngine()._releaseEffect(this._effect);
+            this._effect = null;
+        }
+
         // Callback
         if (this.onDispose) {
             this.onDispose();
         }
     };
 
-    BABYLON.Material.prototype.dispose = function () {
-        this.baseDispose();
+    BABYLON.Material.prototype.dispose = function (forceDisposeEffect) {
+        this.baseDispose(forceDisposeEffect);
     };
 })();

+ 14 - 5
Babylon/Materials/babylon.shaderMaterial.js

@@ -27,6 +27,8 @@ var BABYLON = BABYLON || {};
         this._vectors3 = [];
         this._vectors4 = [];
         this._matrices = [];
+
+        this._cachedWorldViewMatrix = new BABYLON.Matrix();
     };
 
     BABYLON.ShaderMaterial.prototype = Object.create(BABYLON.Material.prototype);
@@ -48,7 +50,9 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.ShaderMaterial.prototype.setTexture = function (name, texture) {
-        this._checkUniform(name);
+        if (this._options.samplers.indexOf(name) === -1) {
+            this._options.samplers.push(name);
+        }
         this._textures[name] = texture;
 
         return this;
@@ -116,8 +120,8 @@ var BABYLON = BABYLON || {};
         this._effect = engine.createEffect(this._shaderPath,
             this._options.attributes,
             this._options.uniforms,
-            this._options.samplers,
-            "");
+            this._options.samplers,            
+            "", null, this.onCompiled, this.onError);
 
         if (!this._effect.isReady()) {
             return false;
@@ -136,6 +140,11 @@ var BABYLON = BABYLON || {};
             this._effect.setMatrix("view", this._scene.getViewMatrix());
         }
 
+        if (this._options.uniforms.indexOf("worldView") !== -1) {
+            world.multiplyToRef(this._scene.getViewMatrix(), this._cachedWorldViewMatrix);
+            this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
+        }
+
         if (this._options.uniforms.indexOf("projection") !== -1) {
             this._effect.setMatrix("projection", this._scene.getProjectionMatrix());
         }
@@ -190,13 +199,13 @@ var BABYLON = BABYLON || {};
         }
     };
 
-    BABYLON.ShaderMaterial.prototype.dispose = function () {
+    BABYLON.ShaderMaterial.prototype.dispose = function (forceDisposeEffect) {
         for (var name in this._textures) {
             this._textures[name].dispose();
         }
 
         this._textures = [];
         
-        this.baseDispose();
+        this.baseDispose(forceDisposeEffect);
     };
 })();

+ 31 - 18
Babylon/Materials/babylon.standardMaterial.js

@@ -64,7 +64,7 @@ var BABYLON = BABYLON || {};
 
         // Textures
         if (this._scene.texturesEnabled) {
-            if (this.diffuseTexture) {
+            if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
                 if (!this.diffuseTexture.isReady()) {
                     return false;
                 } else {
@@ -72,7 +72,7 @@ var BABYLON = BABYLON || {};
                 }
             }
 
-            if (this.ambientTexture) {
+            if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
                 if (!this.ambientTexture.isReady()) {
                     return false;
                 } else {
@@ -80,7 +80,7 @@ var BABYLON = BABYLON || {};
                 }
             }
 
-            if (this.opacityTexture) {
+            if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
                 if (!this.opacityTexture.isReady()) {
                     return false;
                 } else {
@@ -88,7 +88,7 @@ var BABYLON = BABYLON || {};
                 }
             }
 
-            if (this.reflectionTexture) {
+            if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
                 if (!this.reflectionTexture.isReady()) {
                     return false;
                 } else {
@@ -96,7 +96,7 @@ var BABYLON = BABYLON || {};
                 }
             }
 
-            if (this.emissiveTexture) {
+            if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
                 if (!this.emissiveTexture.isReady()) {
                     return false;
                 } else {
@@ -104,7 +104,7 @@ var BABYLON = BABYLON || {};
                 }
             }
 
-            if (this.specularTexture) {
+            if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
                 if (!this.specularTexture.isReady()) {
                     return false;
                 } else {
@@ -114,7 +114,7 @@ var BABYLON = BABYLON || {};
             }
         }
 
-        if (this._scene.getEngine().getCaps().standardDerivatives && this.bumpTexture) {
+        if (this._scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && BABYLON.StandardMaterial.BumpTextureEnabled) {
             if (!this.bumpTexture.isReady()) {
                 return false;
             } else {
@@ -245,11 +245,12 @@ var BABYLON = BABYLON || {};
                 "vFogInfos", "vFogColor",
                  "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos",
                  "mBones",
-                 "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix"],
+                 "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix",
+                 "darkness0", "darkness1", "darkness2", "darkness3"],
                 ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler",
                  "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3"
                 ],
-                join, optionalDefines);
+                join, optionalDefines, this.onCompiled, this.onError);
         }
         if (!this._effect.isReady()) {
             return false;
@@ -289,7 +290,7 @@ var BABYLON = BABYLON || {};
         }
 
         // Textures        
-        if (this.diffuseTexture) {
+        if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
             this._effect.setTexture("diffuseSampler", this.diffuseTexture);
 
             this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
@@ -298,21 +299,21 @@ var BABYLON = BABYLON || {};
             this._baseColor.copyFromFloats(1, 1, 1);
         }
 
-        if (this.ambientTexture) {
+        if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
             this._effect.setTexture("ambientSampler", this.ambientTexture);
 
             this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
             this._effect.setMatrix("ambientMatrix", this.ambientTexture._computeTextureMatrix());
         }
 
-        if (this.opacityTexture) {
+        if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
             this._effect.setTexture("opacitySampler", this.opacityTexture);
 
             this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
             this._effect.setMatrix("opacityMatrix", this.opacityTexture._computeTextureMatrix());
         }
 
-        if (this.reflectionTexture) {
+        if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
             if (this.reflectionTexture.isCube) {
                 this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
             } else {
@@ -323,21 +324,21 @@ var BABYLON = BABYLON || {};
             this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
         }
 
-        if (this.emissiveTexture) {
+        if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
             this._effect.setTexture("emissiveSampler", this.emissiveTexture);
 
             this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
             this._effect.setMatrix("emissiveMatrix", this.emissiveTexture._computeTextureMatrix());
         }
 
-        if (this.specularTexture) {
+        if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
             this._effect.setTexture("specularSampler", this.specularTexture);
 
             this._effect.setFloat2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
             this._effect.setMatrix("specularMatrix", this.specularTexture._computeTextureMatrix());
         }
 
-        if (this.bumpTexture && this._scene.getEngine().getCaps().standardDerivatives) {
+        if (this.bumpTexture && this._scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
             this._effect.setTexture("bumpSampler", this.bumpTexture);
 
             this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
@@ -391,6 +392,7 @@ var BABYLON = BABYLON || {};
                     world.multiplyToRef(shadowGenerator.getTransformMatrix(), this._lightMatrix);
                     this._effect.setMatrix("lightMatrix" + lightIndex, this._lightMatrix);
                     this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
+                    this._effect.setFloat("darkness" + lightIndex, shadowGenerator.getDarkness());
                 }
 
                 lightIndex++;
@@ -450,7 +452,7 @@ var BABYLON = BABYLON || {};
         return results;
     };
 
-    BABYLON.StandardMaterial.prototype.dispose = function () {
+    BABYLON.StandardMaterial.prototype.dispose = function (forceDisposeEffect) {
         if (this.diffuseTexture) {
             this.diffuseTexture.dispose();
         }
@@ -479,7 +481,7 @@ var BABYLON = BABYLON || {};
             this.bumpTexture.dispose();
         }
 
-        this.baseDispose();
+        this.baseDispose(forceDisposeEffect);
     };
 
     BABYLON.StandardMaterial.prototype.clone = function (name) {
@@ -523,4 +525,15 @@ var BABYLON = BABYLON || {};
         return newStandardMaterial;
     };
 
+    // Statics
+
+    // Flags used to enable or disable a type of texture for all Standard Materials
+    BABYLON.StandardMaterial.DiffuseTextureEnabled = true;
+    BABYLON.StandardMaterial.AmbientTextureEnabled = true;
+    BABYLON.StandardMaterial.OpacityTextureEnabled = true;
+    BABYLON.StandardMaterial.ReflectionTextureEnabled = true;
+    BABYLON.StandardMaterial.EmissiveTextureEnabled = true;
+    BABYLON.StandardMaterial.SpecularTextureEnabled = true;
+    BABYLON.StandardMaterial.BumpTextureEnabled = true;
+
 })();

+ 4 - 3
Babylon/Materials/textures/babylon.renderTargetTexture.js

@@ -86,12 +86,13 @@ var BABYLON = BABYLON || {};
         // Render
         this._renderingManager.render(this.customRenderFunction, this.renderList, this.renderParticles, this.renderSprites);
 
-        // Unbind
-        engine.unBindFramebuffer(this._texture);
-
+        //Call this before unBinding Framebuffer in case of manipulating texture with WebGL commands inside the onAfterRender method.
         if (this.onAfterRender) {
             this.onAfterRender();
         }
+
+        // Unbind
+        engine.unBindFramebuffer(this._texture);
     };
 
     BABYLON.RenderTargetTexture.prototype.clone = function () {

+ 32 - 54
Babylon/Mesh/babylon.mesh.js

@@ -78,6 +78,7 @@ var BABYLON = BABYLON || {};
     BABYLON.Mesh.prototype.renderingGroupId = 0;
 
     BABYLON.Mesh.prototype.infiniteDistance = false;
+    BABYLON.Mesh.prototype.showBoundingBox = false;
 
     // Properties
 
@@ -325,7 +326,6 @@ var BABYLON = BABYLON || {};
 
     BABYLON.Mesh.prototype.computeWorldMatrix = function (force) {
         if (!force && (this._currentRenderId == this._scene.getRenderId() || this.isSynchronized(true))) {
-            this._currentRenderId = this._scene.getRenderId();
             return this._worldMatrix;
         }
 
@@ -450,6 +450,8 @@ var BABYLON = BABYLON || {};
         this._vertexBuffers[kind] = new BABYLON.VertexBuffer(this, data, kind, updatable);
 
         if (kind === BABYLON.VertexBuffer.PositionKind) {
+            this._resetPointsArrayCache();
+
             var stride = this._vertexBuffers[kind].getStrideSize();
             this._totalVertices = data.length / stride;
 
@@ -460,9 +462,21 @@ var BABYLON = BABYLON || {};
         }
     };
 
-    BABYLON.Mesh.prototype.updateVerticesData = function (kind, data) {
+    BABYLON.Mesh.prototype.updateVerticesData = function (kind, data, updateExtends) {
         if (this._vertexBuffers[kind]) {
             this._vertexBuffers[kind].update(data);
+
+            if (kind === BABYLON.VertexBuffer.PositionKind) {
+                this._resetPointsArrayCache();
+
+                if (updateExtends) {
+                    var stride = this._vertexBuffers[kind].getStrideSize();
+                    this._totalVertices = data.length / stride;
+
+                    var extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
+                    this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
+                }
+            }
         }
     };
 
@@ -720,8 +734,9 @@ var BABYLON = BABYLON || {};
         this._generatePointsArray();
         // Transformation
         if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
-            subMesh._lastColliderTransformMatrix = transformMatrix;
+            subMesh._lastColliderTransformMatrix = transformMatrix.clone();
             subMesh._lastColliderWorldVertices = [];
+            subMesh._trianglePlanes = [];
             var start = subMesh.verticesStart;
             var end = (subMesh.verticesStart + subMesh.verticesCount);
             for (var i = start; i < end; i++) {
@@ -1118,7 +1133,7 @@ var BABYLON = BABYLON || {};
 
     // Cylinder and cone (Code inspired by SharpDX.org)
     BABYLON.Mesh.CreateCylinder = function (name, height, diameterTop, diameterBottom, tessellation, scene, updatable) {
-        var cylinder = new BABYLON.Mesh(name, scene);        
+        var cylinder = new BABYLON.Mesh(name, scene);
         var vertexData = BABYLON.VertexData.CreateCylinder(height, diameterTop, diameterBottom, tessellation);
 
         vertexData.applyToMesh(cylinder, updatable);
@@ -1136,6 +1151,15 @@ var BABYLON = BABYLON || {};
         return torus;
     };
 
+    BABYLON.Mesh.CreateTorusKnot = function (name, radius, tube, radialSegments, tubularSegments, p, q, scene, updatable) {
+        var torusKnot = new BABYLON.Mesh(name, scene);
+        var vertexData = BABYLON.VertexData.CreateTorusKnot(radius, tube, radialSegments, tubularSegments, p, q);
+
+        vertexData.applyToMesh(torusKnot, updatable);
+
+        return torusKnot;
+    };
+
     // Plane & ground
     BABYLON.Mesh.CreatePlane = function (name, size, scene, updatable) {
         var plane = new BABYLON.Mesh(name, scene);
@@ -1216,7 +1240,7 @@ var BABYLON = BABYLON || {};
             }
 
             // Normals
-            BABYLON.Mesh.ComputeNormal(positions, normals, indices);
+            BABYLON.VertexData.ComputeNormals(positions, indices, normals);
 
             // Transfer
             ground.setVerticesData(positions, BABYLON.VertexBuffer.PositionKind, updatable);
@@ -1235,56 +1259,10 @@ var BABYLON = BABYLON || {};
     };
 
     // Tools
-    BABYLON.Mesh.ComputeNormal = function (positions, normals, indices) {
-        var positionVectors = [];
-        var facesOfVertices = [];
-        var index;
-
-        for (index = 0; index < positions.length; index += 3) {
-            var vector3 = new BABYLON.Vector3(positions[index], positions[index + 1], positions[index + 2]);
-            positionVectors.push(vector3);
-            facesOfVertices.push([]);
-        }
-        // Compute normals
-        var facesNormals = [];
-        for (index = 0; index < indices.length / 3; index++) {
-            var i1 = indices[index * 3];
-            var i2 = indices[index * 3 + 1];
-            var i3 = indices[index * 3 + 2];
-
-            var p1 = positionVectors[i1];
-            var p2 = positionVectors[i2];
-            var p3 = positionVectors[i3];
-
-            var p1p2 = p1.subtract(p2);
-            var p3p2 = p3.subtract(p2);
-
-            facesNormals[index] = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(p1p2, p3p2));
-            facesOfVertices[i1].push(index);
-            facesOfVertices[i2].push(index);
-            facesOfVertices[i3].push(index);
-        }
-
-        for (index = 0; index < positionVectors.length; index++) {
-            var faces = facesOfVertices[index];
-
-            var normal = BABYLON.Vector3.Zero();
-            for (var faceIndex = 0; faceIndex < faces.length; faceIndex++) {
-                normal.addInPlace(facesNormals[faces[faceIndex]]);
-            }
-
-            normal = BABYLON.Vector3.Normalize(normal.scale(1.0 / faces.length));
-
-            normals[index * 3] = normal.x;
-            normals[index * 3 + 1] = normal.y;
-            normals[index * 3 + 2] = normal.z;
-        }
-    };
-
-    BABYLON.Mesh.MinMax = function(meshes) {
+    BABYLON.Mesh.MinMax = function (meshes) {
         var minVector;
         var maxVector;
-        for(var i in meshes) {
+        for (var i in meshes) {
             var mesh = meshes[i];
             var boundingBox = mesh.getBoundingInfo().boundingBox;
             if (!minVector) {
@@ -1302,7 +1280,7 @@ var BABYLON = BABYLON || {};
         };
     };
 
-    BABYLON.Mesh.Center = function(meshesOrMinMaxVector) {
+    BABYLON.Mesh.Center = function (meshesOrMinMaxVector) {
         var minMaxVector = meshesOrMinMaxVector.min !== undefined ? meshesOrMinMaxVector : BABYLON.Mesh.MinMax(meshesOrMinMaxVector);
         return BABYLON.Vector3.Center(minMaxVector.min, minMaxVector.max);
     };

+ 233 - 2
Babylon/Mesh/babylon.mesh.vertexData.js

@@ -7,7 +7,7 @@ var BABYLON = BABYLON || {};
     };
 
     // Methods
-    BABYLON.VertexData.prototype.applyToMesh = function(mesh, updatable) {
+    BABYLON.VertexData.prototype.applyToMesh = function (mesh, updatable) {
         if (this.positions) {
             mesh.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
         }
@@ -20,10 +20,22 @@ var BABYLON = BABYLON || {};
             mesh.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
         }
 
+        if (this.uv2s) {
+            mesh.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
+        }
+
         if (this.colors) {
             mesh.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
         }
 
+        if (this.matricesIndices) {
+            mesh.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
+        }
+
+        if (this.matricesWeights) {
+            mesh.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
+        }
+
         if (this.indices) {
             mesh.setIndices(this.indices);
         }
@@ -99,6 +111,33 @@ var BABYLON = BABYLON || {};
             }
         }
 
+        if (other.uv2s) {
+            if (!this.uv2s) {
+                this.uv2s = [];
+            }
+            for (index = 0; index < other.uv2s.length; index++) {
+                this.uv2s.push(other.uv2s[index]);
+            }
+        }
+
+        if (other.matricesIndices) {
+            if (!this.matricesIndices) {
+                this.matricesIndices = [];
+            }
+            for (index = 0; index < other.matricesIndices.length; index++) {
+                this.matricesIndices.push(other.matricesIndices[index]);
+            }
+        }
+
+        if (other.matricesWeights) {
+            if (!this.matricesWeights) {
+                this.matricesWeights = [];
+            }
+            for (index = 0; index < other.matricesWeights.length; index++) {
+                this.matricesWeights.push(other.matricesWeights[index]);
+            }
+        }
+
         if (other.colors) {
             if (!this.colors) {
                 this.colors = [];
@@ -110,7 +149,43 @@ var BABYLON = BABYLON || {};
     };
 
     // Statics
-    BABYLON.VertexData.CreateBox = function(size) {
+    BABYLON.VertexData.ExtractFromMesh = function (mesh) {
+        var result = new BABYLON.VertexData();
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+            result.positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+        }
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+            result.normals = mesh.getVerticesData(BABYLON.VertexBuffer.NormalKind);
+        }
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+            result.uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+        }
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+            result.uv2s = mesh.getVerticesData(BABYLON.VertexBuffer.UV2Kind);
+        }
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+            result.colors = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
+        }
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind)) {
+            result.matricesIndices = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind);
+        }
+
+        if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            result.matricesWeights = mesh.getVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind);
+        }
+
+        result.indices = mesh.getIndices();
+
+        return result;
+    };
+
+    BABYLON.VertexData.CreateBox = function (size) {
         var normalsSource = [
             new BABYLON.Vector3(0, 0, 1),
             new BABYLON.Vector3(0, 0, -1),
@@ -125,6 +200,8 @@ var BABYLON = BABYLON || {};
         var normals = [];
         var uvs = [];
 
+        size = size || 1;
+
         // Create each face in turn.
         for (var index = 0; index < normalsSource.length; index++) {
             var normal = normalsSource[index];
@@ -177,6 +254,10 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.VertexData.CreateSphere = function (segments, diameter) {
+
+        segments = segments || 32;
+        diameter = diameter || 1;
+
         var radius = diameter / 2;
 
         var totalZRotationSteps = 2 + segments;
@@ -242,6 +323,11 @@ var BABYLON = BABYLON || {};
         var normals = [];
         var uvs = [];
 
+        height = height || 1;
+        diameterTop = diameterTop || 0.5;
+        diameterBottom = diameterBottom || 1;
+        tessellation = tessellation || 16;
+
         var getCircleVector = function (i) {
             var angle = (i * 2.0 * Math.PI / tessellation);
             var dx = Math.sin(angle);
@@ -350,6 +436,10 @@ var BABYLON = BABYLON || {};
         var normals = [];
         var uvs = [];
 
+        diameter = diameter || 1;
+        thickness = thickness || 0.5;
+        tessellation = tessellation || 16;
+
         var stride = tessellation + 1;
 
         for (var i = 0; i <= tessellation; i++) {
@@ -410,6 +500,10 @@ var BABYLON = BABYLON || {};
         var uvs = [];
         var row, col;
 
+        width = width || 1;
+        height = height || 1;
+        subdivisions = subdivisions || 1;
+
         for (row = 0; row <= subdivisions; row++) {
             for (col = 0; col <= subdivisions; col++) {
                 var position = new BABYLON.Vector3((col * width) / subdivisions - (width / 2.0), 0, ((subdivisions - row) * height) / subdivisions - (height / 2.0));
@@ -450,6 +544,8 @@ var BABYLON = BABYLON || {};
         var normals = [];
         var uvs = [];
 
+        size = size || 1;
+
         // Vertices
         var halfSize = size / 2.0;
         positions.push(-halfSize, -halfSize, 0);
@@ -487,4 +583,139 @@ var BABYLON = BABYLON || {};
 
         return vertexData;
     };
+
+    // based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473
+    BABYLON.VertexData.CreateTorusKnot = function (radius, tube, radialSegments, tubularSegments, p, q) {
+        var indices = [];
+        var positions = [];
+        var normals = [];
+        var uvs = [];
+
+        radius = radius || 2;
+        tube = tube || 0.5;
+        radialSegments = radialSegments || 32;
+        tubularSegments = tubularSegments || 32;
+        p = p || 2;
+        q = q || 3;
+
+        // Helper
+        function getPos(u, q, p, radius) {
+
+            var cu = Math.cos(u);
+            var su = Math.sin(u);
+            var quOverP = q / p * u;
+            var cs = Math.cos(quOverP);
+
+            var tx = radius * (2 + cs) * 0.5 * cu;
+            var ty = radius * (2 + cs) * su * 0.5;
+            var tz = radius * Math.sin(quOverP) * 0.5;
+
+            return new BABYLON.Vector3(tx, ty, tz);
+        };
+
+        // Vertices
+        for (var i = 0; i <= radialSegments; i++) {
+            var modI = i % radialSegments;
+            var u = modI / radialSegments * 2 * p * Math.PI;
+            var p1 = getPos(u, q, p, radius);
+            var p2 = getPos(u + 0.01, q, p, radius);
+            var tang = p2.subtract(p1);
+            var n = p2.add(p1);
+
+            var bitan = BABYLON.Vector3.Cross(tang, n);
+            n = BABYLON.Vector3.Cross(bitan, tang);
+
+            bitan.normalize();
+            n.normalize();
+
+            for (var j = 0; j < tubularSegments; j++) {
+                var modJ = j % tubularSegments;
+                var v = modJ / tubularSegments * 2 * Math.PI;
+                var cx = -tube * Math.cos(v);
+                var cy = tube * Math.sin(v);
+
+                positions.push(p1.x + cx * n.x + cy * bitan.x);
+                positions.push(p1.y + cx * n.y + cy * bitan.y);
+                positions.push(p1.z + cx * n.z + cy * bitan.z);
+
+                uvs.push(i / radialSegments);
+                uvs.push(j / tubularSegments);
+            }
+        }
+
+        var max = radialSegments * tubularSegments - 1;
+
+        for (var i = 0; i < radialSegments; i++) {
+            for (var j = 0; j < tubularSegments; j++) {
+                var jNext =  (j + 1) % tubularSegments;
+                var a = i * tubularSegments + j;
+                var b = (i + 1) * tubularSegments + j;
+                var c = (i + 1) * tubularSegments + jNext;
+                var d = i * tubularSegments + jNext;
+
+                indices.push(d); indices.push(b); indices.push(a);
+                indices.push(d); indices.push(c); indices.push(b);
+            }
+        }
+
+        // Normals
+        BABYLON.VertexData.ComputeNormals(positions, indices, normals);
+
+        // Result
+        var vertexData = new BABYLON.VertexData();
+
+        vertexData.indices = indices;
+        vertexData.positions = positions;
+        vertexData.normals = normals;
+        vertexData.uvs = uvs;
+
+        return vertexData;
+    };
+
+    // Tools
+    BABYLON.VertexData.ComputeNormals = function (positions, indices, normals) {
+        var positionVectors = [];
+        var facesOfVertices = [];
+        var index;
+
+        for (index = 0; index < positions.length; index += 3) {
+            var vector3 = new BABYLON.Vector3(positions[index], positions[index + 1], positions[index + 2]);
+            positionVectors.push(vector3);
+            facesOfVertices.push([]);
+        }
+        // Compute normals
+        var facesNormals = [];
+        for (index = 0; index < indices.length / 3; index++) {
+            var i1 = indices[index * 3];
+            var i2 = indices[index * 3 + 1];
+            var i3 = indices[index * 3 + 2];
+
+            var p1 = positionVectors[i1];
+            var p2 = positionVectors[i2];
+            var p3 = positionVectors[i3];
+
+            var p1p2 = p1.subtract(p2);
+            var p3p2 = p3.subtract(p2);
+
+            facesNormals[index] = BABYLON.Vector3.Normalize(BABYLON.Vector3.Cross(p1p2, p3p2));
+            facesOfVertices[i1].push(index);
+            facesOfVertices[i2].push(index);
+            facesOfVertices[i3].push(index);
+        }
+
+        for (index = 0; index < positionVectors.length; index++) {
+            var faces = facesOfVertices[index];
+
+            var normal = BABYLON.Vector3.Zero();
+            for (var faceIndex = 0; faceIndex < faces.length; faceIndex++) {
+                normal.addInPlace(facesNormals[faces[faceIndex]]);
+            }
+
+            normal = BABYLON.Vector3.Normalize(normal.scale(1.0 / faces.length));
+
+            normals[index * 3] = normal.x;
+            normals[index * 3 + 1] = normal.y;
+            normals[index * 3 + 2] = normal.z;
+        }
+    };
 })();

+ 6 - 4
Babylon/Mesh/babylon.vertexBuffer.js

@@ -3,9 +3,9 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.VertexBuffer = function (mesh, data, kind, updatable) {
+    BABYLON.VertexBuffer = function (mesh, data, kind, updatable, engine) {
         this._mesh = mesh;
-        this._engine = mesh.getScene().getEngine();
+        this._engine = engine || mesh.getScene().getEngine();
         this._updatable = updatable;
         
         if (updatable) {
@@ -21,7 +21,9 @@ var BABYLON = BABYLON || {};
         switch (kind) {
             case BABYLON.VertexBuffer.PositionKind:
                 this._strideSize = 3;
-                this._mesh._resetPointsArrayCache();
+                if (this._mesh) {
+                    this._mesh._resetPointsArrayCache();
+                }
                 break;
             case BABYLON.VertexBuffer.NormalKind:
                 this._strideSize = 3;
@@ -62,7 +64,7 @@ var BABYLON = BABYLON || {};
         this._engine.updateDynamicVertexBuffer(this._buffer, data);
         this._data = data;
         
-        if (this._kind === BABYLON.VertexBuffer.PositionKind) {
+        if (this._kind === BABYLON.VertexBuffer.PositionKind && this._mesh) {
             this._mesh._resetPointsArrayCache();
         }
     };

+ 1 - 1
Babylon/Particles/babylon.particleSystem.js

@@ -380,7 +380,7 @@ var BABYLON = BABYLON || {};
 
         result.emitter = newEmitter;
         if (this.particleTexture) {
-            result.particleTexture = new BABYLON.Texture(this.particleTexture.name, this._scene);
+            result.particleTexture = new BABYLON.Texture(this.particleTexture.url, this._scene);
         }
 
         result.start();

+ 239 - 0
Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.js

@@ -0,0 +1,239 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.PostProcessRenderEffect = function PostProcessRenderEffect(engine, name, postProcessType, ratio, samplingMode, singleInstance) {
+		this._engine = engine;
+
+		this._name = name;
+
+		this._singleInstance = singleInstance || true;
+
+		this._postProcesses = [];
+
+		this._postProcessType = postProcessType;
+
+		this._ratio = ratio || 1.0;
+		this._samplingMode = samplingMode || null;
+
+		this._cameras = [];
+		this._indicesForCamera = [];
+
+		this._renderPasses = [];
+		this._renderEffectAsPasses = [];
+
+		this.parameters = function () { };
+
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.addPass = function(renderPass) {
+		this._renderPasses[renderPass._name] = renderPass;
+
+		this._linkParameters();
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.removePass = function (renderPass) {
+		delete this._renderPasses[renderPass._name];
+
+		this._linkParameters();
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.addRenderEffectAsPass = function(renderEffect) {
+		this._renderEffectAsPasses[renderEffect._name] = renderEffect;
+
+		this._linkParameters();
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.getPass = function (passName) {
+	    for (var renderPassName in this._renderPasses) {
+	        if (renderPassName == passName) {
+	            return this._renderPasses[passName];
+	        }
+	    }
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.emptyPasses = function () {
+		this._renderPasses.length = 0;
+
+		this._linkParameters();
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.attachCameras = function (cameras) {
+		var postProcess = null;
+
+		cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		for (var i = 0; i < cameras.length; i++) {
+			if (this._singleInstance) {
+			    postProcess = this._postProcesses[0] || BABYLON.PostProcessRenderEffect.getInstance(this._engine, this._postProcessType, this._ratio, this._samplingMode);
+				this._postProcesses[0] = postProcess;
+			}
+			else {
+			    postProcess = this._postProcesses[cameras[i]] || BABYLON.PostProcessRenderEffect.getInstance(this._engine, this._postProcessType, this._ratio, this._samplingMode);
+				this._postProcesses[cameras[i].name] = postProcess;
+			}
+
+			var index = cameras[i].attachPostProcess(postProcess);
+
+			if (this._indicesForCamera[cameras[i].name] == null) {
+				this._indicesForCamera[cameras[i].name] = [];
+			}
+
+			this._indicesForCamera[cameras[i].name].push(index);
+
+			if (this._cameras.indexOf(cameras[i].name) == -1) {
+				this._cameras.push(cameras[i].name);
+			}
+
+			for (var passName in this._renderPasses) {
+			    this._renderPasses[passName].incRefCount();
+			}
+		}
+
+		this._linkParameters();
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.detachCameras = function (cameras) {
+		cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		for (var i = 0; i < cameras.length; i++) {
+		    if (this._singleInstance) {
+			    cameras[i].detachPostProcess(this._postProcesses[0], this._indicesForCamera[cameras[i].name]);
+			}
+			else {
+				cameras[i].detachPostProcess(this._postProcesses[cameras[i].name], this._indicesForCamera[cameras[i].name]);
+			}
+
+			this._indicesForCamera.splice(cameras[i].name, 1);
+			this._cameras.splice(this._cameras.indexOf(cameras[i].name), 1);
+
+			for (var passName in this._renderPasses) {
+			    this._renderPasses[passName].decRefCount();
+			}
+		}
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype._linkParameters = function () {
+		var that = this;
+		for (var index in this._postProcesses) {
+		    this._postProcesses[index].onApply = function (effect) {
+		        that.parameters(effect);
+		        that._linkTextures(effect);
+		    };
+		}
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype._linkTextures = function (effect) {
+        for (var renderPassName in this._renderPasses) {
+            effect.setTexture(renderPassName, this._renderPasses[renderPassName].getRenderTexture());
+        }
+      
+        for (var renderEffectName in this._renderEffectAsPasses) {
+            effect.setTextureFromPostProcess(renderEffectName + "Sampler", this._renderEffectAsPasses[renderEffectName].getPostProcess());
+        }
+	};
+
+    
+	BABYLON.PostProcessRenderEffect.prototype._update = function () {
+		for (var renderPassName in this._renderPasses) {
+			this._renderPasses[renderPassName]._update();
+		}
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.enable = function (cameras) {
+	    cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		for (var i = 0; i < cameras.length; i++) {
+			for (var j = 0; j < this._indicesForCamera[cameras[i].name].length; j++) {
+				if (cameras[i]._postProcesses[this._indicesForCamera[cameras[i].name][j]] === undefined) {
+					if (this._singleInstance) {
+						cameras[i].attachPostProcess(this._postProcesses[0], this._indicesForCamera[cameras[i].name][j]);
+					}
+					else {
+						cameras[i].attachPostProcess(this._postProcesses[cameras[i].name], this._indicesForCamera[cameras[i].name][j]);
+					}
+				}
+			}
+
+			for (var passName in this._renderPasses) {
+			    this._renderPasses[passName].incRefCount();
+			}
+		}
+	};
+
+	BABYLON.PostProcessRenderEffect.prototype.disable = function (cameras) {
+		cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		for (var i = 0; i < cameras.length; i++) {
+		    if (this._singleInstance) {
+				cameras[i].detachPostProcess(this._postProcesses[0], this._indicesForCamera[cameras[i].name]);
+			}
+			else {
+				cameras[i].detachPostProcess(this._postProcesses[cameras[i].name], this._indicesForCamera[cameras[i].name]);
+		    }
+
+		    for (var passName in this._renderPasses) {
+		        this._renderPasses[passName].decRefCount();
+		    }
+		}
+	};
+
+
+	BABYLON.PostProcessRenderEffect.prototype.getPostProcess = function(camera) {
+		return this._postProcess;
+	};
+
+	BABYLON.PostProcessRenderEffect.getInstance = function (engine, postProcessType, ratio, samplingMode) {
+	    var tmpClass;
+	    var instance;
+	    var args = new Array();
+
+	    var parameters = BABYLON.PostProcessRenderEffect.getParametersNames(postProcessType);
+	    for (var i = 0; i < parameters.length; i++) {
+	        switch (parameters[i]) {
+	            case "name":
+	                args[i] = postProcessType.toString();
+	                break;
+	            case "ratio":
+	                args[i] = ratio;
+	                break;
+	            case "camera":
+	                args[i] = null;
+	                break;
+	            case "samplingMode":
+	                args[i] = samplingMode;
+	                break;
+	            case "engine":
+	                args[i] = engine;
+	                break;
+	            case "reusable":
+	                args[i] = true;
+	                break;
+	            default:
+	                args[i] = null;
+	                break;
+	        }
+	    }
+
+	    tmpClass = function () { };
+	    tmpClass.prototype = postProcessType.prototype;
+
+	    instance = new tmpClass();
+	    postProcessType.apply(instance, args);
+
+	    return instance;
+	};
+
+	BABYLON.PostProcessRenderEffect.getParametersNames = function (func) {
+	    var commentsRegex = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
+	    var functWithoutComments = eval(func).toString().replace(commentsRegex, '');
+
+	    var parameters = functWithoutComments.slice(functWithoutComments.indexOf('(') + 1, functWithoutComments.indexOf(')')).match(/([^\s,]+)/g);
+
+	    if (parameters === null)
+	        parameters = [];
+	    return parameters;
+	};
+
+})();

+ 50 - 0
Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPass.js

@@ -0,0 +1,50 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.PostProcessRenderPass = function PostProcessRenderPass(scene, name, size, renderList, beforeRender, afterRender) {
+		this._name = name;
+		this._enabled = true;
+
+		this._renderList = renderList;
+
+		this._renderTexture = new BABYLON.RenderTargetTexture(name, size, scene);
+		this.setRenderList(renderList);
+
+		this._renderTexture.onBeforeRender = beforeRender;
+		this._renderTexture.onAfterRender = afterRender;
+
+		this._scene = scene;
+
+		this._refCount = 0;
+	};
+
+	BABYLON.PostProcessRenderPass.prototype.incRefCount = function () {
+	    if (this._refCount == 0) {
+	        this._scene.customRenderTargets.push(this._renderTexture);
+	    }
+
+	    this._refCount++;
+	};
+
+	BABYLON.PostProcessRenderPass.prototype.decRefCount = function () {
+	    this._refCount--;
+
+	    if (this._refCount <= 0) {
+	        this._scene.customRenderTargets.splice(this._scene.customRenderTargets.indexOf(this._renderTexture), 1);
+	    }
+	};
+
+	BABYLON.PostProcessRenderPass.prototype.setRenderList = function (renderList) {
+		this._renderTexture.renderList = renderList;
+	};
+
+	BABYLON.PostProcessRenderPass.prototype.getRenderTexture = function () {
+		return this._renderTexture;
+	};
+
+	BABYLON.PostProcessRenderPass.prototype._update = function () {
+		this.setRenderList(this._renderList);
+	};
+})();

+ 138 - 0
Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.js

@@ -0,0 +1,138 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.PostProcessRenderPipeline = function PostProcessRenderPipeline(engine, name) {
+		this._engine = engine;
+
+		this._name = name;
+
+		this._renderEffects = [];
+		this._renderEffectsPasses = [];
+
+		this._cameras = [];
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.addEffect = function (renderEffect) {
+		this._renderEffects[renderEffect._name] = renderEffect;
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.enableEffect = function (renderEffectName, cameras) {
+	    cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		var renderEffects = this._renderEffects[renderEffectName];
+
+		if (!renderEffects) {
+			return;
+		}
+
+		renderEffects.enable(cameras);
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.disableEffect = function (renderEffectName, cameras) {
+	    cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		var renderEffects = this._renderEffects[renderEffectName];
+
+		if (!renderEffects) {
+			return;
+		}
+
+		renderEffects.disable(cameras);
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.attachCameras = function (cameras, unique) {
+		cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+		
+		var indicesToDelete = [];
+
+		for (var i = 0; i < cameras.length; i++) {
+			if (this._cameras.indexOf(cameras[i]) == -1) {
+				this._cameras.push(cameras[i]);
+			}
+			else if(unique) {
+				indicesToDelete.push(i);
+			}
+		}
+
+		for (var i = 0; i < indicesToDelete.length; i++) {
+			cameras.splice(indicesToDelete[i], 1);
+		}
+
+		for(var renderEffectName in this._renderEffects) {
+			this._renderEffects[renderEffectName].attachCameras(cameras);
+		}
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.detachCameras = function (cameras) {
+		cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		for (var renderEffectName in this._renderEffects) {
+			this._renderEffects[renderEffectName].detachCameras(cameras);
+		}
+
+		for (var i = 0; i < cameras.length; i++) {
+			this._cameras.splice(this._cameras.indexOf(cameras[i]), 1);
+		}
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.enableDisplayOnlyPass = function (passName, cameras) {
+		cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		var pass = null;
+
+		for (var renderEffectName in this._renderEffects) {
+			pass = this._renderEffects[renderEffectName].getPass(passName);
+
+			if (pass != null) {
+				break;
+			}
+		}
+
+		if (pass == null) {
+			return;
+		}
+		
+		for (var renderEffectName in this._renderEffects) {
+			this._renderEffects[renderEffectName].disable(cameras);
+		}
+		
+		pass._name = BABYLON.PostProcessRenderPipeline.PASS_SAMPLER_NAME;
+		
+		for (var i = 0; i < cameras.length; i++) {
+		    this._renderEffectsPasses[cameras[i].name] = this._renderEffectsPasses[cameras[i].name] || new BABYLON.RenderEffect(this._engine, BABYLON.PostProcessRenderPipeline.PASS_EFFECT_NAME, "BABYLON.DisplayPassPostProcess", 1.0);
+			this._renderEffectsPasses[cameras[i].name].emptyPasses();
+			this._renderEffectsPasses[cameras[i].name].addPass(pass);
+			this._renderEffectsPasses[cameras[i].name].attachCameras(cameras[i]);
+		}
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype.disableDisplayOnlyPass = function (cameras) {
+	    cameras = BABYLON.Tools.MakeArray(cameras || this._cameras);
+
+		for (var i = 0; i < cameras.length; i++) {
+		    this._renderEffectsPasses[cameras[i].name] = this._renderEffectsPasses[cameras[i].name] || new BABYLON.RenderEffect(this._engine, BABYLON.PostProcessRenderPipeline.PASS_EFFECT_NAME, "BABYLON.DisplayPassPostProcess", 1.0);
+		    this._renderEffectsPasses[cameras[i].name].disable(cameras[i]);
+		}
+
+		for (var renderEffectName in this._renderEffects) {
+			this._renderEffects[renderEffectName].enable(cameras);
+		}
+	};
+
+	BABYLON.PostProcessRenderPipeline.prototype._update = function () {
+		for (var renderEffectName in this._renderEffects) {
+			this._renderEffects[renderEffectName]._update();
+		}
+
+		for(var i = 0; i < this._cameras.length; i++) {
+			if (this._renderEffectsPasses[this._cameras[i]]) {
+				this._renderEffectsPasses[this._cameras[i]]._update();
+			}
+		}
+	};
+
+	BABYLON.PostProcessRenderPipeline.PASS_EFFECT_NAME = "passEffect";
+	BABYLON.PostProcessRenderPipeline.PASS_SAMPLER_NAME = "passSampler";
+})();

+ 81 - 0
Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.js

@@ -0,0 +1,81 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+	BABYLON.PostProcessRenderPipelineManager = function PostProcessRenderPipelineManager() {
+		this._renderPipelines = [];
+	};
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.addPipeline = function(renderPipeline) {
+		this._renderPipelines[renderPipeline._name] = renderPipeline;
+	};
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.update = function () {
+		for (var renderPipelineName in this._renderPipelines) {
+			this._renderPipelines[renderPipelineName]._update();
+		}
+	};
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.attachCamerasToRenderPipeline = function (renderPipelineName, cameras, unique) {
+		var renderPipeline = this._renderPipelines[renderPipelineName];
+
+		if (!renderPipeline) {
+			return;
+		}
+
+		renderPipeline.attachCameras(cameras, unique);
+	};
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.detachCamerasFromRenderPipeline = function (renderPipelineName, cameras) {
+		var renderPipeline = this._renderPipelines[renderPipelineName];
+
+		if (!renderPipeline) {
+			return;
+		}
+
+		renderPipeline.detachCameras(cameras);
+	};
+
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.enableEffectInPipeline = function (renderPipelineName, renderEffectName, cameras) {
+		var renderPipeline = this._renderPipelines[renderPipelineName];
+
+		if (!renderPipeline) {
+			return;
+		}
+
+		renderPipeline.enableEffect(renderEffectName, cameras);
+	};
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.disableEffectInPipeline = function (renderPipelineName, renderEffectName, cameras) {
+		var renderPipeline = this._renderPipelines[renderPipelineName];
+
+		if (!renderPipeline) {
+			return;
+		}
+
+		renderPipeline.disableEffect(renderEffectName, cameras);
+	};
+
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.enableDisplayOnlyPassInPipeline = function (renderPipelineName, passName, cameras) {
+		var renderPipeline = this._renderPipelines[renderPipelineName];
+
+		if (!renderPipeline) {
+			return;
+		}
+
+		renderPipeline.enableDisplayOnlyPass(passName, cameras);
+	};
+
+	BABYLON.PostProcessRenderPipelineManager.prototype.disableDisplayOnlyPassInPipeline = function (renderPipelineName, cameras) {
+		var renderPipeline = this._renderPipelines[renderPipelineName];
+
+		if (!renderPipeline) {
+			return;
+		}
+
+		renderPipeline.disableDisplayOnlyPass(cameras);
+	};
+})();

+ 11 - 0
Babylon/PostProcess/babylon.displayPassPostProcess.js

@@ -0,0 +1,11 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.DisplayPassPostProcess = function (name, ratio, camera, samplingMode, engine, reusable) {
+        BABYLON.PostProcess.call(this, name, "displayPass", ["passSampler"], ["passSampler"], ratio, camera, samplingMode, engine, reusable);
+    };
+
+    BABYLON.DisplayPassPostProcess.prototype = Object.create(BABYLON.PostProcess.prototype);
+})();

+ 84 - 0
Babylon/Rendering/babylon.boundingBoxRenderer.js

@@ -0,0 +1,84 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.BoundingBoxRenderer = function (scene) {
+        this._scene = scene;
+        this._colorShader = new BABYLON.ShaderMaterial("colorShader", scene, "color",
+        {
+            attributes: ["position"],
+            uniforms: ["worldViewProjection", "color"]
+        });
+        this.frontColor = new BABYLON.Color3(1, 1, 1);
+        this.backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
+
+        var engine = this._scene.getEngine();
+        var boxdata = BABYLON.VertexData.CreateBox(1.0);
+        this._vb = new BABYLON.VertexBuffer(null, boxdata.positions, BABYLON.VertexBuffer.PositionKind, false, engine);
+        this._ib = engine.createIndexBuffer([0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 7, 1, 6, 2, 5, 3, 4]);
+
+        this.renderList = new BABYLON.Tools.SmartArray(32);
+    };
+
+    // Members
+    BABYLON.BoundingBoxRenderer.prototype.showBackLines = true;
+
+    // Functions
+    BABYLON.BoundingBoxRenderer.prototype.reset = function() {
+        this.renderList.reset();
+    };
+
+    BABYLON.BoundingBoxRenderer.prototype.render = function () {
+        if (this.renderList.length == 0 || !this._colorShader.isReady()) {
+            return;
+        }
+
+        var engine = this._scene.getEngine();
+        engine.setDepthWrite(false);
+        this._colorShader._preBind();
+        for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
+            var mesh = this.renderList.data[boundingBoxIndex];
+            var boundingBox = mesh.getBoundingInfo().boundingBox;
+            var min = boundingBox.minimum;
+            var max = boundingBox.maximum;
+            var diff = max.subtract(min);
+            var median = min.add(diff.scale(0.5));
+
+            var worldMatrix = BABYLON.Matrix.Scaling(diff.x, diff.y, diff.z)
+                .multiply(BABYLON.Matrix.Translation(median.x, median.y, median.z))
+                .multiply(mesh.getWorldMatrix());
+
+            // VBOs
+            engine.bindBuffers(this._vb._buffer, this._ib, [3], 3 * 4, this._colorShader.getEffect());
+
+            if (this.showBackLines) {
+                // Back
+                engine.setDepthFunctionToGreaterOrEqual();
+                this._colorShader.setColor3("color", this.backColor);
+                this._colorShader.bind(worldMatrix, mesh);
+
+                // Draw order
+                engine.draw(false, 0, 24);
+            }
+
+            // Front
+            engine.setDepthFunctionToLess();
+            this._colorShader.setColor3("color", this.frontColor);
+            this._colorShader.bind(worldMatrix, mesh);
+
+            // Draw order
+            engine.draw(false, 0, 24);
+        }
+        this._colorShader.unbind();
+        engine.setDepthFunctionToLessOrEqual();
+        engine.setDepthWrite(true);
+    };
+
+
+    BABYLON.BoundingBoxRenderer.prototype.dispose = function () {
+        this._colorShader.dispose();
+        this._vb.dispose();
+        this._scene.getEngine()._releaseBuffer(this._ib);
+    };
+})();

+ 7 - 0
Babylon/Shaders/color.fragment.fx

@@ -0,0 +1,7 @@
+precision mediump float;
+
+uniform vec3 color;
+
+void main(void) {
+	gl_FragColor = vec4(color, 1.);
+}

+ 11 - 0
Babylon/Shaders/color.vertex.fx

@@ -0,0 +1,11 @@
+precision mediump float;
+
+// Attributes
+attribute vec3 position;
+
+// Uniforms
+uniform mat4 worldViewProjection;
+
+void main(void) {
+	gl_Position = worldViewProjection * vec4(position, 1.0);
+}

+ 11 - 7
Babylon/Shaders/default.fragment.fx

@@ -32,6 +32,7 @@ uniform vec3 vLightSpecular0;
 #ifdef SHADOW0
 varying vec4 vPositionFromLight0;
 uniform sampler2D shadowSampler0;
+uniform float darkness0;
 #endif
 #ifdef SPOTLIGHT0
 uniform vec4 vLightDirection0;
@@ -48,6 +49,7 @@ uniform vec3 vLightSpecular1;
 #ifdef SHADOW1
 varying vec4 vPositionFromLight1;
 uniform sampler2D shadowSampler1;
+uniform float darkness1;
 #endif
 #ifdef SPOTLIGHT1
 uniform vec4 vLightDirection1;
@@ -64,6 +66,7 @@ uniform vec3 vLightSpecular2;
 #ifdef SHADOW2
 varying vec4 vPositionFromLight2;
 uniform sampler2D shadowSampler2;
+uniform float darkness2;
 #endif
 #ifdef SPOTLIGHT2
 uniform vec4 vLightDirection2;
@@ -80,6 +83,7 @@ uniform vec3 vLightSpecular3;
 #ifdef SHADOW3
 varying vec4 vPositionFromLight3;
 uniform sampler2D shadowSampler3;
+uniform float darkness3;
 #endif
 #ifdef SPOTLIGHT3
 uniform vec4 vLightDirection3;
@@ -178,7 +182,7 @@ float unpackHalf(vec2 color)
 	return color.x + (color.y / 255.0);
 }
 
-float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler)
+float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness)
 {
 	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
 	vec2 uv = 0.5 * depth.xy + vec2(0.5, 0.5);
@@ -192,7 +196,7 @@ float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler)
 
 	if (depth.z > shadow)
 	{
-		return 0.;
+		return darkness;
 	}
 	return 1.;
 }
@@ -332,7 +336,7 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
 	// Specular
 	vec3 angleW = normalize(viewDirectionW + lightVectorW);
 	float specComp = max(0., dot(vNormal, angleW));
-	specComp = pow(specComp, vSpecularColor.a);
+	specComp = pow(specComp, max(1., vSpecularColor.a));
 
 	result.diffuse = ndl * diffuseColor;
 	result.specular = specComp * specularColor;
@@ -452,7 +456,7 @@ void main(void) {
 #ifdef SHADOWVSM0
 	shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0);
 #else
-	shadow = computeShadow(vPositionFromLight0, shadowSampler0);
+	shadow = computeShadow(vPositionFromLight0, shadowSampler0, darkness0);
 #endif
 #else
 	shadow = 1.;
@@ -475,7 +479,7 @@ void main(void) {
 #ifdef SHADOWVSM1
 	shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1);
 #else
-	shadow = computeShadow(vPositionFromLight1, shadowSampler1);
+	shadow = computeShadow(vPositionFromLight1, shadowSampler1, darkness1);
 #endif
 #else
 	shadow = 1.;
@@ -498,7 +502,7 @@ void main(void) {
 #ifdef SHADOWVSM2
 	shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2);
 #else
-	shadow = computeShadow(vPositionFromLight2, shadowSampler2);
+	shadow = computeShadow(vPositionFromLight2, shadowSampler2, darkness2);
 #endif	
 #else
 	shadow = 1.;
@@ -521,7 +525,7 @@ void main(void) {
 #ifdef SHADOWVSM3
 	shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3);
 #else
-	shadow = computeShadow(vPositionFromLight3, shadowSampler3);
+	shadow = computeShadow(vPositionFromLight3, shadowSampler3, darkness3);
 #endif	
 #else
 	shadow = 1.;

+ 13 - 0
Babylon/Shaders/displayPass.fragment.fx

@@ -0,0 +1,13 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+// Samplers
+varying vec2 vUV;
+uniform sampler2D textureSampler;
+uniform sampler2D passSampler;
+
+void main(void)
+{
+    gl_FragColor = texture2D(passSampler, vUV);
+}

+ 135 - 0
Babylon/Tools/babylon.andOrNotEvaluator.js

@@ -0,0 +1,135 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.AndOrNotEvaluator = BABYLON.AndOrNotEvaluator || {};
+
+    BABYLON.AndOrNotEvaluator.Eval = function (query, evaluateCallback) {
+        if (!query.match(/\([^\(\)]*\)/g)) {
+            query = BABYLON.AndOrNotEvaluator._HandleParenthesisContent(query, evaluateCallback);
+        }
+        else {
+            query = query.replace(/\([^\(\)]*\)/g, function (r) {
+                // remove parenthesis
+                r = r.slice(1, r.length - 1);
+                return BABYLON.AndOrNotEvaluator._HandleParenthesisContent(r, evaluateCallback);
+            });
+        }
+
+        if (query === "true") {
+            return true;
+        }
+
+        if (query === "false") {
+            return false;
+        }
+
+        return BABYLON.AndOrNotEvaluator.Eval(query, evaluateCallback);
+    };
+
+    BABYLON.AndOrNotEvaluator._HandleParenthesisContent = function (parenthesisContent, evaluateCallback) {
+        evaluateCallback = evaluateCallback || function (r) {
+            /*switch(r)
+            {
+                case "true":
+                    return true;
+                case "false":
+                case "0":
+                case "":
+                case "undefined":
+                case "null":
+                default:
+                    return false;
+            }*/
+            return r === "true" ? true : false;
+        };
+
+        var result;
+        var or = parenthesisContent.split("||");
+
+        for (var i in or) {
+            var ori = BABYLON.AndOrNotEvaluator._SimplifyNegation(or[i].trim());
+            var and = ori.split("&&");
+
+            if (and.length > 1) {
+                for (var j = 0; j < and.length; ++j) {
+                    var andj = BABYLON.AndOrNotEvaluator._SimplifyNegation(and[j].trim());
+                    if (andj !== "true" && andj !== "false") {
+                        if (andj[0] === "!") {
+                            result = andj.substring(1);
+                            if (evaluateCallback) {
+                                result = evaluateCallback(result);
+                            }
+                            result = !result;
+                        }
+                        else {
+                            result = andj;
+                            if (evaluateCallback) {
+                                result = evaluateCallback(result);
+                            }
+                        }
+                    }
+                    else {
+                        result = andj === "true" ? true : false;
+                    }
+                    if (!result) { // no need to continue since 'false && ... && ...' will always return false
+                        ori = "false";
+                        break;
+                    }
+                }
+            }
+
+            if (result || ori === "true") { // no need to continue since 'true || ... || ...' will always return true
+                result = true;
+                break;
+            }
+
+            // result equals false (or undefined)
+
+            if (ori !== "true" && ori !== "false") {
+                if (ori[0] === "!") {
+                    result = ori.substring(1);
+                    if (evaluateCallback) {
+                        result = evaluateCallback(result);
+                    }
+                    result = !result;
+                }
+                else {
+                    result = ori;
+                    if (evaluateCallback) {
+                        result = evaluateCallback(result);
+                    }
+                }
+            }
+            else {
+                result = ori === "true" ? true : false;
+            }
+        }
+
+        // the whole parenthesis scope is replaced by 'true' or 'false'
+        return result ? "true" : "false";
+    };
+
+    BABYLON.AndOrNotEvaluator._SimplifyNegation = function (booleanString) {
+        booleanString = booleanString.replace(/^[\s!]+/, function (r) {
+            // remove whitespaces
+            r = r.replace(/[\s]/g, function (r) {
+                return "";
+            });
+            return r.length % 2 ? "!" : "";
+        });
+
+        booleanString = booleanString.trim();
+
+        if (booleanString === "!true") {
+            booleanString = "false";
+        }
+        else if (booleanString === "!false") {
+            booleanString = "true";
+        }
+
+        return booleanString;
+    };
+
+})();

+ 5 - 0
Babylon/Tools/babylon.sceneSerializer.js

@@ -8,6 +8,7 @@ var BABYLON = BABYLON || {};
         var serializationObject = {};
         serializationObject.name = light.name;
         serializationObject.id = light.id;
+        serializationObject.tags = light._tags;
 
         if (light instanceof BABYLON.PointLight) {
             serializationObject.type = 0;
@@ -39,6 +40,7 @@ var BABYLON = BABYLON || {};
     var serializeCamera = function (camera) {
         var serializationObject = {};
         serializationObject.name = camera.name;
+        serializationObject.tags = camera._tags;
         serializationObject.id = camera.id;
         serializationObject.position = camera.position.asArray();
 
@@ -125,6 +127,7 @@ var BABYLON = BABYLON || {};
 
         serializationObject.name = material.name;
         serializationObject.id = material.id;
+        serializationObject.tags = material._tags;
 
         serializationObject.materials = [];
 
@@ -155,6 +158,7 @@ var BABYLON = BABYLON || {};
         serializationObject.alpha = material.alpha;
 
         serializationObject.id = material.id;
+        serializationObject.tags = material._tags;
         serializationObject.backFaceCulling = material.backFaceCulling;
 
         if (material.diffuseTexture) {
@@ -349,6 +353,7 @@ var BABYLON = BABYLON || {};
 
         serializationObject.name = mesh.name;
         serializationObject.id = mesh.id;
+        serializationObject.tags = mesh._tags;
 
         serializationObject.position = mesh.position.asArray();
 

+ 101 - 0
Babylon/Tools/babylon.tags.js

@@ -0,0 +1,101 @@
+"use strict";
+
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.Tags = BABYLON.Tags || {};
+
+    BABYLON.Tags.EnableFor = function (obj) {
+        obj._tags = obj._tags || {};
+
+        obj.hasTags = function () {
+            return BABYLON.Tags.HasTags(obj);
+        };
+
+        obj.addTags = function (tagsString) {
+            return BABYLON.Tags.AddTagsTo(obj, tagsString);
+        };
+
+        obj.removeTags = function (tagsString) {
+            return BABYLON.Tags.RemoveTagsFrom(obj, tagsString);
+        };
+
+        obj.matchesTagsQuery = function (tagsQuery) {
+            return BABYLON.Tags.MatchesQuery(obj, tagsQuery);
+        };
+    };
+
+    BABYLON.Tags.DisableFor = function (obj) {
+        delete obj._tags;
+        delete obj.hasTags;
+        delete obj.addTags;
+        delete obj.removeTags;
+        delete obj.matchesTagsQuery;
+    };
+
+    BABYLON.Tags.HasTags = function (obj) {
+        if (!obj._tags) {
+            return false;
+        }
+        return !BABYLON.Tools.IsEmpty(obj._tags);
+    };
+
+    // the tags 'true' and 'false' are reserved and cannot be used as tags
+    // a tag cannot start with '||', '&&', and '!'
+    // it cannot contain whitespaces
+    BABYLON.Tags.AddTagsTo = function (obj, tagsString) {
+        if (!tagsString) {
+            return;
+        }
+
+        var tags = tagsString.split(" ");
+        for (var t in tags) {
+            BABYLON.Tags._AddTagTo(obj, tags[t]);
+        }
+    };
+
+    BABYLON.Tags._AddTagTo = function (obj, tag) {
+        tag = tag.trim();
+
+        if (tag === "" || tag === "true" || tag === "false") {
+            return;
+        }
+
+        if (tag.match(/[\s]/) || tag.match(/^([!]|([|]|[&]){2})/)) {
+            return;
+        }
+
+        BABYLON.Tags.EnableFor(obj);
+        obj._tags[tag] = true;
+    };
+
+    BABYLON.Tags.RemoveTagsFrom = function (obj, tagsString) {
+        if (!BABYLON.Tags.HasTags(obj)) {
+            return;
+        }
+        var tags = tagsString.split(" ");
+        for (var t in tags) {
+            BABYLON.Tags._RemoveTagFrom(obj, tags[t]);
+        }
+    };
+    
+
+    BABYLON.Tags._RemoveTagFrom = function (obj, tag) {
+        delete obj._tags[tag];
+    };
+
+    BABYLON.Tags.MatchesQuery = function (obj, tagsQuery) {
+        if (tagsQuery === undefined) {
+            return true;
+        }
+
+        if (tagsQuery === "") {
+            return BABYLON.Tags.HasTags(obj);
+        }
+
+        return BABYLON.AndOrNotEvaluator.Eval(tagsQuery, function (r) {
+            return BABYLON.Tags.HasTags(obj) && obj._tags[r];
+        });
+    };
+
+})();

+ 14 - 0
Babylon/Tools/babylon.tools.js

@@ -51,6 +51,13 @@ var BABYLON = BABYLON || {};
             maximum: maximum
         };
     };
+	
+	BABYLON.Tools.MakeArray = function (obj, allowsNullUndefined) {
+		if (allowsNullUndefined !== true && (obj === undefined || obj == null))
+			return undefined;
+
+		return Array.isArray(obj) ? obj : [obj];
+    };
 
     // Smart array
     BABYLON.Tools.SmartArray = function(capacity) {
@@ -342,6 +349,13 @@ var BABYLON = BABYLON || {};
         }
     };
 
+    BABYLON.Tools.IsEmpty = function (obj) {
+        for (var i in obj) {
+            return false;
+        }
+        return true;
+    };
+
     // FPS
     var fpsRange = 60;
     var previousFramesDuration = [];

+ 36 - 5
Babylon/babylon.engine.js

@@ -161,6 +161,22 @@ var BABYLON = BABYLON || {};
     };
 
     // Methods
+    BABYLON.Engine.prototype.setDepthFunctionToGreater = function() {
+        this._gl.depthFunc(this._gl.GREATER);
+    };
+
+    BABYLON.Engine.prototype.setDepthFunctionToGreaterOrEqual = function () {
+        this._gl.depthFunc(this._gl.GEQUAL);
+    };
+
+    BABYLON.Engine.prototype.setDepthFunctionToLess = function () {
+        this._gl.depthFunc(this._gl.LESS);
+    };
+
+    BABYLON.Engine.prototype.setDepthFunctionToLessOrEqual = function () {
+        this._gl.depthFunc(this._gl.LEQUAL);
+    };
+
     BABYLON.Engine.prototype.stopRenderLoop = function () {
         this._renderFunction = null;
         this._runningLoop = false;
@@ -272,6 +288,8 @@ var BABYLON = BABYLON || {};
             gl.generateMipmap(gl.TEXTURE_2D);
             gl.bindTexture(gl.TEXTURE_2D, null);
         }
+
+        this._gl.bindFramebuffer(this._gl.FRAMEBUFFER, null);
     };
 
     BABYLON.Engine.prototype.flushFramebuffer = function () {
@@ -307,11 +325,14 @@ var BABYLON = BABYLON || {};
 
     BABYLON.Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, length) {
         this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
-        // Should be (vertices instanceof Float32Array ? vertices : new Float32Array(vertices)) but Chrome raises an Exception in this case :(
-        if (length) {
+        if (length && length != vertices.length) {
             this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices, 0, length));
         } else {
-            this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
+            if (vertices instanceof Float32Array) {
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices);
+            } else {
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
+            }
         }
         
         this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
@@ -388,7 +409,16 @@ var BABYLON = BABYLON || {};
     };
 
     // Shaders
-    BABYLON.Engine.prototype.createEffect = function (baseName, attributesNames, uniformsNames, samplers, defines, optionalDefines) {
+    BABYLON.Engine.prototype._releaseEffect = function (effect) {
+        if (this._compiledEffects[effect._key]) {
+            delete this._compiledEffects[effect._key];
+            if (effect._program) {
+                this._gl.deleteProgram(effect._program);
+            }
+        }
+    };
+
+    BABYLON.Engine.prototype.createEffect = function (baseName, attributesNames, uniformsNames, samplers, defines, optionalDefines, onCompiled, onError) {
         var vertex = baseName.vertexElement || baseName.vertex || baseName;
         var fragment = baseName.fragmentElement || baseName.fragment || baseName;
         
@@ -397,7 +427,8 @@ var BABYLON = BABYLON || {};
             return this._compiledEffects[name];
         }
 
-        var effect = new BABYLON.Effect(baseName, attributesNames, uniformsNames, samplers, this, defines, optionalDefines);
+        var effect = new BABYLON.Effect(baseName, attributesNames, uniformsNames, samplers, this, defines, optionalDefines, onCompiled, onError);
+        effect._key = name;
         this._compiledEffects[name] = effect;
 
         return effect;

+ 1 - 1
Babylon/babylon.node.js

@@ -52,7 +52,7 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.Node.prototype.isSynchronizedWithParent = function() {
-        return this.parent ? !this.parent._currentRenderId === this._currentRenderId : true;
+        return this.parent ? this.parent._currentRenderId <= this._currentRenderId : true;
     };
 
     BABYLON.Node.prototype.isSynchronized = function (updateCache) {

+ 65 - 9
Babylon/babylon.scene.js

@@ -3,7 +3,7 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-    BABYLON.Scene = function (engine) {
+    BABYLON.Scene = function(engine) {
         this._engine = engine;
         this.autoClear = true;
         this.clearColor = new BABYLON.Color3(0.2, 0.2, 0.3);
@@ -106,9 +106,16 @@ var BABYLON = BABYLON || {};
 
         // Multi-cameras
         this.activeCameras = [];
+
+        // Render bounding boxes
+        this._boundingBoxRenderer = new BABYLON.BoundingBoxRenderer(this);
+    };
+
+    // Properties 
+    BABYLON.Scene.prototype.getBoundingBoxRenderer = function () {
+        return this._boundingBoxRenderer;
     };
 
-    // Properties   
     BABYLON.Scene.prototype.getEngine = function () {
         return this._engine;
     };
@@ -409,7 +416,7 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.Scene.prototype.getLastMeshByID = function (id) {
-        for (var index = this.meshes.length - 1; index >= 0 ; index--) {
+        for (var index = this.meshes.length - 1; index >= 0; index--) {
             if (this.meshes[index].id === id) {
                 return this.meshes[index];
             }
@@ -419,19 +426,19 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.Scene.prototype.getLastEntryByID = function (id) {
-        for (var index = this.meshes.length - 1; index >= 0 ; index--) {
+        for (var index = this.meshes.length - 1; index >= 0; index--) {
             if (this.meshes[index].id === id) {
                 return this.meshes[index];
             }
         }
 
-        for (var index = this.cameras.length - 1; index >= 0 ; index--) {
+        for (var index = this.cameras.length - 1; index >= 0; index--) {
             if (this.cameras[index].id === id) {
                 return this.cameras[index];
             }
         }
 
-        for (var index = this.lights.length - 1; index >= 0 ; index--) {
+        for (var index = this.lights.length - 1; index >= 0; index--) {
             if (this.lights[index].id === id) {
                 return this.lights[index];
             }
@@ -451,7 +458,7 @@ var BABYLON = BABYLON || {};
     };
 
     BABYLON.Scene.prototype.getLastSkeletonByID = function (id) {
-        for (var index = this.skeletons.length - 1; index >= 0 ; index--) {
+        for (var index = this.skeletons.length - 1; index >= 0; index--) {
             if (this.skeletons[index].id === id) {
                 return this.skeletons[index];
             }
@@ -511,6 +518,7 @@ var BABYLON = BABYLON || {};
         this._processedMaterials.reset();
         this._activeParticleSystems.reset();
         this._activeSkeletons.reset();
+        this._boundingBoxRenderer.reset();
 
         if (!this._frustumPlanes) {
             this._frustumPlanes = BABYLON.Frustum.GetPlanes(this._transformMatrix);
@@ -545,6 +553,10 @@ var BABYLON = BABYLON || {};
                         }
                         mesh._renderId = this._renderId;
 
+                        if (mesh.showBoundingBox) {
+                            this._boundingBoxRenderer.renderList.push(mesh);
+                        }
+
                         if (mesh.skeleton) {
                             this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
                         }
@@ -584,6 +596,10 @@ var BABYLON = BABYLON || {};
                         this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
                     }
 
+                    if (mesh.showBoundingBox) {
+                        this._boundingBoxRenderer.renderList.push(mesh);
+                    }
+
                     for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
                         var subMesh = mesh.subMeshes[subIndex];
 
@@ -676,6 +692,9 @@ var BABYLON = BABYLON || {};
         // Render
         this._renderingManager.render(null, null, true, true);
 
+        // Bounding boxes
+        this._boundingBoxRenderer.render();
+
         // Lens flares
         for (var lensFlareSystemIndex = 0; lensFlareSystemIndex < this.lensFlareSystems.length; lensFlareSystemIndex++) {
             this.lensFlareSystems[lensFlareSystemIndex].render();
@@ -760,7 +779,7 @@ var BABYLON = BABYLON || {};
             var light = this.lights[lightIndex];
             var shadowGenerator = light.getShadowGenerator();
 
-            if (light.isEnabled() && shadowGenerator) {
+            if (light.isEnabled() && shadowGenerator && shadowGenerator.getShadowMap()._scene.textures.indexOf(shadowGenerator.getShadowMap()) !== -1) {
                 this._renderTargets.push(shadowGenerator.getShadowMap());
             }
         }
@@ -798,6 +817,8 @@ var BABYLON = BABYLON || {};
 
         this.skeletons = [];
 
+        this._boundingBoxRenderer.dispose();
+
         // Detach cameras
         var canvas = this._engine.getRenderingCanvas();
         var index;
@@ -1083,9 +1104,44 @@ var BABYLON = BABYLON || {};
         }
     };
 
+    // Tags
+    BABYLON.Scene.prototype._getByTags = function (list, tagsQuery) {
+        if (tagsQuery === undefined) {
+            // returns the complete list (could be done with BABYLON.Tags.MatchesQuery but no need to have a for-loop here)
+            return list;
+        }
+
+        var listByTags = [];
+
+        for (var i in list) {
+            var item = list[i];
+            if (BABYLON.Tags.MatchesQuery(item, tagsQuery)) {
+                listByTags.push(item);
+            }
+        }
+
+        return listByTags;
+    };
+
+    BABYLON.Scene.prototype.getMeshesByTags = function (tagsQuery) {
+        return this._getByTags(this.meshes, tagsQuery);
+    };
+
+    BABYLON.Scene.prototype.getCamerasByTags = function (tagsQuery) {
+        return this._getByTags(this.cameras, tagsQuery);
+    };
+
+    BABYLON.Scene.prototype.getLightsByTags = function (tagsQuery) {
+        return this._getByTags(this.lights, tagsQuery);
+    };
+
+    BABYLON.Scene.prototype.getMaterialByTags = function (tagsQuery) {
+        return this._getByTags(this.materials, tagsQuery).concat(this._getByTags(this.multiMaterials, tagsQuery));
+    };
+
     // Statics
     BABYLON.Scene.FOGMODE_NONE = 0;
     BABYLON.Scene.FOGMODE_EXP = 1;
     BABYLON.Scene.FOGMODE_EXP2 = 2;
     BABYLON.Scene.FOGMODE_LINEAR = 3;
-})();
+})();

+ 8 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <files xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="babylonJS.xsd">
+  <script src="Babylon/Rendering/babylon.boundingBoxRenderer.js"></script>
   <script src="Babylon/Materials/babylon.shaderMaterial.js"></script>
   <script src="Babylon/Cameras/babylon.virtualJoysticksCamera.js"></script>
   <script src="Babylon/Tools/babylon.virtualJoystick.js"></script>
@@ -16,6 +17,11 @@
   <script src="Babylon/LensFlare/babylon.lensFlareSystem.js"></script>
   <script src="Babylon/LensFlare/babylon.lensFlare.js"></script>
   <script src="Babylon/PostProcess/babylon.anaglyphPostProcess.js"></script>
+  <script src="Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPass.js"></script>
+  <script src="Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderEffect.js"></script>
+  <script src="Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPipeline.js"></script>
+  <script src="Babylon/PostProcess/RenderPipeline/babylon.postProcessRenderPipelineManager.js"></script>
+  <script src="Babylon/PostProcess/babylon.displayPassPostProcess.js"></script>
   <script src="Babylon/PostProcess/babylon.fxaaPostProcess.js"></script>
   <script src="Babylon/PostProcess/babylon.filterPostProcess.js"></script>
   <script src="Babylon/PostProcess/babylon.convolutionPostProcess.js"></script>
@@ -76,6 +82,8 @@
   <script src="Babylon/babylon.engine.js"></script>
   <script src="Babylon/Math/babylon.axis.js"></script>
   <script src="Babylon/Math/babylon.math.js"></script>
+  <script src="Babylon/Tools/babylon.tags.js"></script>
+  <script src="Babylon/Tools/babylon.andOrNotEvaluator.js"></script>
   <script src="Babylon/Tools/babylon.tools.js"></script>
   <script src="Babylon/babylon.node.js"></script>
 </files>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/ourOwnBabylon.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 24
babylon.1.10.0.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 28 - 0
babylon.1.11.js


+ 1 - 0
readme.md

@@ -45,6 +45,7 @@ Online [sandbox](http://www.babylonjs.com/sandbox) where you can test your .baby
  - Bump texture
  - Up to 4 lights (points, directionals, spots, hemispherics)
  - Custom materials
+ - Custom shaders
  - Skybox
  - Vertex color
  - Bones (Animations and shadows are supported)

+ 20 - 0
what's new.md

@@ -1,5 +1,25 @@
 Changes list
 ============
+- 1.11.0:
+ - **Major updates**
+ - New option for mesh: ```mesh.showBoundingBox``` to display mesh's bounding box. You can configure back and front color using ```scene.getBoundingBoxRenderer()```. This function returns a ```BABYLON.BoundingBoxRenderer``` where you can define ```backColor```, ```frontColor``` and ```showBackLines``` ([deltakosh](http://www.github.com/deltakosh))
+ - New basic mesh: ```BABYLON.Mesh.CreateTorusKnot``` ([deltakosh](http://www.github.com/deltakosh))
+ - New ```BABYLON.AnaglyphArcRotateCamera``` and ```BABYLON.AnaglyphFreeCamera``` ([michael-korbas](https://github.com/michael-korbas)), ([deltakosh](http://www.github.com/deltakosh))
+ - Tags system ([gwenael-hagenmuller](https://github.com/gwenael-hagenmuller))
+ - New render pipeline system for post-processes. See documentation [here](https://github.com/BabylonJS/Babylon.js/wiki/How-to-use-PostProcessRenderPipeline) ([michael-korbas](https://github.com/michael-korbas))
+ - **Updates**
+ - Added parameters to enable or disable a type of texture on all ```BABYLON.StandardMaterial``` ([demonixis](http://www.github.com/demonixis))
+ - New ```BABYLON.VertexData.ExtractFromMesh``` function ([deltakosh](http://www.github.com/deltakosh))
+ - Cameras can now have sub-cameras (see ```BABYLON.AnaglyphArcRotateCamera``` for example) ([deltakosh](http://www.github.com/deltakosh))
+ - New ```BABYLON.Engine.runEvenInBackground``` property. True by default. It allows you to stop rendering when the browser is not the foreground application. ([deltakosh](http://www.github.com/deltakosh))
+ - Darkness of a shadow + shadow on transparent meshes ([clementlevasseur](https://github.com/clementlevasseur))
+ - New event for materials: ```onCompiled``` and ```onError``` ([deltakosh](http://www.github.com/deltakosh))
+ - **Bugfixes**
+ - Fixed a bug with collisions cache
+ - Fixed a bug with mesh.dispose when called twice ([deltakosh](http://www.github.com/deltakosh))
+ - Fixed an issue with Internet Explorer while rendering a RenderTargetTexture outside the engine renderLoop ([nicolas-obre](https://github.com/nicolas-obre))
+ - **New demos*
+ - [CYOS](http://www.babylonjs.com/cyos)
 - 1.10.0:
  - **Major updates**
  - Virtual joysticks canera ([davrous](http://www.github.com/davrous))