|
@@ -221,10 +221,6 @@ var BABYLON;
|
|
|
this._fallbacks = fallbacks;
|
|
|
}
|
|
|
this.uniqueId = Effect._uniqueIdSeed++;
|
|
|
- if (this._getFromCache(baseName)) {
|
|
|
- this._prepareEffect();
|
|
|
- return;
|
|
|
- }
|
|
|
var vertexSource;
|
|
|
var fragmentSource;
|
|
|
if (baseName.vertexElement) {
|
|
@@ -245,71 +241,30 @@ var BABYLON;
|
|
|
else {
|
|
|
fragmentSource = baseName.fragment || baseName;
|
|
|
}
|
|
|
- var finalVertexCode;
|
|
|
- this._loadVertexShaderAsync(vertexSource)
|
|
|
- .then(function (vertexCode) {
|
|
|
- return _this._processIncludesAsync(vertexCode);
|
|
|
- })
|
|
|
- .then(function (vertexCodeWithIncludes) {
|
|
|
- finalVertexCode = _this._processShaderConversion(vertexCodeWithIncludes, false);
|
|
|
- return _this._loadFragmentShaderAsync(fragmentSource);
|
|
|
- })
|
|
|
- .then(function (fragmentCode) {
|
|
|
- return _this._processIncludesAsync(fragmentCode);
|
|
|
- })
|
|
|
- .then(function (fragmentCodeWithIncludes) {
|
|
|
- var migratedFragmentCode = _this._processShaderConversion(fragmentCodeWithIncludes, true);
|
|
|
- if (baseName) {
|
|
|
- var vertex = baseName.vertexElement || baseName.vertex || baseName;
|
|
|
- var fragment = baseName.fragmentElement || baseName.fragment || baseName;
|
|
|
- _this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + finalVertexCode;
|
|
|
- _this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
|
|
|
- }
|
|
|
- else {
|
|
|
- _this._vertexSourceCode = finalVertexCode;
|
|
|
- _this._fragmentSourceCode = migratedFragmentCode;
|
|
|
- }
|
|
|
- _this._setInCache(baseName);
|
|
|
- _this._prepareEffect();
|
|
|
+ this._loadVertexShader(vertexSource, function (vertexCode) {
|
|
|
+ _this._processIncludes(vertexCode, function (vertexCodeWithIncludes) {
|
|
|
+ _this._processShaderConversion(vertexCodeWithIncludes, false, function (migratedVertexCode) {
|
|
|
+ _this._loadFragmentShader(fragmentSource, function (fragmentCode) {
|
|
|
+ _this._processIncludes(fragmentCode, function (fragmentCodeWithIncludes) {
|
|
|
+ _this._processShaderConversion(fragmentCodeWithIncludes, true, function (migratedFragmentCode) {
|
|
|
+ if (baseName) {
|
|
|
+ var vertex = baseName.vertexElement || baseName.vertex || baseName;
|
|
|
+ var fragment = baseName.fragmentElement || baseName.fragment || baseName;
|
|
|
+ _this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + migratedVertexCode;
|
|
|
+ _this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ _this._vertexSourceCode = migratedVertexCode;
|
|
|
+ _this._fragmentSourceCode = migratedFragmentCode;
|
|
|
+ }
|
|
|
+ _this._prepareEffect();
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|
|
|
}
|
|
|
- Effect.prototype._getSourceCacheKey = function (baseName) {
|
|
|
- var cacheKey = baseName;
|
|
|
- if (this._indexParameters) {
|
|
|
- for (var key in this._indexParameters) {
|
|
|
- if (this._indexParameters.hasOwnProperty(key)) {
|
|
|
- cacheKey += "|";
|
|
|
- cacheKey += key;
|
|
|
- cacheKey += "_";
|
|
|
- cacheKey += this._indexParameters[key];
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return cacheKey;
|
|
|
- };
|
|
|
- Effect.prototype._getFromCache = function (baseName) {
|
|
|
- if (typeof baseName !== "string") {
|
|
|
- return false;
|
|
|
- }
|
|
|
- var cacheKey = this._getSourceCacheKey(baseName);
|
|
|
- var sources = Effect._sourceCache[cacheKey];
|
|
|
- if (!sources) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- this._vertexSourceCode = sources.vertex;
|
|
|
- this._fragmentSourceCode = sources.fragment;
|
|
|
- return true;
|
|
|
- };
|
|
|
- Effect.prototype._setInCache = function (baseName) {
|
|
|
- if (typeof baseName !== "string") {
|
|
|
- return;
|
|
|
- }
|
|
|
- var cacheKey = this._getSourceCacheKey(baseName);
|
|
|
- Effect._sourceCache[cacheKey] = {
|
|
|
- vertex: this._vertexSourceCode,
|
|
|
- fragment: this._fragmentSourceCode
|
|
|
- };
|
|
|
- };
|
|
|
Object.defineProperty(Effect.prototype, "key", {
|
|
|
/**
|
|
|
* Unique key for this effect
|
|
@@ -416,22 +371,25 @@ var BABYLON;
|
|
|
});
|
|
|
};
|
|
|
/** @ignore */
|
|
|
- Effect.prototype._loadVertexShaderAsync = function (vertex) {
|
|
|
+ Effect.prototype._loadVertexShader = function (vertex, callback) {
|
|
|
if (BABYLON.Tools.IsWindowObjectExist()) {
|
|
|
// DOM element ?
|
|
|
if (vertex instanceof HTMLElement) {
|
|
|
var vertexCode = BABYLON.Tools.GetDOMTextContent(vertex);
|
|
|
- return Promise.resolve(vertexCode);
|
|
|
+ callback(vertexCode);
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
// Base64 encoded ?
|
|
|
if (vertex.substr(0, 7) === "base64:") {
|
|
|
var vertexBinary = window.atob(vertex.substr(7));
|
|
|
- return Promise.resolve(vertexBinary);
|
|
|
+ callback(vertexBinary);
|
|
|
+ return;
|
|
|
}
|
|
|
// Is in local store ?
|
|
|
if (Effect.ShadersStore[vertex + "VertexShader"]) {
|
|
|
- return Promise.resolve(Effect.ShadersStore[vertex + "VertexShader"]);
|
|
|
+ callback(Effect.ShadersStore[vertex + "VertexShader"]);
|
|
|
+ return;
|
|
|
}
|
|
|
var vertexShaderUrl;
|
|
|
if (vertex[0] === "." || vertex[0] === "/" || vertex.indexOf("http") > -1) {
|
|
@@ -441,28 +399,32 @@ var BABYLON;
|
|
|
vertexShaderUrl = BABYLON.Engine.ShadersRepository + vertex;
|
|
|
}
|
|
|
// Vertex shader
|
|
|
- return this._engine._loadFileAsync(vertexShaderUrl + ".vertex.fx");
|
|
|
+ this._engine._loadFile(vertexShaderUrl + ".vertex.fx", callback);
|
|
|
};
|
|
|
/** @ignore */
|
|
|
- Effect.prototype._loadFragmentShaderAsync = function (fragment) {
|
|
|
+ Effect.prototype._loadFragmentShader = function (fragment, callback) {
|
|
|
if (BABYLON.Tools.IsWindowObjectExist()) {
|
|
|
// DOM element ?
|
|
|
if (fragment instanceof HTMLElement) {
|
|
|
var fragmentCode = BABYLON.Tools.GetDOMTextContent(fragment);
|
|
|
- return Promise.resolve(fragmentCode);
|
|
|
+ callback(fragmentCode);
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
// Base64 encoded ?
|
|
|
if (fragment.substr(0, 7) === "base64:") {
|
|
|
var fragmentBinary = window.atob(fragment.substr(7));
|
|
|
- return Promise.resolve(fragmentBinary);
|
|
|
+ callback(fragmentBinary);
|
|
|
+ return;
|
|
|
}
|
|
|
// Is in local store ?
|
|
|
if (Effect.ShadersStore[fragment + "PixelShader"]) {
|
|
|
- return Promise.resolve(Effect.ShadersStore[fragment + "PixelShader"]);
|
|
|
+ callback(Effect.ShadersStore[fragment + "PixelShader"]);
|
|
|
+ return;
|
|
|
}
|
|
|
if (Effect.ShadersStore[fragment + "FragmentShader"]) {
|
|
|
- return Promise.resolve(Effect.ShadersStore[fragment + "FragmentShader"]);
|
|
|
+ callback(Effect.ShadersStore[fragment + "FragmentShader"]);
|
|
|
+ return;
|
|
|
}
|
|
|
var fragmentShaderUrl;
|
|
|
if (fragment[0] === "." || fragment[0] === "/" || fragment.indexOf("http") > -1) {
|
|
@@ -472,7 +434,7 @@ var BABYLON;
|
|
|
fragmentShaderUrl = BABYLON.Engine.ShadersRepository + fragment;
|
|
|
}
|
|
|
// Fragment shader
|
|
|
- return this._engine._loadFileAsync(fragmentShaderUrl + ".fragment.fx");
|
|
|
+ this._engine._loadFile(fragmentShaderUrl + ".fragment.fx", callback);
|
|
|
};
|
|
|
Effect.prototype._dumpShadersSource = function (vertexCode, fragmentCode, defines) {
|
|
|
// Rebuild shaders source code
|
|
@@ -501,14 +463,16 @@ var BABYLON;
|
|
|
}
|
|
|
};
|
|
|
;
|
|
|
- Effect.prototype._processShaderConversion = function (sourceCode, isFragment) {
|
|
|
+ Effect.prototype._processShaderConversion = function (sourceCode, isFragment, callback) {
|
|
|
var preparedSourceCode = this._processPrecision(sourceCode);
|
|
|
if (this._engine.webGLVersion == 1) {
|
|
|
- return preparedSourceCode;
|
|
|
+ callback(preparedSourceCode);
|
|
|
+ return;
|
|
|
}
|
|
|
// Already converted
|
|
|
if (preparedSourceCode.indexOf("#version 3") !== -1) {
|
|
|
- return preparedSourceCode.replace("#version 300 es", "");
|
|
|
+ callback(preparedSourceCode.replace("#version 300 es", ""));
|
|
|
+ return;
|
|
|
}
|
|
|
var hasDrawBuffersExtension = preparedSourceCode.search(/#extension.+GL_EXT_draw_buffers.+require/) !== -1;
|
|
|
// Remove extensions
|
|
@@ -532,86 +496,80 @@ var BABYLON;
|
|
|
result = result.replace(/gl_FragData/g, "glFragData");
|
|
|
result = result.replace(/void\s+?main\s*\(/g, (hasDrawBuffersExtension ? "" : "out vec4 glFragColor;\n") + "void main(");
|
|
|
}
|
|
|
- return result;
|
|
|
+ callback(result);
|
|
|
};
|
|
|
- Effect.prototype._processIncludesAsync = function (sourceCode) {
|
|
|
+ Effect.prototype._processIncludes = function (sourceCode, callback) {
|
|
|
var _this = this;
|
|
|
- return new Promise(function (resolve, reject) {
|
|
|
- var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
|
|
|
- var match = regex.exec(sourceCode);
|
|
|
- var returnValue = sourceCode;
|
|
|
- while (match != null) {
|
|
|
- var includeFile = match[1];
|
|
|
- // Uniform declaration
|
|
|
- if (includeFile.indexOf("__decl__") !== -1) {
|
|
|
- includeFile = includeFile.replace(/__decl__/, "");
|
|
|
- if (_this._engine.supportsUniformBuffers) {
|
|
|
- includeFile = includeFile.replace(/Vertex/, "Ubo");
|
|
|
- includeFile = includeFile.replace(/Fragment/, "Ubo");
|
|
|
- }
|
|
|
- includeFile = includeFile + "Declaration";
|
|
|
- }
|
|
|
- if (Effect.IncludesShadersStore[includeFile]) {
|
|
|
- // Substitution
|
|
|
- var includeContent = Effect.IncludesShadersStore[includeFile];
|
|
|
- if (match[2]) {
|
|
|
- var splits = match[3].split(",");
|
|
|
- for (var index = 0; index < splits.length; index += 2) {
|
|
|
- var source = new RegExp(splits[index], "g");
|
|
|
- var dest = splits[index + 1];
|
|
|
- includeContent = includeContent.replace(source, dest);
|
|
|
- }
|
|
|
+ var regex = /#include<(.+)>(\((.*)\))*(\[(.*)\])*/g;
|
|
|
+ var match = regex.exec(sourceCode);
|
|
|
+ var returnValue = new String(sourceCode);
|
|
|
+ while (match != null) {
|
|
|
+ var includeFile = match[1];
|
|
|
+ // Uniform declaration
|
|
|
+ if (includeFile.indexOf("__decl__") !== -1) {
|
|
|
+ includeFile = includeFile.replace(/__decl__/, "");
|
|
|
+ if (this._engine.supportsUniformBuffers) {
|
|
|
+ includeFile = includeFile.replace(/Vertex/, "Ubo");
|
|
|
+ includeFile = includeFile.replace(/Fragment/, "Ubo");
|
|
|
+ }
|
|
|
+ includeFile = includeFile + "Declaration";
|
|
|
+ }
|
|
|
+ if (Effect.IncludesShadersStore[includeFile]) {
|
|
|
+ // Substitution
|
|
|
+ var includeContent = Effect.IncludesShadersStore[includeFile];
|
|
|
+ if (match[2]) {
|
|
|
+ var splits = match[3].split(",");
|
|
|
+ for (var index = 0; index < splits.length; index += 2) {
|
|
|
+ var source = new RegExp(splits[index], "g");
|
|
|
+ var dest = splits[index + 1];
|
|
|
+ includeContent = includeContent.replace(source, dest);
|
|
|
}
|
|
|
- if (match[4]) {
|
|
|
- var indexString = match[5];
|
|
|
- if (indexString.indexOf("..") !== -1) {
|
|
|
- var indexSplits = indexString.split("..");
|
|
|
- var minIndex = parseInt(indexSplits[0]);
|
|
|
- var maxIndex = parseInt(indexSplits[1]);
|
|
|
- var sourceIncludeContent = includeContent.slice(0);
|
|
|
- includeContent = "";
|
|
|
- if (isNaN(maxIndex)) {
|
|
|
- maxIndex = _this._indexParameters[indexSplits[1]];
|
|
|
- }
|
|
|
- for (var i = minIndex; i < maxIndex; i++) {
|
|
|
- if (!_this._engine.supportsUniformBuffers) {
|
|
|
- // Ubo replacement
|
|
|
- sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, function (str, p1) {
|
|
|
- return p1 + "{X}";
|
|
|
- });
|
|
|
- }
|
|
|
- includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
|
|
|
- }
|
|
|
+ }
|
|
|
+ if (match[4]) {
|
|
|
+ var indexString = match[5];
|
|
|
+ if (indexString.indexOf("..") !== -1) {
|
|
|
+ var indexSplits = indexString.split("..");
|
|
|
+ var minIndex = parseInt(indexSplits[0]);
|
|
|
+ var maxIndex = parseInt(indexSplits[1]);
|
|
|
+ var sourceIncludeContent = includeContent.slice(0);
|
|
|
+ includeContent = "";
|
|
|
+ if (isNaN(maxIndex)) {
|
|
|
+ maxIndex = this._indexParameters[indexSplits[1]];
|
|
|
}
|
|
|
- else {
|
|
|
- if (!_this._engine.supportsUniformBuffers) {
|
|
|
+ for (var i = minIndex; i < maxIndex; i++) {
|
|
|
+ if (!this._engine.supportsUniformBuffers) {
|
|
|
// Ubo replacement
|
|
|
- includeContent = includeContent.replace(/light\{X\}.(\w*)/g, function (str, p1) {
|
|
|
+ sourceIncludeContent = sourceIncludeContent.replace(/light\{X\}.(\w*)/g, function (str, p1) {
|
|
|
return p1 + "{X}";
|
|
|
});
|
|
|
}
|
|
|
- includeContent = includeContent.replace(/\{X\}/g, indexString);
|
|
|
+ includeContent += sourceIncludeContent.replace(/\{X\}/g, i.toString()) + "\n";
|
|
|
}
|
|
|
}
|
|
|
- // Replace
|
|
|
- returnValue = returnValue.replace(match[0], includeContent);
|
|
|
- }
|
|
|
- else {
|
|
|
- var includeShaderUrl = BABYLON.Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
|
|
|
- _this._engine._loadFileAsync(includeShaderUrl)
|
|
|
- .then(function (fileContent) {
|
|
|
- Effect.IncludesShadersStore[includeFile] = fileContent;
|
|
|
- return _this._processIncludesAsync(returnValue);
|
|
|
- })
|
|
|
- .then(function (returnValue) {
|
|
|
- resolve(returnValue);
|
|
|
- });
|
|
|
- return;
|
|
|
+ else {
|
|
|
+ if (!this._engine.supportsUniformBuffers) {
|
|
|
+ // Ubo replacement
|
|
|
+ includeContent = includeContent.replace(/light\{X\}.(\w*)/g, function (str, p1) {
|
|
|
+ return p1 + "{X}";
|
|
|
+ });
|
|
|
+ }
|
|
|
+ includeContent = includeContent.replace(/\{X\}/g, indexString);
|
|
|
+ }
|
|
|
}
|
|
|
- match = regex.exec(sourceCode);
|
|
|
+ // Replace
|
|
|
+ returnValue = returnValue.replace(match[0], includeContent);
|
|
|
}
|
|
|
- resolve(returnValue);
|
|
|
- });
|
|
|
+ else {
|
|
|
+ var includeShaderUrl = BABYLON.Engine.ShadersRepository + "ShadersInclude/" + includeFile + ".fx";
|
|
|
+ this._engine._loadFile(includeShaderUrl, function (fileContent) {
|
|
|
+ Effect.IncludesShadersStore[includeFile] = fileContent;
|
|
|
+ _this._processIncludes(returnValue, callback);
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ match = regex.exec(sourceCode);
|
|
|
+ }
|
|
|
+ callback(returnValue);
|
|
|
};
|
|
|
Effect.prototype._processPrecision = function (source) {
|
|
|
if (source.indexOf("precision highp float") === -1) {
|
|
@@ -803,8 +761,7 @@ var BABYLON;
|
|
|
this._engine.setTextureArray(this._samplers.indexOf(channel), this.getUniform(channel), textures);
|
|
|
};
|
|
|
/**
|
|
|
- * (Warning! setTextureFromPostProcessOutput may be desired instead)
|
|
|
- * Sets the input texture of the passed in post process to be input of this effect. (To use the output of the passed in post process use setTextureFromPostProcessOutput)
|
|
|
+ * Sets a texture to be the input of the specified post process. (To use the output, pass in the next post process in the pipeline)
|
|
|
* @param channel Name of the sampler variable.
|
|
|
* @param postProcess Post process to get the input texture from.
|
|
|
*/
|
|
@@ -812,7 +769,8 @@ var BABYLON;
|
|
|
this._engine.setTextureFromPostProcess(this._samplers.indexOf(channel), postProcess);
|
|
|
};
|
|
|
/**
|
|
|
- * Sets the output texture of the passed in post process to be input of this effect.
|
|
|
+ * (Warning! setTextureFromPostProcessOutput may be desired instead)
|
|
|
+ * Sets the input texture of the passed in post process to be input of this effect. (To use the output of the passed in post process use setTextureFromPostProcessOutput)
|
|
|
* @param channel Name of the sampler variable.
|
|
|
* @param postProcess Post process to get the output texture from.
|
|
|
*/
|
|
@@ -1264,8 +1222,6 @@ var BABYLON;
|
|
|
};
|
|
|
Effect._uniqueIdSeed = 0;
|
|
|
Effect._baseCache = {};
|
|
|
- Effect._sourceCache = {};
|
|
|
- // Statics
|
|
|
/**
|
|
|
* Store of each shader (The can be looked up using effect.key)
|
|
|
*/
|