diff --git a/Source/Renderer/Context.js b/Source/Renderer/Context.js index f2d23f2927c2..a893efa14980 100644 --- a/Source/Renderer/Context.js +++ b/Source/Renderer/Context.js @@ -929,11 +929,11 @@ define([ }); Context.prototype.replaceShaderProgram = function(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations) { - return this.shaderCache.replaceShaderProgram(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations); + return this._shaderCache.replaceShaderProgram(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations); }; Context.prototype.createShaderProgram = function(vertexShaderSource, fragmentShaderSource, attributeLocations) { - return this.shaderCache.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations); + return this._shaderCache.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations); }; function createBuffer(gl, bufferTarget, typedArrayOrSizeInBytes, usage) { diff --git a/Source/Renderer/ShaderCache.js b/Source/Renderer/ShaderCache.js index 1fc5b9977ada..7372497d8040 100644 --- a/Source/Renderer/ShaderCache.js +++ b/Source/Renderer/ShaderCache.js @@ -2,11 +2,13 @@ define([ '../Core/defined', '../Core/destroyObject', - './ShaderProgram' + './ShaderProgram', + './ShaderSource' ], function( defined, destroyObject, - ShaderProgram) { + ShaderProgram, + ShaderSource) { "use strict"; /** @@ -27,16 +29,15 @@ define([ *
* * @param {ShaderProgram} shaderProgram The shader program that is being reassigned. This can beundefined
.
- * @param {String} vertexShaderSource The GLSL source for the vertex shader.
- * @param {String} fragmentShaderSource The GLSL source for the fragment shader.
+ * @param {String|ShaderSource} vertexShaderSource The GLSL source for the vertex shader.
+ * @param {String|ShaderSource} fragmentShaderSource The GLSL source for the fragment shader.
* @param {Object} attributeLocations Indices for the attribute inputs to the vertex shader.
* @returns {ShaderProgram} The cached or newly created shader program.
*
* @see ShaderCache#getShaderProgram
*
* @example
- * this._shaderProgram = context.shaderCache.replaceShaderProgram(
- * this._shaderProgram, vs, fs, attributeLocations);
+ * this._shaderProgram = context.shaderCache.replaceShaderProgram(this._shaderProgram, vs, fs, attributeLocations);
*/
ShaderCache.prototype.replaceShaderProgram = function(shaderProgram, vertexShaderSource, fragmentShaderSource, attributeLocations) {
if (defined(shaderProgram)) {
@@ -46,8 +47,36 @@ define([
return this.getShaderProgram(vertexShaderSource, fragmentShaderSource, attributeLocations);
};
+ /**
+ * Returns a shader program from the cache, or creates and caches a new shader program,
+ * given the GLSL vertex and fragment shader source and attribute locations.
+ *
+ * @param {String|ShaderSource} vertexShaderSource The GLSL source for the vertex shader.
+ * @param {String|ShaderSource} fragmentShaderSource The GLSL source for the fragment shader.
+ * @param {Object} attributeLocations Indices for the attribute inputs to the vertex shader.
+ *
+ * @returns {ShaderProgram} The cached or newly created shader program.
+ */
ShaderCache.prototype.getShaderProgram = function(vertexShaderSource, fragmentShaderSource, attributeLocations) {
- var keyword = vertexShaderSource + fragmentShaderSource + JSON.stringify(attributeLocations);
+ // convert shaders which are provided as strings into ShaderSource objects
+ // because ShaderSource handles all the automatic including of built-in functions, etc.
+
+ if (typeof vertexShaderSource === 'string') {
+ vertexShaderSource = new ShaderSource({
+ sources : [vertexShaderSource]
+ });
+ }
+
+ if (typeof fragmentShaderSource === 'string') {
+ fragmentShaderSource = new ShaderSource({
+ sources : [fragmentShaderSource]
+ });
+ }
+
+ var vertexShaderText = vertexShaderSource.getCombinedShader(false);
+ var fragmentShaderText = fragmentShaderSource.getCombinedShader(true);
+
+ var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
var cachedShader;
if (this._shaders[keyword]) {
@@ -57,17 +86,25 @@ define([
delete this._shadersToRelease[keyword];
} else {
var context = this._context;
- var sp = new ShaderProgram(context._gl, context.logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations);
+ var shaderProgram = new ShaderProgram({
+ gl : context._gl,
+ logShaderCompilation : context.logShaderCompilation,
+ vertexShaderSource : vertexShaderSource,
+ vertexShaderText : vertexShaderText,
+ fragmentShaderSource : fragmentShaderSource,
+ fragmentShaderText : fragmentShaderText,
+ attributeLocations : attributeLocations
+ });
cachedShader = {
cache : this,
- shaderProgram : sp,
+ shaderProgram : shaderProgram,
keyword : keyword,
count : 0
};
// A shader can't be in more than one cache.
- sp._cachedShader = cachedShader;
+ shaderProgram._cachedShader = cachedShader;
this._shaders[keyword] = cachedShader;
}
diff --git a/Source/Renderer/ShaderProgram.js b/Source/Renderer/ShaderProgram.js
index af73d8d5e3ff..c8155a034476 100644
--- a/Source/Renderer/ShaderProgram.js
+++ b/Source/Renderer/ShaderProgram.js
@@ -9,7 +9,6 @@ define([
'../Core/Matrix3',
'../Core/Matrix4',
'../Core/RuntimeError',
- '../Shaders/Builtin/CzmBuiltins',
'./AutomaticUniforms'
], function(
defined,
@@ -21,7 +20,6 @@ define([
Matrix3,
Matrix4,
RuntimeError,
- CzmBuiltins,
AutomaticUniforms) {
"use strict";
/*global console*/
@@ -34,7 +32,7 @@ define([
scratchUniformMatrix3 = new Float32Array(9);
scratchUniformMatrix4 = new Float32Array(16);
}
- function setUniform (uniform) {
+ function setUniform(uniform) {
var gl = uniform._gl;
var location = uniform._location;
switch (uniform._activeUniform.type) {
@@ -340,10 +338,10 @@ define([
/**
* @private
*/
- var ShaderProgram = function(gl, logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations) {
- this._gl = gl;
- this._logShaderCompilation = logShaderCompilation;
- this._attributeLocations = attributeLocations;
+ var ShaderProgram = function(options) {
+ this._gl = options.gl;
+ this._logShaderCompilation = options.logShaderCompilation;
+ this._attributeLocations = options.attributeLocations;
this._program = undefined;
this._numberOfVertexAttributes = undefined;
@@ -352,15 +350,17 @@ define([
this._uniforms = undefined;
this._automaticUniforms = undefined;
this._manualUniforms = undefined;
- this._cachedShader = undefined; // Used by ShaderCache
+ this._cachedShader = undefined; // Used by ShaderCache
/**
* @private
*/
this.maximumTextureUnitIndex = undefined;
- this._vertexShaderSource = vertexShaderSource;
- this._fragmentShaderSource = fragmentShaderSource;
+ this._vertexShaderSource = options.vertexShaderSource;
+ this._vertexShaderText = options.vertexShaderText;
+ this._fragmentShaderSource = options.fragmentShaderSource;
+ this._fragmentShaderText = options.fragmentShaderText;
/**
* @private
@@ -370,36 +370,30 @@ define([
defineProperties(ShaderProgram.prototype, {
/**
- * GLSL source for the shader program's vertex shader. This is the version of
- * the source provided when the shader program was created, not the final
- * source provided to WebGL, which includes Cesium bulit-ins.
- *
+ * GLSL source for the shader program's vertex shader.
* @memberof ShaderProgram.prototype
*
- * @type {String}
+ * @type {ShaderSource}
* @readonly
*/
- vertexShaderSource: {
+ vertexShaderSource : {
get : function() {
return this._vertexShaderSource;
}
},
/**
- * GLSL source for the shader program's fragment shader. This is the version of
- * the source provided when the shader program was created, not the final
- * source provided to WebGL, which includes Cesium bulit-ins.
- *
+ * GLSL source for the shader program's fragment shader.
* @memberof ShaderProgram.prototype
*
- * @type {String}
+ * @type {ShaderSource}
* @readonly
*/
- fragmentShaderSource: {
+ fragmentShaderSource : {
get : function() {
return this._fragmentShaderSource;
}
},
- vertexAttributes: {
+ vertexAttributes : {
get : function() {
initialize(this);
return this._vertexAttributes;
@@ -411,13 +405,13 @@ define([
return this._numberOfVertexAttributes;
}
},
- allUniforms: {
+ allUniforms : {
get : function() {
initialize(this);
return this._uniformsByName;
}
},
- manualUniforms: {
+ manualUniforms : {
get : function() {
initialize(this);
return this._manualUniforms;
@@ -425,221 +419,9 @@ define([
}
});
- /**
- * For ShaderProgram testing
- * @private
- */
- ShaderProgram._czmBuiltinsAndUniforms = {};
-
- // combine automatic uniforms and Cesium built-ins
- for ( var builtinName in CzmBuiltins) {
- if (CzmBuiltins.hasOwnProperty(builtinName)) {
- ShaderProgram._czmBuiltinsAndUniforms[builtinName] = CzmBuiltins[builtinName];
- }
- }
- for ( var uniformName in AutomaticUniforms) {
- if (AutomaticUniforms.hasOwnProperty(uniformName)) {
- var uniform = AutomaticUniforms[uniformName];
- if (typeof uniform.getDeclaration === 'function') {
- ShaderProgram._czmBuiltinsAndUniforms[uniformName] = uniform.getDeclaration(uniformName);
- }
- }
- }
-
- function extractShaderVersion(source) {
- // This will fail if the first #version is actually in a comment.
- var index = source.indexOf('#version');
- if (index !== -1) {
- var newLineIndex = source.indexOf('\n', index);
-
- // We could throw an exception if there is not a new line after
- // #version, but the GLSL compiler will catch it.
- if (index !== -1) {
- // Extract #version directive, including the new line.
- var version = source.substring(index, newLineIndex + 1);
-
- // Comment out original #version directive so the line numbers
- // are not off by one. There can be only one #version directive
- // and it must appear at the top of the source, only preceded by
- // whitespace and comments.
- var modified = source.substring(0, index) + '//' + source.substring(index);
-
- return {
- version : version,
- source : modified
- };
- }
- }
-
- return {
- version : '', // defaults to #version 100
- source : source // no modifications required
- };
- }
-
- function getDependencyNode(name, glslSource, nodes) {
- var dependencyNode;
-
- // check if already loaded
- for (var i = 0; i < nodes.length; ++i) {
- if (nodes[i].name === name) {
- dependencyNode = nodes[i];
- }
- }
-
- if (!defined(dependencyNode)) {
- // strip doc comments so we don't accidentally try to determine a dependency for something found
- // in a comment
- var commentBlocks = glslSource.match(/\/\*\*[\s\S]*?\*\//gm);
- if (defined(commentBlocks) && commentBlocks !== null) {
- for (i = 0; i < commentBlocks.length; ++i) {
- var commentBlock = commentBlocks[i];
-
- // preserve the number of lines in the comment block so the line numbers will be correct when debugging shaders
- var numberOfLines = commentBlock.match(/\n/gm).length;
- var modifiedComment = '';
- for (var lineNumber = 0; lineNumber < numberOfLines; ++lineNumber) {
- if (lineNumber === 0) {
- modifiedComment += '// Comment replaced to prevent problems when determining dependencies on built-in functions\n';
- } else {
- modifiedComment += '//\n';
- }
- }
-
- glslSource = glslSource.replace(commentBlock, modifiedComment);
- }
- }
-
- // create new node
- dependencyNode = {
- name : name,
- glslSource : glslSource,
- dependsOn : [],
- requiredBy : [],
- evaluated : false
- };
- nodes.push(dependencyNode);
- }
-
- return dependencyNode;
- }
-
- function generateDependencies(currentNode, dependencyNodes) {
- if (currentNode.evaluated) {
- return;
- }
-
- currentNode.evaluated = true;
-
- // identify all dependencies that are referenced from this glsl source code
- var czmMatches = currentNode.glslSource.match(/\bczm_[a-zA-Z0-9_]*/g);
- if (defined(czmMatches) && czmMatches !== null) {
- // remove duplicates
- czmMatches = czmMatches.filter(function(elem, pos) {
- return czmMatches.indexOf(elem) === pos;
- });
-
- czmMatches.forEach(function(element, index, array) {
- if (element !== currentNode.name && ShaderProgram._czmBuiltinsAndUniforms.hasOwnProperty(element)) {
- var referencedNode = getDependencyNode(element, ShaderProgram._czmBuiltinsAndUniforms[element], dependencyNodes);
- currentNode.dependsOn.push(referencedNode);
- referencedNode.requiredBy.push(currentNode);
-
- // recursive call to find any dependencies of the new node
- generateDependencies(referencedNode, dependencyNodes);
- }
- });
- }
- }
-
- function sortDependencies(dependencyNodes) {
- var nodesWithoutIncomingEdges = [];
- var allNodes = [];
-
- while (dependencyNodes.length > 0) {
- var node = dependencyNodes.pop();
- allNodes.push(node);
-
- if (node.requiredBy.length === 0) {
- nodesWithoutIncomingEdges.push(node);
- }
- }
-
- while (nodesWithoutIncomingEdges.length > 0) {
- var currentNode = nodesWithoutIncomingEdges.shift();
-
- dependencyNodes.push(currentNode);
-
- for (var i = 0; i < currentNode.dependsOn.length; ++i) {
- // remove the edge from the graph
- var referencedNode = currentNode.dependsOn[i];
- var index = referencedNode.requiredBy.indexOf(currentNode);
- referencedNode.requiredBy.splice(index, 1);
-
- // if referenced node has no more incoming edges, add to list
- if (referencedNode.requiredBy.length === 0) {
- nodesWithoutIncomingEdges.push(referencedNode);
- }
- }
- }
-
- // if there are any nodes left with incoming edges, then there was a circular dependency somewhere in the graph
- var badNodes = [];
- for (var j = 0; j < allNodes.length; ++j) {
- if (allNodes[j].requiredBy.length !== 0) {
- badNodes.push(allNodes[j]);
- }
- }
- if (badNodes.length !== 0) {
- var message = 'A circular dependency was found in the following built-in functions/structs/constants: \n';
- for (j = 0; j < badNodes.length; ++j) {
- message = message + badNodes[j].name + '\n';
- }
- throw new DeveloperError(message);
- }
- }
-
- function getBuiltinsAndAutomaticUniforms(shaderSource) {
- // generate a dependency graph for builtin functions
- var dependencyNodes = [];
- var root = getDependencyNode('main', shaderSource, dependencyNodes);
- generateDependencies(root, dependencyNodes);
- sortDependencies(dependencyNodes);
-
- // Concatenate the source code for the function dependencies.
- // Iterate in reverse so that dependent items are declared before they are used.
- var builtinsSource = '';
- for (var i = dependencyNodes.length - 1; i >= 0; --i) {
- builtinsSource = builtinsSource + dependencyNodes[i].glslSource + '\n';
- }
-
- return builtinsSource.replace(root.glslSource, '');
- }
-
- function getFragmentShaderPrecision() {
- return '#ifdef GL_FRAGMENT_PRECISION_HIGH \n' +
- ' precision highp float; \n' +
- '#else \n' +
- ' precision mediump float; \n' +
- '#endif \n\n';
- }
-
- function createAndLinkProgram(gl, logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations) {
- var vsSourceVersioned = extractShaderVersion(vertexShaderSource);
- var fsSourceVersioned = extractShaderVersion(fragmentShaderSource);
-
- var vsSource =
- vsSourceVersioned.version +
- getBuiltinsAndAutomaticUniforms(vsSourceVersioned.source) +
- '\n#line 0\n' +
- vsSourceVersioned.source;
- var fsSource =
- fsSourceVersioned.version +
- getFragmentShaderPrecision() +
- getBuiltinsAndAutomaticUniforms(fsSourceVersioned.source) +
- '\n#line 0\n' +
- fsSourceVersioned.source;
- var log;
+ function createAndLinkProgram(gl, shader) {
+ var vsSource = shader._vertexShaderText;
+ var fsSource = shader._fragmentShaderText;
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vsSource);
@@ -656,6 +438,7 @@ define([
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
+ var attributeLocations = shader._attributeLocations;
if (defined(attributeLocations)) {
for ( var attribute in attributeLocations) {
if (attributeLocations.hasOwnProperty(attribute)) {
@@ -666,6 +449,7 @@ define([
gl.linkProgram(program);
+ var log;
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
// For performance, only check compile errors if there is a linker error.
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
@@ -688,6 +472,8 @@ define([
throw new RuntimeError('Program failed to link. Link log: ' + log);
}
+ var logShaderCompilation = shader._logShaderCompilation;
+
if (logShaderCompilation) {
log = gl.getShaderInfoLog(vertexShader);
if (defined(log) && (log.length > 0)) {
@@ -799,7 +585,7 @@ define([
} else {
locations = [];
value = [];
- for ( var j = 0; j < activeUniform.size; ++j) {
+ for (var j = 0; j < activeUniform.size; ++j) {
loc = gl.getUniformLocation(program, uniformName + '[' + j + ']');
// Workaround for IE 11.0.9. See above.
@@ -858,7 +644,7 @@ define([
}
var gl = shader._gl;
- var program = createAndLinkProgram(gl, shader._logShaderCompilation, shader.vertexShaderSource, shader.fragmentShaderSource, shader._attributeLocations);
+ var program = createAndLinkProgram(gl, shader);
var numberOfVertexAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
var uniforms = findUniforms(gl, program);
var partitionedUniforms = partitionUniforms(uniforms.uniformsByName);
diff --git a/Source/Renderer/ShaderSource.js b/Source/Renderer/ShaderSource.js
new file mode 100644
index 000000000000..5aeb12745860
--- /dev/null
+++ b/Source/Renderer/ShaderSource.js
@@ -0,0 +1,340 @@
+/*global define*/
+define([
+ '../Core/defaultValue',
+ '../Core/defined',
+ '../Core/defineProperties',
+ '../Core/destroyObject',
+ '../Core/DeveloperError',
+ '../Core/FeatureDetection',
+ '../Core/RuntimeError',
+ '../Shaders/Builtin/CzmBuiltins',
+ './AutomaticUniforms'
+ ], function(
+ defaultValue,
+ defined,
+ defineProperties,
+ destroyObject,
+ DeveloperError,
+ FeatureDetection,
+ RuntimeError,
+ CzmBuiltins,
+ AutomaticUniforms) {
+ "use strict";
+ /*global console*/
+
+ function removeComments(source) {
+ return source.replace(/\/\*\*[\s\S]*?\*\//gm, function(match) {
+ // preserve the number of lines in the comment block so the line numbers will be correct when debugging shaders
+ var numberOfLines = match.match(/\n/gm).length;
+ var replacement = '';
+ for (var lineNumber = 0; lineNumber < numberOfLines; ++lineNumber) {
+ replacement += '\n';
+ }
+ return replacement;
+ });
+ }
+
+ function getDependencyNode(name, glslSource, nodes) {
+ var dependencyNode;
+
+ // check if already loaded
+ for (var i = 0; i < nodes.length; ++i) {
+ if (nodes[i].name === name) {
+ dependencyNode = nodes[i];
+ }
+ }
+
+ if (!defined(dependencyNode)) {
+ // strip doc comments so we don't accidentally try to determine a dependency for something found
+ // in a comment
+ glslSource = removeComments(glslSource);
+
+ // create new node
+ dependencyNode = {
+ name : name,
+ glslSource : glslSource,
+ dependsOn : [],
+ requiredBy : [],
+ evaluated : false
+ };
+ nodes.push(dependencyNode);
+ }
+
+ return dependencyNode;
+ }
+
+ function generateDependencies(currentNode, dependencyNodes) {
+ if (currentNode.evaluated) {
+ return;
+ }
+
+ currentNode.evaluated = true;
+
+ // identify all dependencies that are referenced from this glsl source code
+ var czmMatches = currentNode.glslSource.match(/\bczm_[a-zA-Z0-9_]*/g);
+ if (defined(czmMatches) && czmMatches !== null) {
+ // remove duplicates
+ czmMatches = czmMatches.filter(function(elem, pos) {
+ return czmMatches.indexOf(elem) === pos;
+ });
+
+ czmMatches.forEach(function(element, index, array) {
+ if (element !== currentNode.name && ShaderSource._czmBuiltinsAndUniforms.hasOwnProperty(element)) {
+ var referencedNode = getDependencyNode(element, ShaderSource._czmBuiltinsAndUniforms[element], dependencyNodes);
+ currentNode.dependsOn.push(referencedNode);
+ referencedNode.requiredBy.push(currentNode);
+
+ // recursive call to find any dependencies of the new node
+ generateDependencies(referencedNode, dependencyNodes);
+ }
+ });
+ }
+ }
+
+ function sortDependencies(dependencyNodes) {
+ var nodesWithoutIncomingEdges = [];
+ var allNodes = [];
+
+ while (dependencyNodes.length > 0) {
+ var node = dependencyNodes.pop();
+ allNodes.push(node);
+
+ if (node.requiredBy.length === 0) {
+ nodesWithoutIncomingEdges.push(node);
+ }
+ }
+
+ while (nodesWithoutIncomingEdges.length > 0) {
+ var currentNode = nodesWithoutIncomingEdges.shift();
+
+ dependencyNodes.push(currentNode);
+
+ for (var i = 0; i < currentNode.dependsOn.length; ++i) {
+ // remove the edge from the graph
+ var referencedNode = currentNode.dependsOn[i];
+ var index = referencedNode.requiredBy.indexOf(currentNode);
+ referencedNode.requiredBy.splice(index, 1);
+
+ // if referenced node has no more incoming edges, add to list
+ if (referencedNode.requiredBy.length === 0) {
+ nodesWithoutIncomingEdges.push(referencedNode);
+ }
+ }
+ }
+
+ // if there are any nodes left with incoming edges, then there was a circular dependency somewhere in the graph
+ var badNodes = [];
+ for (var j = 0; j < allNodes.length; ++j) {
+ if (allNodes[j].requiredBy.length !== 0) {
+ badNodes.push(allNodes[j]);
+ }
+ }
+
+ if (badNodes.length !== 0) {
+ var message = 'A circular dependency was found in the following built-in functions/structs/constants: \n';
+ for (j = 0; j < badNodes.length; ++j) {
+ message = message + badNodes[j].name + '\n';
+ }
+ throw new DeveloperError(message);
+ }
+ }
+
+ function getBuiltinsAndAutomaticUniforms(shaderSource) {
+ // generate a dependency graph for builtin functions
+ var dependencyNodes = [];
+ var root = getDependencyNode('main', shaderSource, dependencyNodes);
+ generateDependencies(root, dependencyNodes);
+ sortDependencies(dependencyNodes);
+
+ // Concatenate the source code for the function dependencies.
+ // Iterate in reverse so that dependent items are declared before they are used.
+ var builtinsSource = '';
+ for (var i = dependencyNodes.length - 1; i >= 0; --i) {
+ builtinsSource = builtinsSource + dependencyNodes[i].glslSource + '\n';
+ }
+
+ return builtinsSource.replace(root.glslSource, '');
+ }
+
+ function combineShader(shaderSource, isFragmentShader) {
+ var i;
+ var length;
+
+ // Combine shader sources, generally for pseudo-polymorphism, e.g., czm_getMaterial.
+ var combinedSources = '';
+ var sources = shaderSource.sources;
+ if (defined(sources)) {
+ for (i = 0, length = sources.length; i < length; ++i) {
+ // #line needs to be on its own line.
+ combinedSources += '\n#line 0\n' + sources[i];
+ }
+ }
+
+ combinedSources = removeComments(combinedSources);
+
+ // Extract existing shader version from sources
+ var version;
+ combinedSources = combinedSources.replace(/#version\s+(.*?)\n/gm, function(match, group1) {
+ if (defined(version) && version !== group1) {
+ throw new DeveloperError('inconsistent versions found: ' + version + ' and ' + group1);
+ }
+ // Extract #version to put at the top
+ version = group1;
+
+ // Replace original #version directive with a new line so the line numbers
+ // are not off by one. There can be only one #version directive
+ // and it must appear at the top of the source, only preceded by
+ // whitespace and comments.
+ return '\n';
+ });
+
+ // Replace main() for picked if desired.
+ var pickColorQualifier = shaderSource.pickColorQualifier;
+ if (defined(pickColorQualifier)) {
+ combinedSources = combinedSources.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_old_main()');
+ combinedSources += '\
+\n' + pickColorQualifier + ' vec4 czm_pickColor;\n\
+void main()\n\
+{\n\
+ czm_old_main();\n\
+ if (gl_FragColor.a == 0.0) {\n\
+ discard;\n\
+ }\n\
+ gl_FragColor = czm_pickColor;\n\
+}';
+ }
+
+ // combine into single string
+ var result = '';
+
+ // #version must be first
+ // defaults to #version 100 if not specified
+ if (defined(version)) {
+ result = '#version ' + version;
+ }
+
+ if (isFragmentShader) {
+ result += '\
+#ifdef GL_FRAGMENT_PRECISION_HIGH\n\
+ precision highp float;\n\
+#else\n\
+ precision mediump float;\n\
+#endif\n\n';
+ }
+
+ // Prepend #defines for uber-shaders
+ var defines = shaderSource.defines;
+ if (defined(defines)) {
+ for (i = 0, length = defines.length; i < length; ++i) {
+ var define = defines[i];
+ if (define.length !== 0) {
+ result += '#define ' + define + '\n';
+ }
+ }
+ }
+
+ // append built-ins
+ if (shaderSource.includeBuiltIns) {
+ result += getBuiltinsAndAutomaticUniforms(combinedSources);
+ }
+
+ // reset line number
+ result += '\n#line 0\n';
+
+ // append actual source
+ result += combinedSources;
+
+ return result;
+ }
+
+ /**
+ * An object containing various inputs that will be combined to form a final GLSL shader string.
+ *
+ * @param {Object} [options] Object with the following properties:
+ * @param {String[]} [options.sources] An array of strings to combine containing GLSL code for the shader.
+ * @param {String[]} [options.defines] An array of strings containing GLSL identifiers to #define
.
+ * @param {String} [options.pickColorQualifier] The GLSL qualifier, uniform
or varying
, for the input czm_pickColor
. When defined, a pick fragment shader is generated.
+ * @param {Boolean} [options.includeBuiltIns=true] If true, referenced built-in functions will be included with the combined shader. Set to false if this shader will become a source in another shader, to avoid duplicating functions.
+ *
+ * @exception {DeveloperError} options.pickColorQualifier must be 'uniform' or 'varying'.
+ *
+ * @example
+ * // 1. Prepend #defines to a shader
+ * var source = new Cesium.ShaderSource({
+ * defines : ['WHITE'],
+ * so
+ * urces : ['void main() { \n#ifdef WHITE\n gl_FragColor = vec4(1.0); \n#else\n gl_FragColor = vec4(0.0); \n#endif\n }']
+ * });
+ *
+ * // 2. Modify a fragment shader for picking
+ * var source = new Cesium.ShaderSource({
+ * sources : ['void main() { gl_FragColor = vec4(1.0); }'],
+ * pickColorQualifier : 'uniform'
+ * });
+ *
+ * @private
+ */
+ var ShaderSource = function(options) {
+ options = defaultValue(options, defaultValue.EMPTY_OBJECT);
+ var pickColorQualifier = options.pickColorQualifier;
+
+ //>>includeStart('debug', pragmas.debug);
+ if (defined(pickColorQualifier) && pickColorQualifier !== 'uniform' && pickColorQualifier !== 'varying') {
+ throw new DeveloperError('options.pickColorQualifier must be \'uniform\' or \'varying\'.');
+ }
+ //>>includeEnd('debug');
+
+ this.defines = defined(options.defines) ? options.defines.slice(0) : [];
+ this.sources = defined(options.sources) ? options.sources.slice(0) : [];
+ this.pickColorQualifier = pickColorQualifier;
+ this.includeBuiltIns = defaultValue(options.includeBuiltIns, true);
+ };
+
+ ShaderSource.prototype.clone = function() {
+ return new ShaderSource({
+ sources : this.sources,
+ defines : this.defines,
+ pickColorQuantifier : this.pickColorQualifier,
+ includeBuiltIns : this.includeBuiltIns
+ });
+ };
+
+ /**
+ * Create a single string containing the full, combined shader with all dependencies and defines.
+ *
+ * @param {Boolean} isFragmentShader True if this shader will be a fragment shader.
+ * @returns {String} The combined shader string.
+ */
+ ShaderSource.prototype.getCombinedShader = function(isFragmentShader) {
+ //>>includeStart('debug', pragmas.debug);
+ if (!defined(isFragmentShader)) {
+ throw new DeveloperError('isFragmentShader is required.');
+ }
+ //>>includeEnd('debug');
+
+ return combineShader(this, isFragmentShader);
+ };
+
+ /**
+ * For ShaderProgram testing
+ * @private
+ */
+ ShaderSource._czmBuiltinsAndUniforms = {};
+
+ // combine automatic uniforms and Cesium built-ins
+ for ( var builtinName in CzmBuiltins) {
+ if (CzmBuiltins.hasOwnProperty(builtinName)) {
+ ShaderSource._czmBuiltinsAndUniforms[builtinName] = CzmBuiltins[builtinName];
+ }
+ }
+ for ( var uniformName in AutomaticUniforms) {
+ if (AutomaticUniforms.hasOwnProperty(uniformName)) {
+ var uniform = AutomaticUniforms[uniformName];
+ if (typeof uniform.getDeclaration === 'function') {
+ ShaderSource._czmBuiltinsAndUniforms[uniformName] = uniform.getDeclaration(uniformName);
+ }
+ }
+ }
+
+ return ShaderSource;
+});
diff --git a/Source/Renderer/createShaderSource.js b/Source/Renderer/createShaderSource.js
deleted file mode 100644
index 6d4eeac8cda6..000000000000
--- a/Source/Renderer/createShaderSource.js
+++ /dev/null
@@ -1,104 +0,0 @@
-/*global define*/
-define([
- '../Core/defaultValue',
- '../Core/defined',
- '../Core/DeveloperError'
- ], function(
- defaultValue,
- defined,
- DeveloperError) {
- "use strict";
-
- /**
- * Creates a GLSL shader source string by sending the input through three stages:
- * #define
statements are created from options.defines
.options.sources
are combined with line numbers preserved using #line
.options.pickColorQualifier
is defined.
- * The returned fragment shader source sets gl_FragColor
to a new vec4
uniform or varying,
- * czm_pickColor
, but still discards if the original fragment shader discards or outputs an alpha of 0.0.
- * This allows correct picking when a material contains transparent parts.
- * #define
.
- * @param {String[]} [options.sources] An array of strings to combine containing GLSL code for the shader.
- * @param {String} [options.pickColorQualifier] The GLSL qualifier, uniform
or varying
, for the input czm_pickColor
. When defined, a pick fragment shader is generated.
- * @returns {String} The generated GLSL shader source.
- *
- * @exception {DeveloperError} options.pickColorQualifier must be 'uniform' or 'varying'.
- *
- * @example
- * // 1. Prepend #defines to a shader
- * var source = Cesium.createShaderSource({
- * defines : ['WHITE'],
- * sources : ['void main() { \n#ifdef WHITE\n gl_FragColor = vec4(1.0); \n#else\n gl_FragColor = vec4(0.0); \n#endif\n }']
- * });
- *
- * // 2. Modify a fragment shader for picking
- * var source = createShaderSource({
- * sources : ['void main() { gl_FragColor = vec4(1.0); }'],
- * pickColorQualifier : 'uniform'
- * });
- *
- * @private
- */
- function createShaderSource(options) {
- options = defaultValue(options, defaultValue.EMPTY_OBJECT);
- var defines = options.defines;
- var sources = options.sources;
- var pickColorQualifier = options.pickColorQualifier;
-
- if (defined(pickColorQualifier) && (pickColorQualifier !== 'uniform') && (pickColorQualifier !== 'varying')) {
- throw new DeveloperError('options.pickColorQualifier must be \'uniform\' or \'varying\'.');
- }
-
- var source = '';
- var i;
- var length;
-
- // Stage 1. Prepend #defines for uber-shaders
- if (defined(defines) && defines.length > 0) {
- length = defines.length;
- for (i = 0; i < length; ++i) {
- if (defines[i].length !== 0) {
- source += '#define ' + defines[i] + '\n';
- }
- }
- }
-
- // Stage 2. Combine shader sources, generally for pseudo-polymorphism, e.g., czm_getMaterial.
- if (defined(sources) && sources.length > 0) {
- length = sources.length;
- for (i = 0; i < length; ++i) {
- // #line needs to be on its own line.
- source += '\n#line 0\n' + sources[i];
- }
- }
-
- // Stage 3. Replace main() for picked if desired.
- if (defined(pickColorQualifier)) {
- var renamedFS = source.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_old_main()');
- var pickMain =
- pickColorQualifier + ' vec4 czm_pickColor; \n' +
- 'void main() \n' +
- '{ \n' +
- ' czm_old_main(); \n' +
- ' if (gl_FragColor.a == 0.0) { \n' +
- ' discard; \n' +
- ' } \n' +
- ' gl_FragColor = czm_pickColor; \n' +
- '}';
-
- source = renamedFS + '\n' + pickMain;
- }
-
- return source;
- }
-
- return createShaderSource;
-});
diff --git a/Source/Scene/Appearance.js b/Source/Scene/Appearance.js
index dda8b50d8951..f8c424be2c9f 100644
--- a/Source/Scene/Appearance.js
+++ b/Source/Scene/Appearance.js
@@ -4,7 +4,7 @@ define([
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
- '../Renderer/createShaderSource',
+ '../Renderer/ShaderSource',
'./BlendingState',
'./CullFace'
], function(
@@ -12,7 +12,7 @@ define([
defaultValue,
defined,
defineProperties,
- createShaderSource,
+ ShaderSource,
BlendingState,
CullFace) {
"use strict";
@@ -139,10 +139,28 @@ define([
* @returns {String} The full GLSL fragment shader source.
*/
Appearance.prototype.getFragmentShaderSource = function() {
- return createShaderSource({
- defines : [this.flat ? 'FLAT' : '', this.faceForward ? 'FACE_FORWARD' : ''],
- sources : [defined(this.material) ? this.material.shaderSource : '', this.fragmentShaderSource]
+ var defines = [];
+ if (this.flat) {
+ defines.push('FLAT');
+ }
+ if (this.faceForward) {
+ defines.push('FACE_FORWARD');
+ }
+
+ var sources = [];
+ if (defined(this.material)) {
+ sources.push(this.material.shaderSource);
+ }
+ sources.push(this.fragmentShaderSource);
+
+ // includeBuiltIns is false because the primitive will create its own ShaderSource containing our source
+ var shaderSource = new ShaderSource({
+ defines : defines,
+ sources : sources,
+ includeBuiltIns : false
});
+
+ return shaderSource.getCombinedShader(true);
};
/**
diff --git a/Source/Scene/BillboardCollection.js b/Source/Scene/BillboardCollection.js
index bb155c5d7b3e..49fd09342c23 100644
--- a/Source/Scene/BillboardCollection.js
+++ b/Source/Scene/BillboardCollection.js
@@ -14,8 +14,8 @@ define([
'../Core/IndexDatatype',
'../Core/Matrix4',
'../Renderer/BufferUsage',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../Renderer/VertexArrayFacade',
'../Shaders/BillboardCollectionFS',
'../Shaders/BillboardCollectionVS',
@@ -40,8 +40,8 @@ define([
IndexDatatype,
Matrix4,
BufferUsage,
- createShaderSource,
DrawCommand,
+ ShaderSource,
VertexArrayFacade,
BillboardCollectionFS,
BillboardCollectionVS,
@@ -1213,6 +1213,9 @@ define([
var vaLength;
var command;
var j;
+ var defines;
+ var vs;
+ var fs;
if (pass.render) {
var colorList = this._colorCommands;
@@ -1231,17 +1234,30 @@ define([
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistance) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistance) ||
(this._shaderPixelOffsetScaleByDistance && !this._compiledShaderPixelOffsetScaleByDistance)) {
- this._sp = context.replaceShaderProgram(
- this._sp,
- createShaderSource({
- defines : [this._shaderRotation ? 'ROTATION' : '',
- this._shaderScaleByDistance ? 'EYE_DISTANCE_SCALING' : '',
- this._shaderTranslucencyByDistance ? 'EYE_DISTANCE_TRANSLUCENCY' : '',
- this._shaderPixelOffsetScaleByDistance ? 'EYE_DISTANCE_PIXEL_OFFSET' : ''],
- sources : [BillboardCollectionVS]
- }),
- BillboardCollectionFS,
- attributeLocations);
+
+ defines = [];
+ if (this._shaderRotation) {
+ defines.push('ROTATION');
+ }
+ if (this._shaderScaleByDistance) {
+ defines.push('EYE_DISTANCE_SCALING');
+ }
+ if (this._shaderTranslucencyByDistance) {
+ defines.push('EYE_DISTANCE_TRANSLUCENCY');
+ }
+ if (this._shaderPixelOffsetScaleByDistance) {
+ defines.push('EYE_DISTANCE_PIXEL_OFFSET');
+ }
+
+ vs = new ShaderSource({
+ defines : defines,
+ sources : [BillboardCollectionVS]
+ });
+ fs = new ShaderSource({
+ sources : [BillboardCollectionFS]
+ });
+
+ this._sp = context.replaceShaderProgram(this._sp, vs, fs, attributeLocations);
this._compiledShaderRotation = this._shaderRotation;
this._compiledShaderScaleByDistance = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistance = this._shaderTranslucencyByDistance;
@@ -1274,7 +1290,6 @@ define([
}
}
-
if (picking) {
var pickList = this._pickCommands;
@@ -1283,21 +1298,31 @@ define([
(this._shaderScaleByDistance && !this._compiledShaderScaleByDistancePick) ||
(this._shaderTranslucencyByDistance && !this._compiledShaderTranslucencyByDistancePick) ||
(this._shaderPixelOffsetScaleByDistance && !this._compiledShaderPixelOffsetScaleByDistancePick)) {
- this._spPick = context.replaceShaderProgram(
- this._spPick,
- createShaderSource({
- defines : ['RENDER_FOR_PICK',
- this._shaderRotation ? 'ROTATION' : '',
- this._shaderScaleByDistance ? 'EYE_DISTANCE_SCALING' : '',
- this._shaderTranslucencyByDistance ? 'EYE_DISTANCE_TRANSLUCENCY' : '',
- this._shaderPixelOffsetScaleByDistance ? 'EYE_DISTANCE_PIXEL_OFFSET' : ''],
- sources : [BillboardCollectionVS]
- }),
- createShaderSource({
- defines : ['RENDER_FOR_PICK'],
- sources : [BillboardCollectionFS]
- }),
- attributeLocations);
+
+ defines = ['RENDER_FOR_PICK'];
+ if (this._shaderRotation) {
+ defines.push('ROTATION');
+ }
+ if (this._shaderScaleByDistance) {
+ defines.push('EYE_DISTANCE_SCALING');
+ }
+ if (this._shaderTranslucencyByDistance) {
+ defines.push('EYE_DISTANCE_TRANSLUCENCY');
+ }
+ if (this._shaderPixelOffsetScaleByDistance) {
+ defines.push('EYE_DISTANCE_PIXEL_OFFSET');
+ }
+
+ vs = new ShaderSource({
+ defines : defines,
+ sources : [BillboardCollectionVS]
+ });
+ fs = new ShaderSource({
+ defines : ['RENDER_FOR_PICK'],
+ sources : [BillboardCollectionFS]
+ });
+
+ this._spPick = context.replaceShaderProgram(this._spPick, vs, fs, attributeLocations);
this._compiledShaderRotationPick = this._shaderRotation;
this._compiledShaderScaleByDistancePick = this._shaderScaleByDistance;
this._compiledShaderTranslucencyByDistancePick = this._shaderTranslucencyByDistance;
diff --git a/Source/Scene/EllipsoidPrimitive.js b/Source/Scene/EllipsoidPrimitive.js
index c6b3ec367b7f..08db5b8c1860 100644
--- a/Source/Scene/EllipsoidPrimitive.js
+++ b/Source/Scene/EllipsoidPrimitive.js
@@ -11,8 +11,8 @@ define([
'../Core/Matrix4',
'../Core/VertexFormat',
'../Renderer/BufferUsage',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../Shaders/EllipsoidFS',
'../Shaders/EllipsoidVS',
'./BlendingState',
@@ -32,8 +32,8 @@ define([
Matrix4,
VertexFormat,
BufferUsage,
- createShaderSource,
DrawCommand,
+ ShaderSource,
EllipsoidFS,
EllipsoidVS,
BlendingState,
@@ -347,17 +347,28 @@ define([
var colorCommand = this._colorCommand;
- // Recompile shader when material, lighting, or transluceny changes
+ var defines;
+
+ // Recompile shader when material, lighting, or translucency changes
if (materialChanged || lightingChanged || translucencyChanged) {
- var colorFS = createShaderSource({
- defines : [
- this.onlySunLighting ? 'ONLY_SUN_LIGHTING' : '',
- (!translucent && context.fragmentDepth) ? 'WRITE_DEPTH' : ''
- ],
- sources : [this.material.shaderSource, EllipsoidFS] }
- );
+ var colorVS = new ShaderSource({
+ sources : [EllipsoidVS]
+ });
+
+ defines = [];
+ if (this.onlySunLighting) {
+ defines.push('ONLY_SUN_LIGHTING');
+ }
+ if (!translucent && context.fragmentDepth) {
+ defines.push('WRITE_DEPTH');
+ }
- this._sp = context.replaceShaderProgram(this._sp, EllipsoidVS, colorFS, attributeLocations);
+ var colorFS = new ShaderSource({
+ defines : defines,
+ sources : [this.material.shaderSource, EllipsoidFS]
+ });
+
+ this._sp = context.replaceShaderProgram(this._sp, colorVS, colorFS, attributeLocations);
colorCommand.vertexArray = this._va;
colorCommand.renderState = this._rs;
@@ -391,16 +402,25 @@ define([
// Recompile shader when material changes
if (materialChanged || lightingChanged || !defined(this._pickSP)) {
- var pickFS = createShaderSource({
- defines : [
- this.onlySunLighting ? 'ONLY_SUN_LIGHTING' : '',
- (!translucent && context.fragmentDepth) ? 'WRITE_DEPTH' : ''
- ],
+ var pickVS = new ShaderSource({
+ sources : [EllipsoidVS]
+ });
+
+ defines = [];
+ if (this.onlySunLighting) {
+ defines.push('ONLY_SUN_LIGHTING');
+ }
+ if (!translucent && context.fragmentDepth) {
+ defines.push('WRITE_DEPTH');
+ }
+
+ var pickFS = new ShaderSource({
+ defines : defines,
sources : [this.material.shaderSource, EllipsoidFS],
pickColorQualifier : 'uniform'
});
- this._pickSP = context.replaceShaderProgram(this._pickSP, EllipsoidVS, pickFS, attributeLocations);
+ this._pickSP = context.replaceShaderProgram(this._pickSP, pickVS, pickFS, attributeLocations);
pickCommand.vertexArray = this._va;
pickCommand.renderState = this._rs;
diff --git a/Source/Scene/FXAA.js b/Source/Scene/FXAA.js
index 403dd4fd8d1b..16accc2605bb 100644
--- a/Source/Scene/FXAA.js
+++ b/Source/Scene/FXAA.js
@@ -6,7 +6,7 @@ define([
'../Core/destroyObject',
'../Core/PixelFormat',
'../Renderer/ClearCommand',
- '../Renderer/createShaderSource',
+ '../Renderer/ShaderSource',
'../Renderer/PixelDatatype',
'../Renderer/RenderbufferFormat',
'../Shaders/PostProcessFilters/FXAA'
@@ -17,7 +17,7 @@ define([
destroyObject,
PixelFormat,
ClearCommand,
- createShaderSource,
+ ShaderSource,
PixelDatatype,
RenderbufferFormat,
FXAAFS) {
@@ -104,11 +104,7 @@ define([
}
if (!defined(this._command)) {
- var fs = createShaderSource({
- sources : [FXAAFS]
- });
-
- this._command = context.createViewportQuadCommand(fs, {
+ this._command = context.createViewportQuadCommand(FXAAFS, {
renderState : context.createRenderState(),
owner : this
});
diff --git a/Source/Scene/Globe.js b/Source/Scene/Globe.js
index 5318c8021fb1..c78d5143eb07 100644
--- a/Source/Scene/Globe.js
+++ b/Source/Scene/Globe.js
@@ -31,8 +31,8 @@ define([
'../Core/Transforms',
'../Renderer/BufferUsage',
'../Renderer/ClearCommand',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../Shaders/GlobeFS',
'../Shaders/GlobeFSDepth',
'../Shaders/GlobeFSPole',
@@ -80,8 +80,8 @@ define([
Transforms,
BufferUsage,
ClearCommand,
- createShaderSource,
DrawCommand,
+ ShaderSource,
GlobeFS,
GlobeFSDepth,
GlobeFSPole,
@@ -925,12 +925,21 @@ define([
}
}
- surfaceShaderSet.baseVertexShaderString = createShaderSource({
+ // Firefox 33-34 has a regression that prevents the CORDIC implementation from compiling
+ // https://github.com/AnalyticalGraphicsInc/cesium/issues/2197
+ if (FeatureDetection.isFirefox()) {
+ var firefoxVersion = FeatureDetection.firefoxVersion();
+ if (firefoxVersion[0] >= 33 && firefoxVersion[0] <= 34) {
+ shaderDefines.push('DISABLE_CORDIC');
+ }
+ }
+
+ surfaceShaderSet.baseVertexShaderSource = new ShaderSource({
defines : shaderDefines,
sources : [GlobeVS, getPositionMode, get2DYPositionFraction]
});
- surfaceShaderSet.baseFragmentShaderString = createShaderSource({
+ surfaceShaderSet.baseFragmentShaderSource = new ShaderSource({
defines : shaderDefines,
sources : [GlobeFS]
});
diff --git a/Source/Scene/GlobeSurfaceShaderSet.js b/Source/Scene/GlobeSurfaceShaderSet.js
index 45bce6953040..ca5a91742bb6 100644
--- a/Source/Scene/GlobeSurfaceShaderSet.js
+++ b/Source/Scene/GlobeSurfaceShaderSet.js
@@ -16,8 +16,8 @@ define([
* @private
*/
function GlobeSurfaceShaderSet() {
- this.baseVertexShaderString = undefined;
- this.baseFragmentShaderString = undefined;
+ this.baseVertexShaderSource = undefined;
+ this.baseFragmentShaderSource = undefined;
this._attributeLocations = terrainAttributeLocations;
this._shaders = {};
}
@@ -68,39 +68,57 @@ define([
var key = getShaderKey(textureCount, applyBrightness, applyContrast, applyHue, applySaturation, applyGamma, applyAlpha);
var shader = this._shaders[key];
if (!defined(shader)) {
- var vs = this.baseVertexShaderString;
- var fs =
- (applyBrightness ? '#define APPLY_BRIGHTNESS\n' : '') +
- (applyContrast ? '#define APPLY_CONTRAST\n' : '') +
- (applyHue ? '#define APPLY_HUE\n' : '') +
- (applySaturation ? '#define APPLY_SATURATION\n' : '') +
- (applyGamma ? '#define APPLY_GAMMA\n' : '') +
- (applyAlpha ? '#define APPLY_ALPHA\n' : '') +
- '#define TEXTURE_UNITS ' + textureCount + '\n' +
- this.baseFragmentShaderString + '\n' +
- 'vec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates)\n' +
- '{\n' +
- ' vec4 color = initialColor;\n';
+ var vs = this.baseVertexShaderSource;
+
+ var fs = this.baseFragmentShaderSource.clone();
+ fs.defines.push('TEXTURE_UNITS ' + textureCount);
+
+ if (applyBrightness) {
+ fs.defines.push('APPLY_BRIGHTNESS');
+ }
+ if (applyContrast) {
+ fs.defines.push('APPLY_CONTRAST');
+ }
+ if (applyHue) {
+ fs.defines.push('APPLY_HUE');
+ }
+ if (applySaturation) {
+ fs.defines.push('APPLY_SATURATION');
+ }
+ if (applyGamma) {
+ fs.defines.push('APPLY_GAMMA');
+ }
+ if (applyAlpha) {
+ fs.defines.push('APPLY_ALPHA');
+ }
+
+ var computeDayColor = '\
+vec4 computeDayColor(vec4 initialColor, vec2 textureCoordinates)\n\
+{\n\
+ vec4 color = initialColor;\n';
for (var i = 0; i < textureCount; ++i) {
- fs +=
- 'color = sampleAndBlend(\n' +
- ' color,\n' +
- ' u_dayTextures[' + i + '],\n' +
- ' textureCoordinates,\n' +
- ' u_dayTextureTexCoordsRectangle[' + i + '],\n' +
- ' u_dayTextureTranslationAndScale[' + i + '],\n' +
- (applyAlpha ? ' u_dayTextureAlpha[' + i + '],\n' : '1.0,\n') +
- (applyBrightness ? ' u_dayTextureBrightness[' + i + '],\n' : '0.0,\n') +
- (applyContrast ? ' u_dayTextureContrast[' + i + '],\n' : '0.0,\n') +
- (applyHue ? ' u_dayTextureHue[' + i + '],\n' : '0.0,\n') +
- (applySaturation ? ' u_dayTextureSaturation[' + i + '],\n' : '0.0,\n') +
- (applyGamma ? ' u_dayTextureOneOverGamma[' + i + ']);\n' : '0.0);\n') ;
+ computeDayColor += '\
+ color = sampleAndBlend(\n\
+ color,\n\
+ u_dayTextures[' + i + '],\n\
+ textureCoordinates,\n\
+ u_dayTextureTexCoordsRectangle[' + i + '],\n\
+ u_dayTextureTranslationAndScale[' + i + '],\n\
+ ' + (applyAlpha ? 'u_dayTextureAlpha[' + i + ']' : '1.0') + ',\n\
+ ' + (applyBrightness ? 'u_dayTextureBrightness[' + i + ']' : '0.0') + ',\n\
+ ' + (applyContrast ? 'u_dayTextureContrast[' + i + ']' : '0.0') + ',\n\
+ ' + (applyHue ? 'u_dayTextureHue[' + i + ']' : '0.0') + ',\n\
+ ' + (applySaturation ? 'u_dayTextureSaturation[' + i + ']' : '0.0') + ',\n\
+ ' + (applyGamma ? 'u_dayTextureOneOverGamma[' + i + ']' : '0.0') + '\n\
+ );\n';
}
- fs +=
- ' return color;\n' +
- '}';
+ computeDayColor += '\
+ return color;\n\
+}';
+
+ fs.sources.push(computeDayColor);
shader = context.createShaderProgram(vs, fs, this._attributeLocations);
this._shaders[key] = shader;
diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js
index 033372ed0e03..0052562cd560 100644
--- a/Source/Scene/ImageryLayer.js
+++ b/Source/Scene/ImageryLayer.js
@@ -23,6 +23,7 @@ define([
'../Renderer/ClearCommand',
'../Renderer/DrawCommand',
'../Renderer/MipmapHint',
+ '../Renderer/ShaderSource',
'../Renderer/TextureMagnificationFilter',
'../Renderer/TextureMinificationFilter',
'../Renderer/TextureWrap',
@@ -56,6 +57,7 @@ define([
ClearCommand,
DrawCommand,
MipmapHint,
+ ShaderSource,
TextureMagnificationFilter,
TextureMinificationFilter,
TextureWrap,
@@ -831,10 +833,23 @@ define([
bufferUsage : BufferUsage.STATIC_DRAW
});
- reproject.shaderProgram = context.createShaderProgram(
- ReprojectWebMercatorVS,
- ReprojectWebMercatorFS,
- reprojectAttribInds);
+ var vs = new ShaderSource({
+ sources : [ReprojectWebMercatorVS]
+ });
+ var fs = new ShaderSource({
+ sources : [ReprojectWebMercatorFS]
+ });
+
+ // Firefox 33-34 has a regression that prevents the CORDIC implementation from compiling
+ // https://github.com/AnalyticalGraphicsInc/cesium/issues/2197
+ if (FeatureDetection.isFirefox()) {
+ var firefoxVersion = FeatureDetection.firefoxVersion();
+ if (firefoxVersion[0] >= 33 && firefoxVersion[0] <= 34) {
+ vs.defines.push('DISABLE_CORDIC');
+ }
+ }
+
+ reproject.shaderProgram = context.createShaderProgram(vs, fs, reprojectAttribInds);
var maximumSupportedAnisotropy = context.maximumTextureFilterAnisotropy;
reproject.sampler = context.createSampler({
diff --git a/Source/Scene/Model.js b/Source/Scene/Model.js
index bb86dd83e151..ef98fa633a58 100644
--- a/Source/Scene/Model.js
+++ b/Source/Scene/Model.js
@@ -24,8 +24,8 @@ define([
'../Core/Queue',
'../Core/RuntimeError',
'../Renderer/BufferUsage',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../Renderer/TextureMinificationFilter',
'../Renderer/TextureWrap',
'../ThirdParty/gltfDefaults',
@@ -63,8 +63,8 @@ define([
Queue,
RuntimeError,
BufferUsage,
- createShaderSource,
DrawCommand,
+ ShaderSource,
TextureMinificationFilter,
TextureWrap,
gltfDefaults,
@@ -967,7 +967,7 @@ define([
if (model.allowPicking) {
// PERFORMANCE_IDEA: Can optimize this shader with a glTF hint. https://github.com/KhronosGroup/glTF/issues/181
- var pickFS = createShaderSource({
+ var pickFS = new ShaderSource({
sources : [fs],
pickColorQualifier : 'uniform'
});
diff --git a/Source/Scene/OIT.js b/Source/Scene/OIT.js
index d2c0c46ee3ec..868c110b46de 100644
--- a/Source/Scene/OIT.js
+++ b/Source/Scene/OIT.js
@@ -5,9 +5,9 @@ define([
'../Core/destroyObject',
'../Core/PixelFormat',
'../Renderer/ClearCommand',
- '../Renderer/createShaderSource',
'../Renderer/PixelDatatype',
'../Renderer/RenderState',
+ '../Renderer/ShaderSource',
'../Shaders/AdjustTranslucentFS',
'../Shaders/CompositeOITFS',
'./BlendEquation',
@@ -18,9 +18,9 @@ define([
destroyObject,
PixelFormat,
ClearCommand,
- createShaderSource,
PixelDatatype,
RenderState,
+ ShaderSource,
AdjustTranslucentFS,
CompositeOITFS,
BlendEquation,
@@ -218,8 +218,12 @@ define([
var uniformMap;
if (!defined(this._compositeCommand)) {
- fs = createShaderSource({
- defines : [this._translucentMRTSupport ? 'MRT' : ''],
+ var defines = [];
+ if (this._translucentMRTSupport) {
+ defines.push('MRT');
+ }
+ fs = new ShaderSource({
+ defines : defines,
sources : [CompositeOITFS]
});
@@ -243,7 +247,7 @@ define([
if (!defined(this._adjustTranslucentCommand)) {
if (this._translucentMRTSupport) {
- fs = createShaderSource({
+ fs = new ShaderSource({
defines : ['MRT'],
sources : [AdjustTranslucentFS]
});
@@ -263,7 +267,7 @@ define([
owner : this
});
} else if (this._translucentMultipassSupport) {
- fs = createShaderSource({
+ fs = new ShaderSource({
sources : [AdjustTranslucentFS]
});
@@ -312,7 +316,8 @@ define([
};
var translucentColorBlend = {
- enabled : true,color : new Color(0.0, 0.0, 0.0, 0.0),
+ enabled : true,
+ color : new Color(0.0, 0.0, 0.0, 0.0),
equationRgb : BlendEquation.ADD,
equationAlpha : BlendEquation.ADD,
functionSourceRgb : BlendFunction.ONE,
@@ -322,7 +327,8 @@ define([
};
var translucentAlphaBlend = {
- enabled : true,color : new Color(0.0, 0.0, 0.0, 0.0),
+ enabled : true,
+ color : new Color(0.0, 0.0, 0.0, 0.0),
equationRgb : BlendEquation.ADD,
equationAlpha : BlendEquation.ADD,
functionSourceRgb : BlendFunction.ZERO,
@@ -379,32 +385,37 @@ define([
var shader = cache[id];
if (!defined(shader)) {
var attributeLocations = shaderProgram._attributeLocations;
- var vs = shaderProgram.vertexShaderSource;
- var fs = shaderProgram.fragmentShaderSource;
- var renamedFS = fs.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_translucent_main()');
- renamedFS = renamedFS.replace(/gl_FragColor/g, 'czm_gl_FragColor');
- renamedFS = renamedFS.replace(/\bdiscard\b/g, 'czm_discard = true');
- renamedFS = renamedFS.replace(/czm_phong/g, 'czm_translucentPhong');
+ var fs = shaderProgram.fragmentShaderSource.clone();
+
+ fs.sources = fs.sources.map(function(source) {
+ source = source.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_translucent_main()');
+ source = source.replace(/gl_FragColor/g, 'czm_gl_FragColor');
+ source = source.replace(/\bdiscard\b/g, 'czm_discard = true');
+ source = source.replace(/czm_phong/g, 'czm_translucentPhong');
+ return source;
+ });
// Discarding the fragment in main is a workaround for ANGLE D3D9
// shader compilation errors.
- var newSourceFS =
- (source.indexOf('gl_FragData') !== -1 ? '#extension GL_EXT_draw_buffers : enable \n' : '') +
- 'vec4 czm_gl_FragColor;\n' +
- 'bool czm_discard = false;\n' +
- renamedFS + '\n\n' +
- 'void main()\n' +
- '{\n' +
- ' czm_translucent_main();\n' +
- ' if (czm_discard)\n' +
- ' {\n' +
- ' discard;\n' +
- ' }\n' +
- source +
- '}\n';
-
- shader = context.createShaderProgram(vs, newSourceFS, attributeLocations);
+
+ fs.sources.splice(0, 0,
+ (source.indexOf('gl_FragData') !== -1 ? '#extension GL_EXT_draw_buffers : enable \n' : '') +
+ 'vec4 czm_gl_FragColor;\n' +
+ 'bool czm_discard = false;\n');
+
+ fs.sources.push(
+ 'void main()\n' +
+ '{\n' +
+ ' czm_translucent_main();\n' +
+ ' if (czm_discard)\n' +
+ ' {\n' +
+ ' discard;\n' +
+ ' }\n' +
+ source +
+ '}\n');
+
+ shader = context.createShaderProgram(shaderProgram.vertexShaderSource, fs, attributeLocations);
cache[id] = shader;
}
diff --git a/Source/Scene/PolylineCollection.js b/Source/Scene/PolylineCollection.js
index dbb4c39469a5..08224a3b3686 100644
--- a/Source/Scene/PolylineCollection.js
+++ b/Source/Scene/PolylineCollection.js
@@ -16,8 +16,8 @@ define([
'../Core/Math',
'../Core/Matrix4',
'../Renderer/BufferUsage',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../Shaders/PolylineCommon',
'../Shaders/PolylineFS',
'../Shaders/PolylineVS',
@@ -43,8 +43,8 @@ define([
CesiumMath,
Matrix4,
BufferUsage,
- createShaderSource,
DrawCommand,
+ ShaderSource,
PolylineCommon,
PolylineFS,
PolylineVS,
@@ -1028,11 +1028,18 @@ define([
return;
}
- var vsSource = createShaderSource({ sources : [PolylineCommon, PolylineVS] });
- var fsSource = createShaderSource({ sources : [this.material.shaderSource, PolylineFS] });
- var fsPick = createShaderSource({ sources : [fsSource], pickColorQualifier : 'varying' });
- this.shaderProgram = context.createShaderProgram(vsSource, fsSource, attributeLocations);
- this.pickShaderProgram = context.createShaderProgram(vsSource, fsPick, attributeLocations);
+ var vs = new ShaderSource({
+ sources : [PolylineCommon, PolylineVS]
+ });
+ var fs = new ShaderSource({
+ sources : [this.material.shaderSource, PolylineFS]
+ });
+ var fsPick = new ShaderSource({
+ sources : fs.sources,
+ pickColorQualifier : 'varying'
+ });
+ this.shaderProgram = context.createShaderProgram(vs, fs, attributeLocations);
+ this.pickShaderProgram = context.createShaderProgram(vs, fsPick, attributeLocations);
};
function intersectsIDL(polyline) {
diff --git a/Source/Scene/PolylineColorAppearance.js b/Source/Scene/PolylineColorAppearance.js
index 9204add7172a..fb13cf6f9b9a 100644
--- a/Source/Scene/PolylineColorAppearance.js
+++ b/Source/Scene/PolylineColorAppearance.js
@@ -3,7 +3,6 @@ define([
'../Core/defaultValue',
'../Core/defineProperties',
'../Core/VertexFormat',
- '../Renderer/createShaderSource',
'../Shaders/Appearances/PerInstanceFlatColorAppearanceFS',
'../Shaders/Appearances/PolylineColorAppearanceVS',
'../Shaders/PolylineCommon',
@@ -12,13 +11,15 @@ define([
defaultValue,
defineProperties,
VertexFormat,
- createShaderSource,
PerInstanceFlatColorAppearanceFS,
PolylineColorAppearanceVS,
PolylineCommon,
Appearance) {
"use strict";
+ var defaultVertexShaderSource = PolylineCommon + '\n' + PolylineColorAppearanceVS;
+ var defaultFragmentShaderSource = PerInstanceFlatColorAppearanceFS;
+
/**
* An appearance for {@link GeometryInstance} instances with color attributes and {@link PolylineGeometry}.
* This allows several geometry instances, each with a different color, to
@@ -61,8 +62,6 @@ define([
var translucent = defaultValue(options.translucent, true);
var closed = false;
- var vs = createShaderSource({ sources : [PolylineCommon, PolylineColorAppearanceVS] });
- var fs = PerInstanceFlatColorAppearanceFS;
var vertexFormat = PolylineColorAppearance.VERTEX_FORMAT;
/**
@@ -85,8 +84,8 @@ define([
*/
this.translucent = translucent;
- this._vertexShaderSource = defaultValue(options.vertexShaderSource, vs);
- this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, fs);
+ this._vertexShaderSource = defaultValue(options.vertexShaderSource, defaultVertexShaderSource);
+ this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, defaultFragmentShaderSource);
this._renderState = defaultValue(options.renderState, Appearance.getDefaultRenderState(translucent, closed));
this._closed = closed;
diff --git a/Source/Scene/PolylineMaterialAppearance.js b/Source/Scene/PolylineMaterialAppearance.js
index 718a3551fb1e..debc9bf75dc3 100644
--- a/Source/Scene/PolylineMaterialAppearance.js
+++ b/Source/Scene/PolylineMaterialAppearance.js
@@ -4,7 +4,6 @@ define([
'../Core/defined',
'../Core/defineProperties',
'../Core/VertexFormat',
- '../Renderer/createShaderSource',
'../Shaders/Appearances/PolylineMaterialAppearanceVS',
'../Shaders/PolylineCommon',
'../Shaders/PolylineFS',
@@ -15,7 +14,6 @@ define([
defined,
defineProperties,
VertexFormat,
- createShaderSource,
PolylineMaterialAppearanceVS,
PolylineCommon,
PolylineFS,
@@ -23,6 +21,9 @@ define([
Material) {
"use strict";
+ var defaultVertexShaderSource = PolylineCommon + '\n' + PolylineMaterialAppearanceVS;
+ var defaultFragmentShaderSource = PolylineFS;
+
/**
* An appearance for {@link PolylineGeometry} that supports shading with materials.
*
@@ -61,8 +62,6 @@ define([
var translucent = defaultValue(options.translucent, true);
var closed = false;
- var vs = createShaderSource({ sources : [PolylineCommon, PolylineMaterialAppearanceVS] });
- var fs = PolylineFS;
var vertexFormat = PolylineMaterialAppearance.VERTEX_FORMAT;
/**
@@ -87,8 +86,8 @@ define([
*/
this.translucent = translucent;
- this._vertexShaderSource = defaultValue(options.vertexShaderSource, vs);
- this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, fs);
+ this._vertexShaderSource = defaultValue(options.vertexShaderSource, defaultVertexShaderSource);
+ this._fragmentShaderSource = defaultValue(options.fragmentShaderSource, defaultFragmentShaderSource);
this._renderState = defaultValue(options.renderState, Appearance.getDefaultRenderState(translucent, closed));
this._closed = closed;
diff --git a/Source/Scene/Primitive.js b/Source/Scene/Primitive.js
index 75669f6d0ccb..8f9c743120be 100644
--- a/Source/Scene/Primitive.js
+++ b/Source/Scene/Primitive.js
@@ -19,8 +19,8 @@ define([
'../Core/subdivideArray',
'../Core/TaskProcessor',
'../Renderer/BufferUsage',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../ThirdParty/when',
'./CullFace',
'./Pass',
@@ -47,8 +47,8 @@ define([
subdivideArray,
TaskProcessor,
BufferUsage,
- createShaderSource,
DrawCommand,
+ ShaderSource,
when,
CullFace,
Pass,
@@ -485,7 +485,7 @@ define([
}
}
- return createShaderSource({ sources : [forwardDecl, attributes, vertexShaderSource, computeFunctions] });
+ return [forwardDecl, attributes, vertexShaderSource, computeFunctions].join('\n');
}
function createPickVertexShaderSource(vertexShaderSource) {
@@ -853,7 +853,10 @@ define([
validateShaderMatching(this._sp, attributeLocations);
if (allowPicking) {
- var pickFS = createShaderSource({ sources : [fs], pickColorQualifier : 'varying' });
+ var pickFS = new ShaderSource({
+ sources : [fs],
+ pickColorQualifier : 'varying'
+ });
this._pickSP = context.replaceShaderProgram(this._pickSP, createPickVertexShaderSource(vs), pickFS, attributeLocations);
} else {
this._pickSP = context.createShaderProgram(vs, fs, attributeLocations);
diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index 97cef8db1290..d3373613446d 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -985,8 +985,12 @@ define([
function createDebugFragmentShaderProgram(command, scene, shaderProgram) {
var context = scene.context;
var sp = defaultValue(shaderProgram, command.shaderProgram);
- var fragmentShaderSource = sp.fragmentShaderSource;
- var renamedFS = fragmentShaderSource.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_Debug_main()');
+ var fs = sp.fragmentShaderSource.clone();
+
+ fs.sources = fs.sources.map(function(source) {
+ source = source.replace(/void\s+main\s*\(\s*(?:void)?\s*\)/g, 'void czm_Debug_main()');
+ return source;
+ });
var newMain =
'void main() \n' +
@@ -1012,9 +1016,10 @@ define([
newMain += '}';
- var source = renamedFS + '\n' + newMain;
+ fs.sources.push(newMain);
+
var attributeLocations = getAttributeLocations(sp);
- return context.createShaderProgram(sp.vertexShaderSource, source, attributeLocations);
+ return context.createShaderProgram(sp.vertexShaderSource, fs, attributeLocations);
}
function executeDebugCommand(command, scene, passState, renderState, shaderProgram) {
diff --git a/Source/Scene/SkyAtmosphere.js b/Source/Scene/SkyAtmosphere.js
index 1e678707d082..3404b57446c9 100644
--- a/Source/Scene/SkyAtmosphere.js
+++ b/Source/Scene/SkyAtmosphere.js
@@ -10,8 +10,8 @@ define([
'../Core/GeometryPipeline',
'../Core/VertexFormat',
'../Renderer/BufferUsage',
- '../Renderer/createShaderSource',
'../Renderer/DrawCommand',
+ '../Renderer/ShaderSource',
'../Shaders/SkyAtmosphereFS',
'../Shaders/SkyAtmosphereVS',
'./BlendingState',
@@ -28,8 +28,8 @@ define([
GeometryPipeline,
VertexFormat,
BufferUsage,
- createShaderSource,
DrawCommand,
+ ShaderSource,
SkyAtmosphereFS,
SkyAtmosphereVS,
BlendingState,
@@ -164,13 +164,13 @@ define([
blending : BlendingState.ALPHA_BLEND
});
- var vs = createShaderSource({
+ var vs = new ShaderSource({
defines : ['SKY_FROM_SPACE'],
sources : [SkyAtmosphereVS]
});
this._spSkyFromSpace = context.createShaderProgram(vs, SkyAtmosphereFS);
- vs = createShaderSource({
+ vs = new ShaderSource({
defines : ['SKY_FROM_ATMOSPHERE'],
sources : [SkyAtmosphereVS]
});
diff --git a/Source/Scene/ViewportQuad.js b/Source/Scene/ViewportQuad.js
index e588075586d6..96645a36342a 100644
--- a/Source/Scene/ViewportQuad.js
+++ b/Source/Scene/ViewportQuad.js
@@ -5,7 +5,7 @@ define([
'../Core/defined',
'../Core/destroyObject',
'../Core/DeveloperError',
- '../Renderer/createShaderSource',
+ '../Renderer/ShaderSource',
'../Shaders/ViewportQuadFS',
'./BlendingState',
'./Material',
@@ -16,7 +16,7 @@ define([
defined,
destroyObject,
DeveloperError,
- createShaderSource,
+ ShaderSource,
ViewportQuadFS,
BlendingState,
Material,
@@ -133,7 +133,9 @@ define([
this._overlayCommand.shaderProgram.destroy();
}
- var fsSource = createShaderSource({ sources : [this._material.shaderSource, ViewportQuadFS] });
+ var fsSource = new ShaderSource({
+ sources : [this._material.shaderSource, ViewportQuadFS]
+ });
this._overlayCommand = context.createViewportQuadCommand(fsSource, {
renderState : this._rs,
uniformMap : this._material._uniforms,
diff --git a/Source/Shaders/Builtin/Functions/cosineAndSine.glsl b/Source/Shaders/Builtin/Functions/cosineAndSine.glsl
index 5821de1367a5..57e8f7314cfd 100644
--- a/Source/Shaders/Builtin/Functions/cosineAndSine.glsl
+++ b/Source/Shaders/Builtin/Functions/cosineAndSine.glsl
@@ -1,3 +1,6 @@
+// Firefox 33-34 has a regression that prevents the CORDIC implementation from compiling
+#ifndef DISABLE_CORDIC
+
/**
* @private
*/
@@ -208,4 +211,6 @@ vec2 czm_cosineAndSine(float angle)
{
return cordic(angle);
}
-}
\ No newline at end of file
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/Shaders/Builtin/Functions/latitudeToWebMercatorFraction.glsl b/Source/Shaders/Builtin/Functions/latitudeToWebMercatorFraction.glsl
index c51f7e038f22..0a69e21db6b2 100644
--- a/Source/Shaders/Builtin/Functions/latitudeToWebMercatorFraction.glsl
+++ b/Source/Shaders/Builtin/Functions/latitudeToWebMercatorFraction.glsl
@@ -15,7 +15,12 @@
*/
float czm_latitudeToWebMercatorFraction(float latitude, float southMercatorYLow, float southMercatorYHigh, float oneOverMercatorHeight)
{
+// Firefox 33-34 has a regression that prevents the CORDIC implementation from compiling
+#ifdef DISABLE_CORDIC
+ float sinLatitude = sin(latitude);
+#else
float sinLatitude = czm_cosineAndSine(latitude).y;
+#endif
float mercatorY = 0.5 * log((1.0 + sinLatitude) / (1.0 - sinLatitude));
// mercatorY - southMercatorY in simulated double precision.
diff --git a/Specs/Renderer/ShaderProgramSpec.js b/Specs/Renderer/ShaderProgramSpec.js
index df8729bb49fb..c55b4a78b1e9 100644
--- a/Specs/Renderer/ShaderProgramSpec.js
+++ b/Specs/Renderer/ShaderProgramSpec.js
@@ -11,6 +11,7 @@ defineSuite([
'Renderer/BufferUsage',
'Renderer/ClearCommand',
'Renderer/DrawCommand',
+ 'Renderer/ShaderSource',
'Specs/createContext',
'Specs/destroyContext'
], function(
@@ -25,6 +26,7 @@ defineSuite([
BufferUsage,
ClearCommand,
DrawCommand,
+ ShaderSource,
createContext,
destroyContext) {
"use strict";
@@ -53,9 +55,9 @@ defineSuite([
beforeAll(function() {
context = createContext();
- for(var functionName in injectedTestFunctions) {
- if(injectedTestFunctions.hasOwnProperty(functionName)) {
- ShaderProgram._czmBuiltinsAndUniforms[functionName] = injectedTestFunctions[functionName];
+ for ( var functionName in injectedTestFunctions) {
+ if (injectedTestFunctions.hasOwnProperty(functionName)) {
+ ShaderSource._czmBuiltinsAndUniforms[functionName] = injectedTestFunctions[functionName];
}
}
@@ -66,7 +68,7 @@ defineSuite([
for ( var functionName in injectedTestFunctions) {
if (injectedTestFunctions.hasOwnProperty(functionName)) {
- delete ShaderProgram._czmBuiltinsAndUniforms[functionName];
+ delete ShaderSource._czmBuiltinsAndUniforms[functionName];
}
}
});
@@ -96,8 +98,17 @@ defineSuite([
var fs = 'void main() { gl_FragColor = vec4(1.0); }';
sp = context.createShaderProgram(vs, fs);
- expect(sp.vertexShaderSource).toEqual(vs);
- expect(sp.fragmentShaderSource).toEqual(fs);
+ var expectedVSText = new ShaderSource({
+ sources : [vs]
+ }).getCombinedShader(false);
+
+ expect(sp._vertexShaderText).toEqual(expectedVSText);
+
+ var expectedFSText = new ShaderSource({
+ sources : [fs]
+ }).getCombinedShader(true);
+
+ expect(sp._fragmentShaderText).toEqual(expectedFSText);
});
it('has a position vertex attribute', function() {
@@ -649,8 +660,8 @@ defineSuite([
it('fails with built-in function circular dependency', function() {
var vs = 'void main() { gl_Position = vec4(0.0); }';
var fs = 'void main() { czm_circularDependency1(); gl_FragColor = vec4(1.0); }';
- sp = context.createShaderProgram(vs, fs);
expect(function() {
+ sp = context.createShaderProgram(vs, fs);
sp._bind();
}).toThrowDeveloperError();
});
diff --git a/Specs/Renderer/ShaderSourceSpec.js b/Specs/Renderer/ShaderSourceSpec.js
new file mode 100644
index 000000000000..ab7a1a1037f6
--- /dev/null
+++ b/Specs/Renderer/ShaderSourceSpec.js
@@ -0,0 +1,69 @@
+/*global defineSuite*/
+defineSuite([
+ 'Renderer/ShaderSource'
+ ], function(
+ ShaderSource) {
+ "use strict";
+ /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/
+
+ it('combines #defines', function() {
+ var source = new ShaderSource({
+ defines : ['A', 'B', '']
+ });
+
+ var shaderText = source.getCombinedShader(false);
+ expect(shaderText).toContain('#define A');
+ expect(shaderText).toContain('#define B');
+ expect(shaderText.match(/#define/g).length).toEqual(2);
+ });
+
+ it('combines sources', function() {
+ var source = new ShaderSource({
+ sources : ['void func() {}', 'void main() {}']
+ });
+ var shaderText = source.getCombinedShader(false);
+ expect(shaderText).toContain('#line 0\nvoid func() {}');
+ expect(shaderText).toContain('#line 0\nvoid main() {}');
+ });
+
+ it('combines #defines and sources', function() {
+ var source = new ShaderSource({
+ defines : ['A', 'B', ''],
+ sources : ['void func() {}', 'void main() {}']
+ });
+ var shaderText = source.getCombinedShader(false);
+ expect(shaderText).toContain('#define A');
+ expect(shaderText).toContain('#define B');
+ expect(shaderText.match(/#define/g).length).toEqual(2);
+ expect(shaderText).toContain('#line 0\nvoid func() {}');
+ expect(shaderText).toContain('#line 0\nvoid main() {}');
+ });
+
+ it('creates a pick shader with a uniform', function() {
+ var source = new ShaderSource({
+ sources : ['void main() { gl_FragColor = vec4(1.0); }'],
+ pickColorQualifier : 'uniform'
+ });
+ var shaderText = source.getCombinedShader(false);
+ expect(shaderText).toContain('uniform vec4 czm_pickColor;');
+ expect(shaderText).toContain('gl_FragColor = czm_pickColor;');
+ });
+
+ it('creates a pick shader with a varying', function() {
+ var source = new ShaderSource({
+ sources : ['void main() { gl_FragColor = vec4(1.0); }'],
+ pickColorQualifier : 'varying'
+ });
+ var shaderText = source.getCombinedShader(false);
+ expect(shaderText).toContain('varying vec4 czm_pickColor;');
+ expect(shaderText).toContain('gl_FragColor = czm_pickColor;');
+ });
+
+ it('throws with invalid qualifier', function() {
+ expect(function() {
+ var source = new ShaderSource({
+ pickColorQualifier : 'const'
+ });
+ }).toThrowDeveloperError();
+ });
+});
\ No newline at end of file
diff --git a/Specs/Renderer/createShaderSourceSpec.js b/Specs/Renderer/createShaderSourceSpec.js
deleted file mode 100644
index 6ba0c7b6f18c..000000000000
--- a/Specs/Renderer/createShaderSourceSpec.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*global defineSuite*/
-defineSuite([
- 'Renderer/createShaderSource'
- ], function(
- createShaderSource) {
- "use strict";
- /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor*/
-
- it('combines #defines', function() {
- var source = createShaderSource({ defines : ['A', 'B', '' ] });
- expect(source).toContain('#define A');
- expect(source).toContain('#define B');
- expect(source.match(/#define/g).length).toEqual(2);
- });
-
- it('combines sources', function() {
- var source = createShaderSource({ sources : ['void func() {}', 'void main() {}'] });
- expect(source).toContain('void func() {}');
- expect(source).toContain('void main() {}');
- expect(source.match(/#line/g).length).toEqual(2);
- });
-
- it('combines #defines and sources', function() {
- var source = createShaderSource({
- defines : ['A', 'B', '' ],
- sources : ['void func() {}', 'void main() {}']
- });
- expect(source).toContain('#define A');
- expect(source).toContain('#define B');
- expect(source.match(/#define/g).length).toEqual(2);
- expect(source).toContain('void func() {}');
- expect(source).toContain('void main() {}');
- expect(source.match(/#line/g).length).toEqual(2);
- });
-
- it('creates a pick shader with a uniform', function() {
- var source = createShaderSource({
- sources : ['void main() { gl_FragColor = vec4(1.0); }'],
- pickColorQualifier : 'uniform'
- });
- expect(source).toContain('uniform vec4 czm_pickColor;');
- expect(source).toContain('gl_FragColor = czm_pickColor;');
- });
-
- it('creates a pick shader with a varying', function() {
- var source = createShaderSource({
- sources : ['void main() { gl_FragColor = vec4(1.0); }'],
- pickColorQualifier : 'varying'
- });
- expect(source).toContain('varying vec4 czm_pickColor;');
- expect(source).toContain('gl_FragColor = czm_pickColor;');
- });
-
- it('throws with invalid qualifier', function() {
- expect(function() {
- createShaderSource({ pickColorQualifier : 'const' });
- }).toThrowDeveloperError();
- });
-});
\ No newline at end of file