<commit_before>/*global define*/
define([
        '../Core/defined',
        '../Core/DeveloperError',
        '../Core/FeatureDetection',
        '../Core/RuntimeError',
        '../Core/destroyObject',
        '../Core/Matrix2',
        '../Core/Matrix3',
        '../Core/Matrix4',
        './AutomaticUniforms',
        './UniformDatatype',
        '../Shaders/Builtin/CzmBuiltins'
    ], function(
        defined,
        DeveloperError,
        FeatureDetection,
        RuntimeError,
        destroyObject,
        Matrix2,
        Matrix3,
        Matrix4,
        AutomaticUniforms,
        UniformDatatype,
        ShaderBuiltins) {
    "use strict";
    /*global console*/

    function getUniformDatatype(gl, activeUniformType) {
        switch (activeUniformType) {
        case gl.FLOAT:
            return function() {
                return UniformDatatype.FLOAT;
            };
        case gl.FLOAT_VEC2:
            return function() {
                return UniformDatatype.FLOAT_VECTOR2;
            };
        case gl.FLOAT_VEC3:
            return function() {
                return UniformDatatype.FLOAT_VECTOR3;
            };
        case gl.FLOAT_VEC4:
            return function() {
                return UniformDatatype.FLOAT_VECTOR4;
            };
        case gl.INT:
            return function() {
                return UniformDatatype.INT;
            };
        case gl.INT_VEC2:
            return function() {
                return UniformDatatype.INT_VECTOR2;
            };
        case gl.INT_VEC3:
            return function() {
                return UniformDatatype.INT_VECTOR3;
            };
        case gl.INT_VEC4:
            return function() {
                return UniformDatatype.INT_VECTOR4;
            };
        case gl.BOOL:
            return function() {
                return UniformDatatype.BOOL;
            };
        case gl.BOOL_VEC2:
            return function() {
                return UniformDatatype.BOOL_VECTOR2;
            };
        case gl.BOOL_VEC3:
            return function() {
                return UniformDatatype.BOOL_VECTOR3;
            };
        case gl.BOOL_VEC4:
            return function() {
                return UniformDatatype.BOOL_VECTOR4;
            };
        case gl.FLOAT_MAT2:
            return function() {
                return UniformDatatype.FLOAT_MATRIX2;
            };
        case gl.FLOAT_MAT3:
            return function() {
                return UniformDatatype.FLOAT_MATRIX3;
            };
        case gl.FLOAT_MAT4:
            return function() {
                return UniformDatatype.FLOAT_MATRIX4;
            };
        case gl.SAMPLER_2D:
            return function() {
                return UniformDatatype.SAMPLER_2D;
            };
        case gl.SAMPLER_CUBE:
            return function() {
                return UniformDatatype.SAMPLER_CUBE;
            };
        default:
            throw new RuntimeError('Unrecognized uniform type: ' + activeUniformType);
        }
    }

    var scratchUniformMatrix2;
    var scratchUniformMatrix3;
    var scratchUniformMatrix4;
    if (FeatureDetection.supportsTypedArrays()) {
        scratchUniformMatrix2 = new Float32Array(4);
        scratchUniformMatrix3 = new Float32Array(9);
        scratchUniformMatrix4 = new Float32Array(16);
    }

    /**
     * A shader program's uniform, including the uniform's value.  This is most commonly used to change
     * the value of a uniform, but can also be used retrieve a uniform's name and datatype,
     * which is useful for creating user interfaces for tweaking shaders.
     * <br /><br />
     * Do not create a uniform object with the <code>new</code> keyword; a shader program's uniforms
     * are available via {@link ShaderProgram#getAllUniforms}.
     * <br /><br />
     * Changing a uniform's value will affect future calls to {@link Context#draw}
     * that use the corresponding shader program.
     * <br /><br />
     * The datatype of the <code>value</code> property depends on the datatype
     * used in the GLSL declaration as shown in the examples in the table below.
     * <br /><br />
     * <table border='1'>
     * <tr>
     * <td>GLSL</td>
     * <td>JavaScript</td>
     * </tr>
     * <tr>
     * <td><code>uniform float u_float; </code></td>
     * <td><code> sp.getAllUniforms().u_float.value = 1.0;</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform vec2 u_vec2; </code></td>
     * <td><code> sp.getAllUniforms().u_vec2.value = new Cartesian2(1.0, 2.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform vec3 u_vec3; </code></td>
     * <td><code> sp.getAllUniforms().u_vec3.value = new Cartesian3(1.0, 2.0, 3.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform vec4 u_vec4; </code></td>
     * <td><code> sp.getAllUniforms().u_vec4.value = new Cartesian4(1.0, 2.0, 3.0, 4.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform int u_int; </code></td>
     * <td><code> sp.getAllUniforms().u_int.value = 1;</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform ivec2 u_ivec2; </code></td>
     * <td><code> sp.getAllUniforms().u_ivec2.value = new Cartesian2(1, 2);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform ivec3 u_ivec3; </code></td>
     * <td><code> sp.getAllUniforms().u_ivec3.value = new Cartesian3(1, 2, 3);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform ivec4 u_ivec4; </code></td>
     * <td><code> sp.getAllUniforms().u_ivec4.value = new Cartesian4(1, 2, 3, 4);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bool u_bool; </code></td>
     * <td><code> sp.getAllUniforms().u_bool.value = true;</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bvec2 u_bvec2; </code></td>
     * <td><code> sp.getAllUniforms().u_bvec2.value = new Cartesian2(true, true);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bvec3 u_bvec3; </code></td>
     * <td><code> sp.getAllUniforms().u_bvec3.value = new Cartesian3(true, true, true);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bvec4 u_bvec4; </code></td>
     * <td><code> sp.getAllUniforms().u_bvec4.value = new Cartesian4(true, true, true, true);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform mat2 u_mat2; </code></td>
     * <td><code> sp.getAllUniforms().u_mat2.value = new Matrix2(1.0, 2.0, 3.0, 4.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform mat3 u_mat3; </code></td>
     * <td><code> sp.getAllUniforms().u_mat3.value = new Matrix3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform mat4 u_mat4; </code></td>
     * <td><code> sp.getAllUniforms().u_mat4.value = new Matrix4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform sampler2D u_texture; </code></td>
     * <td><code> sp.getAllUniforms().u_texture.value = context.createTexture2D(...);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform samplerCube u_cubeMap; </code></td>
     * <td><code> sp.getAllUniforms().u_cubeMap.value = context.createCubeMap(...);</code></td>
     * </tr>
     * </table>
     * <br />
     * When the GLSL uniform is declared as an array, <code>value</code> is also an array as shown in Example 2.
     * Individual members of a <code>struct uniform</code> can be accessed as done in Example 3.
     * <br /><br />
     * Uniforms whose names starting with <code>czm_</code>, such as {@link czm_viewProjection}, are called
     * automatic uniforms; they are implicitly declared and automatically assigned to in
     * <code>Context.draw</code> based on the {@link UniformState}.
     *
     * @alias Uniform
     * @internalConstructor
     *
     * @see Uniform#value
     * @see UniformDatatype
     * @see ShaderProgram#getAllUniforms
     * @see UniformState
     * @see Context#draw
     * @see Context#createTexture2D
     * @see Context#createCubeMap
     *
     * @example
     * // Example 1. Create a shader program and set its
     * // one uniform, a 4x4 matrix, to the identity matrix
     * var vs =
     *   'attribute vec4 position; ' +
     *   'uniform mat4 u_mvp; ' +
     *   'void main() { gl_Position = u_mvp * position; }';
     * var fs = // ...
     * var sp = context.createShaderProgram(vs, fs);
     *
     * var mvp = sp.getAllUniforms().u_mvp;
     * console.log(mvp.getName());           // 'u_mvp'
     * console.log(mvp.getDatatype().name);  // 'FLOAT_MATRIX4'
     * mvp.value = Matrix4.IDENTITY;
     *
     * //////////////////////////////////////////////////////////////////////
     *
     * // Example 2. Setting values for a GLSL array uniform
     * // GLSL:  uniform float u_float[2];
     * sp.getAllUniforms().u_float.value = new Cartesian2(1.0, 2.0);
     *
     * // GLSL:  uniform vec4 u_vec4[2];
     * sp.getAllUniforms().u_vec4.value = [
     *   Cartesian4.UNIT_X,
     *   Cartesian4.UNIT_Y
     * ];
     *
     * //////////////////////////////////////////////////////////////////////
     *
     * // Example 3. Setting values for members of a GLSL struct
     * // GLSL:  uniform struct { float f; vec4 v; } u_struct;
     * sp.getAllUniforms()['u_struct.f'].value = 1.0;
     * sp.getAllUniforms()['u_struct.v'].value = new Cartesian4(1.0, 2.0, 3.0, 4.0);
     */
    var Uniform = function(_gl, activeUniform, _uniformName, _location, uniformValue) {
        /**
         * The value of the uniform.  The datatype depends on the datatype used in the
         * GLSL declaration as explained in the {@link Uniform} help and shown
         * in the examples below.
         *
         * @field
         * @alias Uniform#value
         *
         * @see Context#createTexture2D
         *
         * @example
         * // GLSL:  uniform float u_float;
         * sp.getAllUniforms().u_float.value = 1.0;
         *
         * // GLSL:  uniform vec4 u_vec4;
         * sp.getAllUniforms().u_vec4.value = Cartesian4.ZERO;
         *
         * // GLSL:  uniform bvec4 u_bvec4;
         * sp.getAllUniforms().u_bvec4.value = new Cartesian4(true, true, true, true);
         *
         * // GLSL:  uniform mat4 u_mat4;
         * sp.getAllUniforms().u_mat4.value = Matrix4.IDENTITY;
         *
         * // GLSL:  uniform sampler2D u_texture;
         * sp.getAllUniforms().u_texture.value = context.createTexture2D(...);
         *
         * // GLSL:  uniform vec2 u_vec2[2];
         * sp.getAllUniforms().u_vec2.value = [
         *   new Cartesian2(1.0, 2.0),
         *   new Cartesian2(3.0, 4.0)
         * ];
         *
         * // GLSL:  uniform struct { float f; vec4 v; } u_struct;
         * sp.getAllUniforms()['u_struct.f'].value = 1.0;
         * sp.getAllUniforms()['u_struct.v'].value = new Cartesian4(1.0, 2.0, 3.0, 4.0);
         */
        this.value = uniformValue;

        /**
         * Returns the case-sensitive name of the GLSL uniform.
         *
         * @returns {String} The name of the uniform.
         * @function
         * @alias Uniform#getName
         *
         * @example
         * // GLSL: uniform mat4 u_mvp;
         * console.log(sp.getAllUniforms().u_mvp.getName());  // 'u_mvp'
         */
        this.getName = function() {
            return _uniformName;
        };

        /**
         * Returns the datatype of the uniform.  This is useful when dynamically
         * creating a user interface to tweak shader uniform values.
         *
         * @returns {UniformDatatype} The datatype of the uniform.
         * @function
         * @alias Uniform#getDatatype
         *
         * @see UniformDatatype
         *
         * @example
         * // GLSL: uniform mat4 u_mvp;
         * console.log(sp.getAllUniforms().u_mvp.getDatatype().name);  // 'FLOAT_MATRIX4'
         */
        this.getDatatype = getUniformDatatype(_gl, activeUniform.type);

        this._getLocation = function() {
            return _location;
        };

        this._set = (function() {
            switch (activeUniform.type) {
            case _gl.FLOAT:
                return function() {
                    _gl.uniform1f(_location, this.value);
                };
            case _gl.FLOAT_VEC2:
                return function() {
                    var v = this.value;
                    _gl.uniform2f(_location, v.x, v.y);
                };
            case _gl.FLOAT_VEC3:
                return function() {
                    var v = this.value;
                    _gl.uniform3f(_location, v.x, v.y, v.z);
                };
            case _gl.FLOAT_VEC4:
                return function() {
                    var v = this.value;

                    if (defined(v.red)) {
                        _gl.uniform4f(_location, v.red, v.green, v.blue, v.alpha);
                    } else if (defined(v.x)) {
                        _gl.uniform4f(_location, v.x, v.y, v.z, v.w);
                    } else {
                        throw new DeveloperError('Invalid vec4 value for uniform "' + activeUniform.name + '".');
                    }
                };
            case _gl.SAMPLER_2D:
            case _gl.SAMPLER_CUBE:
                // See _setSampler()
                return undefined;
            case _gl.INT:
            case _gl.BOOL:
                return function() {
                    _gl.uniform1i(_location, this.value);
                };
            case _gl.INT_VEC2:
            case _gl.BOOL_VEC2:
                return function() {
                    var v = this.value;
                    _gl.uniform2i(_location, v.x, v.y);
                };
            case _gl.INT_VEC3:
            case _gl.BOOL_VEC3:
                return function() {
                    var v = this.value;
                    _gl.uniform3i(_location, v.x, v.y, v.z);
                };
            case _gl.INT_VEC4:
            case _gl.BOOL_VEC4:
                return function() {
                    var v = this.value;
                    _gl.uniform4i(_location, v.x, v.y, v.z, v.w);
                };
            case _gl.FLOAT_MAT2:
                return function() {
                    _gl.uniformMatrix2fv(_location, false, Matrix2.toArray(this.value, scratchUniformMatrix2));
                };
            case _gl.FLOAT_MAT3:
                return function() {
                    _gl.uniformMatrix3fv(_location, false, Matrix3.toArray(this.value, scratchUniformMatrix3));
                };
            case _gl.FLOAT_MAT4:
                return function() {
                    _gl.uniformMatrix4fv(_location, false, Matrix4.toArray(this.value, scratchUniformMatrix4));
                };
            default:
                throw new RuntimeError('Unrecognized uniform type: ' + activeUniform.type + ' for uniform "' + activeUniform.name + '".');
            }
        })();

        if ((activeUniform.type === _gl.SAMPLER_2D) || (activeUniform.type === _gl.SAMPLER_CUBE)) {
            this._setSampler = function(textureUnitIndex) {
                _gl.activeTexture(_gl.TEXTURE0 + textureUnitIndex);
                _gl.bindTexture(this.value._getTarget(), this.value._getTexture());
                _gl.uniform1i(_location, textureUnitIndex);

                return textureUnitIndex + 1;
            };

            this._clearSampler = function(textureUnitIndex) {
                _gl.activeTexture(_gl.TEXTURE0 + textureUnitIndex);
                _gl.bindTexture(this.value._getTarget(), null);

                return textureUnitIndex + 1;
            };
        }
    };

    /**
     * Uniform and UniformArray have the same documentation.  It is just an implementation
     * detail that they are two different types.
     *
     * @alias UniformArray
     * @constructor
     *
     * @see Uniform
     */
    var UniformArray = function(_gl, activeUniform, _uniformName, locations, value) {
        this.value = value;

        var _locations = locations;

        /**
         * @private
         */
        this.getName = function() {
            return _uniformName;
        };

        this.getDatatype = getUniformDatatype(_gl, activeUniform.type);

        this._getLocations = function() {
            return _locations;
        };

        this._set = (function() {
            switch (activeUniform.type) {
            case _gl.FLOAT:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniform1f(_locations[i], this.value[i]);
                    }
                };
            case _gl.FLOAT_VEC2:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform2f(_locations[i], v.x, v.y);
                    }
                };
            case _gl.FLOAT_VEC3:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform3f(_locations[i], v.x, v.y, v.z);
                    }
                };
            case _gl.FLOAT_VEC4:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];

                        if (defined(v.red)) {
                            _gl.uniform4f(_locations[i], v.red, v.green, v.blue, v.alpha);
                        } else if (defined(v.x)) {
                            _gl.uniform4f(_locations[i], v.x, v.y, v.z, v.w);
                        } else {
                            throw new DeveloperError('Invalid vec4 value.');
                        }
                    }
                };
            case _gl.SAMPLER_2D:
            case _gl.SAMPLER_CUBE:
                // See _setSampler()
                return undefined;
            case _gl.INT:
            case _gl.BOOL:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniform1i(_locations[i], this.value[i]);
                    }
                };
            case _gl.INT_VEC2:
            case _gl.BOOL_VEC2:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform2i(_locations[i], v.x, v.y);
                    }
                };
            case _gl.INT_VEC3:
            case _gl.BOOL_VEC3:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform3i(_locations[i], v.x, v.y, v.z);
                    }
                };
            case _gl.INT_VEC4:
            case _gl.BOOL_VEC4:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform4i(_locations[i], v.x, v.y, v.z, v.w);
                    }
                };
            case _gl.FLOAT_MAT2:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniformMatrix2fv(_locations[i], false, Matrix2.toArray(this.value[i], scratchUniformMatrix2));
                    }
                };
            case _gl.FLOAT_MAT3:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniformMatrix3fv(_locations[i], false, Matrix3.toArray(this.value[i], scratchUniformMatrix3));
                    }
                };
            case _gl.FLOAT_MAT4:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniformMatrix4fv(_locations[i], false, Matrix4.toArray(this.value[i], scratchUniformMatrix4));
                    }
                };
            default:
                throw new RuntimeError('Unrecognized uniform type: ' + activeUniform.type);
            }
        })();

        if ((activeUniform.type === _gl.SAMPLER_2D) || (activeUniform.type === _gl.SAMPLER_CUBE)) {
            this._setSampler = function(textureUnitIndex) {
                for ( var i = 0; i < _locations.length; ++i) {
                    var value = this.value[i];
                    var index = textureUnitIndex + i;
                    _gl.activeTexture(_gl.TEXTURE0 + index);
                    _gl.bindTexture(value._getTarget(), value._getTexture());
                    _gl.uniform1i(_locations[i], index);
                }

                return textureUnitIndex + _locations.length;
            };

            this._clearSampler = function(textureUnitIndex) {
                for ( var i = 0; i < _locations.length; ++i) {
                    _gl.activeTexture(_gl.TEXTURE0 + textureUnitIndex + i);
                    _gl.bindTexture(this.value[i]._getTarget(), null);
                }

                return textureUnitIndex + _locations.length;
            };
        }
    };

    /**
     * DOC_TBA
     *
     * @alias ShaderProgram
     * @internalConstructor
     *
     * @see Context#createShaderProgram
     * @see Context#getShaderCache
     */
    var ShaderProgram = function(gl, logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations) {
        var program = createAndLinkProgram(gl, logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations);
        var numberOfVertexAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
        var uniforms = findUniforms(gl, program);
        var partitionedUniforms = partitionUniforms(uniforms.allUniforms);

        this._gl = gl;
        this._program = program;
        this._numberOfVertexAttributes = numberOfVertexAttributes;
        this._vertexAttributes = findVertexAttributes(gl, program, numberOfVertexAttributes);
        this._allUniforms = uniforms.allUniforms;
        this._uniforms = uniforms.uniforms;
        this._samplerUniforms = uniforms.samplerUniforms;
        this._automaticUniforms = partitionedUniforms.automaticUniforms;
        this._manualUniforms = partitionedUniforms.manualUniforms;

        /**
         * 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.
         *
         * @type {String}
         *
         * @readonly
         */
        this.vertexShaderSource = 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.
         *
         * @type {String}
         *
         * @readonly
         */
        this.fragmentShaderSource = fragmentShaderSource;
    };

    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 (dependencyNode === undefined) {
            // 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 (commentBlocks !== undefined && 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
        for ( var name in ShaderBuiltins) {
            if (currentNode.name !== name && ShaderBuiltins.hasOwnProperty(name)) {
                if (currentNode.glslSource.indexOf(name) !== -1) {
                    var referencedNode = getDependencyNode(name, ShaderBuiltins[name], 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);<commit_msg>Use regex to extract possible cesium built-in functions/structs/constants<commit_after>/*global define*/
define([
        '../Core/defined',
        '../Core/DeveloperError',
        '../Core/FeatureDetection',
        '../Core/RuntimeError',
        '../Core/destroyObject',
        '../Core/Matrix2',
        '../Core/Matrix3',
        '../Core/Matrix4',
        './AutomaticUniforms',
        './UniformDatatype',
        '../Shaders/Builtin/CzmBuiltins'
    ], function(
        defined,
        DeveloperError,
        FeatureDetection,
        RuntimeError,
        destroyObject,
        Matrix2,
        Matrix3,
        Matrix4,
        AutomaticUniforms,
        UniformDatatype,
        ShaderBuiltins) {
    "use strict";
    /*global console*/

    function getUniformDatatype(gl, activeUniformType) {
        switch (activeUniformType) {
        case gl.FLOAT:
            return function() {
                return UniformDatatype.FLOAT;
            };
        case gl.FLOAT_VEC2:
            return function() {
                return UniformDatatype.FLOAT_VECTOR2;
            };
        case gl.FLOAT_VEC3:
            return function() {
                return UniformDatatype.FLOAT_VECTOR3;
            };
        case gl.FLOAT_VEC4:
            return function() {
                return UniformDatatype.FLOAT_VECTOR4;
            };
        case gl.INT:
            return function() {
                return UniformDatatype.INT;
            };
        case gl.INT_VEC2:
            return function() {
                return UniformDatatype.INT_VECTOR2;
            };
        case gl.INT_VEC3:
            return function() {
                return UniformDatatype.INT_VECTOR3;
            };
        case gl.INT_VEC4:
            return function() {
                return UniformDatatype.INT_VECTOR4;
            };
        case gl.BOOL:
            return function() {
                return UniformDatatype.BOOL;
            };
        case gl.BOOL_VEC2:
            return function() {
                return UniformDatatype.BOOL_VECTOR2;
            };
        case gl.BOOL_VEC3:
            return function() {
                return UniformDatatype.BOOL_VECTOR3;
            };
        case gl.BOOL_VEC4:
            return function() {
                return UniformDatatype.BOOL_VECTOR4;
            };
        case gl.FLOAT_MAT2:
            return function() {
                return UniformDatatype.FLOAT_MATRIX2;
            };
        case gl.FLOAT_MAT3:
            return function() {
                return UniformDatatype.FLOAT_MATRIX3;
            };
        case gl.FLOAT_MAT4:
            return function() {
                return UniformDatatype.FLOAT_MATRIX4;
            };
        case gl.SAMPLER_2D:
            return function() {
                return UniformDatatype.SAMPLER_2D;
            };
        case gl.SAMPLER_CUBE:
            return function() {
                return UniformDatatype.SAMPLER_CUBE;
            };
        default:
            throw new RuntimeError('Unrecognized uniform type: ' + activeUniformType);
        }
    }

    var scratchUniformMatrix2;
    var scratchUniformMatrix3;
    var scratchUniformMatrix4;
    if (FeatureDetection.supportsTypedArrays()) {
        scratchUniformMatrix2 = new Float32Array(4);
        scratchUniformMatrix3 = new Float32Array(9);
        scratchUniformMatrix4 = new Float32Array(16);
    }

    /**
     * A shader program's uniform, including the uniform's value.  This is most commonly used to change
     * the value of a uniform, but can also be used retrieve a uniform's name and datatype,
     * which is useful for creating user interfaces for tweaking shaders.
     * <br /><br />
     * Do not create a uniform object with the <code>new</code> keyword; a shader program's uniforms
     * are available via {@link ShaderProgram#getAllUniforms}.
     * <br /><br />
     * Changing a uniform's value will affect future calls to {@link Context#draw}
     * that use the corresponding shader program.
     * <br /><br />
     * The datatype of the <code>value</code> property depends on the datatype
     * used in the GLSL declaration as shown in the examples in the table below.
     * <br /><br />
     * <table border='1'>
     * <tr>
     * <td>GLSL</td>
     * <td>JavaScript</td>
     * </tr>
     * <tr>
     * <td><code>uniform float u_float; </code></td>
     * <td><code> sp.getAllUniforms().u_float.value = 1.0;</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform vec2 u_vec2; </code></td>
     * <td><code> sp.getAllUniforms().u_vec2.value = new Cartesian2(1.0, 2.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform vec3 u_vec3; </code></td>
     * <td><code> sp.getAllUniforms().u_vec3.value = new Cartesian3(1.0, 2.0, 3.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform vec4 u_vec4; </code></td>
     * <td><code> sp.getAllUniforms().u_vec4.value = new Cartesian4(1.0, 2.0, 3.0, 4.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform int u_int; </code></td>
     * <td><code> sp.getAllUniforms().u_int.value = 1;</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform ivec2 u_ivec2; </code></td>
     * <td><code> sp.getAllUniforms().u_ivec2.value = new Cartesian2(1, 2);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform ivec3 u_ivec3; </code></td>
     * <td><code> sp.getAllUniforms().u_ivec3.value = new Cartesian3(1, 2, 3);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform ivec4 u_ivec4; </code></td>
     * <td><code> sp.getAllUniforms().u_ivec4.value = new Cartesian4(1, 2, 3, 4);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bool u_bool; </code></td>
     * <td><code> sp.getAllUniforms().u_bool.value = true;</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bvec2 u_bvec2; </code></td>
     * <td><code> sp.getAllUniforms().u_bvec2.value = new Cartesian2(true, true);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bvec3 u_bvec3; </code></td>
     * <td><code> sp.getAllUniforms().u_bvec3.value = new Cartesian3(true, true, true);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform bvec4 u_bvec4; </code></td>
     * <td><code> sp.getAllUniforms().u_bvec4.value = new Cartesian4(true, true, true, true);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform mat2 u_mat2; </code></td>
     * <td><code> sp.getAllUniforms().u_mat2.value = new Matrix2(1.0, 2.0, 3.0, 4.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform mat3 u_mat3; </code></td>
     * <td><code> sp.getAllUniforms().u_mat3.value = new Matrix3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform mat4 u_mat4; </code></td>
     * <td><code> sp.getAllUniforms().u_mat4.value = new Matrix4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.0, 2.0);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform sampler2D u_texture; </code></td>
     * <td><code> sp.getAllUniforms().u_texture.value = context.createTexture2D(...);</code></td>
     * </tr>
     * <tr>
     * <td><code>uniform samplerCube u_cubeMap; </code></td>
     * <td><code> sp.getAllUniforms().u_cubeMap.value = context.createCubeMap(...);</code></td>
     * </tr>
     * </table>
     * <br />
     * When the GLSL uniform is declared as an array, <code>value</code> is also an array as shown in Example 2.
     * Individual members of a <code>struct uniform</code> can be accessed as done in Example 3.
     * <br /><br />
     * Uniforms whose names starting with <code>czm_</code>, such as {@link czm_viewProjection}, are called
     * automatic uniforms; they are implicitly declared and automatically assigned to in
     * <code>Context.draw</code> based on the {@link UniformState}.
     *
     * @alias Uniform
     * @internalConstructor
     *
     * @see Uniform#value
     * @see UniformDatatype
     * @see ShaderProgram#getAllUniforms
     * @see UniformState
     * @see Context#draw
     * @see Context#createTexture2D
     * @see Context#createCubeMap
     *
     * @example
     * // Example 1. Create a shader program and set its
     * // one uniform, a 4x4 matrix, to the identity matrix
     * var vs =
     *   'attribute vec4 position; ' +
     *   'uniform mat4 u_mvp; ' +
     *   'void main() { gl_Position = u_mvp * position; }';
     * var fs = // ...
     * var sp = context.createShaderProgram(vs, fs);
     *
     * var mvp = sp.getAllUniforms().u_mvp;
     * console.log(mvp.getName());           // 'u_mvp'
     * console.log(mvp.getDatatype().name);  // 'FLOAT_MATRIX4'
     * mvp.value = Matrix4.IDENTITY;
     *
     * //////////////////////////////////////////////////////////////////////
     *
     * // Example 2. Setting values for a GLSL array uniform
     * // GLSL:  uniform float u_float[2];
     * sp.getAllUniforms().u_float.value = new Cartesian2(1.0, 2.0);
     *
     * // GLSL:  uniform vec4 u_vec4[2];
     * sp.getAllUniforms().u_vec4.value = [
     *   Cartesian4.UNIT_X,
     *   Cartesian4.UNIT_Y
     * ];
     *
     * //////////////////////////////////////////////////////////////////////
     *
     * // Example 3. Setting values for members of a GLSL struct
     * // GLSL:  uniform struct { float f; vec4 v; } u_struct;
     * sp.getAllUniforms()['u_struct.f'].value = 1.0;
     * sp.getAllUniforms()['u_struct.v'].value = new Cartesian4(1.0, 2.0, 3.0, 4.0);
     */
    var Uniform = function(_gl, activeUniform, _uniformName, _location, uniformValue) {
        /**
         * The value of the uniform.  The datatype depends on the datatype used in the
         * GLSL declaration as explained in the {@link Uniform} help and shown
         * in the examples below.
         *
         * @field
         * @alias Uniform#value
         *
         * @see Context#createTexture2D
         *
         * @example
         * // GLSL:  uniform float u_float;
         * sp.getAllUniforms().u_float.value = 1.0;
         *
         * // GLSL:  uniform vec4 u_vec4;
         * sp.getAllUniforms().u_vec4.value = Cartesian4.ZERO;
         *
         * // GLSL:  uniform bvec4 u_bvec4;
         * sp.getAllUniforms().u_bvec4.value = new Cartesian4(true, true, true, true);
         *
         * // GLSL:  uniform mat4 u_mat4;
         * sp.getAllUniforms().u_mat4.value = Matrix4.IDENTITY;
         *
         * // GLSL:  uniform sampler2D u_texture;
         * sp.getAllUniforms().u_texture.value = context.createTexture2D(...);
         *
         * // GLSL:  uniform vec2 u_vec2[2];
         * sp.getAllUniforms().u_vec2.value = [
         *   new Cartesian2(1.0, 2.0),
         *   new Cartesian2(3.0, 4.0)
         * ];
         *
         * // GLSL:  uniform struct { float f; vec4 v; } u_struct;
         * sp.getAllUniforms()['u_struct.f'].value = 1.0;
         * sp.getAllUniforms()['u_struct.v'].value = new Cartesian4(1.0, 2.0, 3.0, 4.0);
         */
        this.value = uniformValue;

        /**
         * Returns the case-sensitive name of the GLSL uniform.
         *
         * @returns {String} The name of the uniform.
         * @function
         * @alias Uniform#getName
         *
         * @example
         * // GLSL: uniform mat4 u_mvp;
         * console.log(sp.getAllUniforms().u_mvp.getName());  // 'u_mvp'
         */
        this.getName = function() {
            return _uniformName;
        };

        /**
         * Returns the datatype of the uniform.  This is useful when dynamically
         * creating a user interface to tweak shader uniform values.
         *
         * @returns {UniformDatatype} The datatype of the uniform.
         * @function
         * @alias Uniform#getDatatype
         *
         * @see UniformDatatype
         *
         * @example
         * // GLSL: uniform mat4 u_mvp;
         * console.log(sp.getAllUniforms().u_mvp.getDatatype().name);  // 'FLOAT_MATRIX4'
         */
        this.getDatatype = getUniformDatatype(_gl, activeUniform.type);

        this._getLocation = function() {
            return _location;
        };

        this._set = (function() {
            switch (activeUniform.type) {
            case _gl.FLOAT:
                return function() {
                    _gl.uniform1f(_location, this.value);
                };
            case _gl.FLOAT_VEC2:
                return function() {
                    var v = this.value;
                    _gl.uniform2f(_location, v.x, v.y);
                };
            case _gl.FLOAT_VEC3:
                return function() {
                    var v = this.value;
                    _gl.uniform3f(_location, v.x, v.y, v.z);
                };
            case _gl.FLOAT_VEC4:
                return function() {
                    var v = this.value;

                    if (defined(v.red)) {
                        _gl.uniform4f(_location, v.red, v.green, v.blue, v.alpha);
                    } else if (defined(v.x)) {
                        _gl.uniform4f(_location, v.x, v.y, v.z, v.w);
                    } else {
                        throw new DeveloperError('Invalid vec4 value for uniform "' + activeUniform.name + '".');
                    }
                };
            case _gl.SAMPLER_2D:
            case _gl.SAMPLER_CUBE:
                // See _setSampler()
                return undefined;
            case _gl.INT:
            case _gl.BOOL:
                return function() {
                    _gl.uniform1i(_location, this.value);
                };
            case _gl.INT_VEC2:
            case _gl.BOOL_VEC2:
                return function() {
                    var v = this.value;
                    _gl.uniform2i(_location, v.x, v.y);
                };
            case _gl.INT_VEC3:
            case _gl.BOOL_VEC3:
                return function() {
                    var v = this.value;
                    _gl.uniform3i(_location, v.x, v.y, v.z);
                };
            case _gl.INT_VEC4:
            case _gl.BOOL_VEC4:
                return function() {
                    var v = this.value;
                    _gl.uniform4i(_location, v.x, v.y, v.z, v.w);
                };
            case _gl.FLOAT_MAT2:
                return function() {
                    _gl.uniformMatrix2fv(_location, false, Matrix2.toArray(this.value, scratchUniformMatrix2));
                };
            case _gl.FLOAT_MAT3:
                return function() {
                    _gl.uniformMatrix3fv(_location, false, Matrix3.toArray(this.value, scratchUniformMatrix3));
                };
            case _gl.FLOAT_MAT4:
                return function() {
                    _gl.uniformMatrix4fv(_location, false, Matrix4.toArray(this.value, scratchUniformMatrix4));
                };
            default:
                throw new RuntimeError('Unrecognized uniform type: ' + activeUniform.type + ' for uniform "' + activeUniform.name + '".');
            }
        })();

        if ((activeUniform.type === _gl.SAMPLER_2D) || (activeUniform.type === _gl.SAMPLER_CUBE)) {
            this._setSampler = function(textureUnitIndex) {
                _gl.activeTexture(_gl.TEXTURE0 + textureUnitIndex);
                _gl.bindTexture(this.value._getTarget(), this.value._getTexture());
                _gl.uniform1i(_location, textureUnitIndex);

                return textureUnitIndex + 1;
            };

            this._clearSampler = function(textureUnitIndex) {
                _gl.activeTexture(_gl.TEXTURE0 + textureUnitIndex);
                _gl.bindTexture(this.value._getTarget(), null);

                return textureUnitIndex + 1;
            };
        }
    };

    /**
     * Uniform and UniformArray have the same documentation.  It is just an implementation
     * detail that they are two different types.
     *
     * @alias UniformArray
     * @constructor
     *
     * @see Uniform
     */
    var UniformArray = function(_gl, activeUniform, _uniformName, locations, value) {
        this.value = value;

        var _locations = locations;

        /**
         * @private
         */
        this.getName = function() {
            return _uniformName;
        };

        this.getDatatype = getUniformDatatype(_gl, activeUniform.type);

        this._getLocations = function() {
            return _locations;
        };

        this._set = (function() {
            switch (activeUniform.type) {
            case _gl.FLOAT:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniform1f(_locations[i], this.value[i]);
                    }
                };
            case _gl.FLOAT_VEC2:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform2f(_locations[i], v.x, v.y);
                    }
                };
            case _gl.FLOAT_VEC3:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform3f(_locations[i], v.x, v.y, v.z);
                    }
                };
            case _gl.FLOAT_VEC4:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];

                        if (defined(v.red)) {
                            _gl.uniform4f(_locations[i], v.red, v.green, v.blue, v.alpha);
                        } else if (defined(v.x)) {
                            _gl.uniform4f(_locations[i], v.x, v.y, v.z, v.w);
                        } else {
                            throw new DeveloperError('Invalid vec4 value.');
                        }
                    }
                };
            case _gl.SAMPLER_2D:
            case _gl.SAMPLER_CUBE:
                // See _setSampler()
                return undefined;
            case _gl.INT:
            case _gl.BOOL:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniform1i(_locations[i], this.value[i]);
                    }
                };
            case _gl.INT_VEC2:
            case _gl.BOOL_VEC2:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform2i(_locations[i], v.x, v.y);
                    }
                };
            case _gl.INT_VEC3:
            case _gl.BOOL_VEC3:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform3i(_locations[i], v.x, v.y, v.z);
                    }
                };
            case _gl.INT_VEC4:
            case _gl.BOOL_VEC4:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        var v = this.value[i];
                        _gl.uniform4i(_locations[i], v.x, v.y, v.z, v.w);
                    }
                };
            case _gl.FLOAT_MAT2:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniformMatrix2fv(_locations[i], false, Matrix2.toArray(this.value[i], scratchUniformMatrix2));
                    }
                };
            case _gl.FLOAT_MAT3:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniformMatrix3fv(_locations[i], false, Matrix3.toArray(this.value[i], scratchUniformMatrix3));
                    }
                };
            case _gl.FLOAT_MAT4:
                return function() {
                    for ( var i = 0; i < _locations.length; ++i) {
                        _gl.uniformMatrix4fv(_locations[i], false, Matrix4.toArray(this.value[i], scratchUniformMatrix4));
                    }
                };
            default:
                throw new RuntimeError('Unrecognized uniform type: ' + activeUniform.type);
            }
        })();

        if ((activeUniform.type === _gl.SAMPLER_2D) || (activeUniform.type === _gl.SAMPLER_CUBE)) {
            this._setSampler = function(textureUnitIndex) {
                for ( var i = 0; i < _locations.length; ++i) {
                    var value = this.value[i];
                    var index = textureUnitIndex + i;
                    _gl.activeTexture(_gl.TEXTURE0 + index);
                    _gl.bindTexture(value._getTarget(), value._getTexture());
                    _gl.uniform1i(_locations[i], index);
                }

                return textureUnitIndex + _locations.length;
            };

            this._clearSampler = function(textureUnitIndex) {
                for ( var i = 0; i < _locations.length; ++i) {
                    _gl.activeTexture(_gl.TEXTURE0 + textureUnitIndex + i);
                    _gl.bindTexture(this.value[i]._getTarget(), null);
                }

                return textureUnitIndex + _locations.length;
            };
        }
    };

    /**
     * DOC_TBA
     *
     * @alias ShaderProgram
     * @internalConstructor
     *
     * @see Context#createShaderProgram
     * @see Context#getShaderCache
     */
    var ShaderProgram = function(gl, logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations) {
        var program = createAndLinkProgram(gl, logShaderCompilation, vertexShaderSource, fragmentShaderSource, attributeLocations);
        var numberOfVertexAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
        var uniforms = findUniforms(gl, program);
        var partitionedUniforms = partitionUniforms(uniforms.allUniforms);

        this._gl = gl;
        this._program = program;
        this._numberOfVertexAttributes = numberOfVertexAttributes;
        this._vertexAttributes = findVertexAttributes(gl, program, numberOfVertexAttributes);
        this._allUniforms = uniforms.allUniforms;
        this._uniforms = uniforms.uniforms;
        this._samplerUniforms = uniforms.samplerUniforms;
        this._automaticUniforms = partitionedUniforms.automaticUniforms;
        this._manualUniforms = partitionedUniforms.manualUniforms;

        /**
         * 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.
         *
         * @type {String}
         *
         * @readonly
         */
        this.vertexShaderSource = 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.
         *
         * @type {String}
         *
         * @readonly
         */
        this.fragmentShaderSource = fragmentShaderSource;
    };

    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 && ShaderBuiltins.hasOwnProperty(element)) {
                    var referencedNode = getDependencyNode(element, ShaderBuiltins[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);
{'fraction_non_alphanumeric': 0.12190868738110336, 'fraction_numerical': 0.013193123370675686, 'mean_word_length': 1.5317962896896182, 'pattern_counts': {'":': 0, '<': 439, '<?xml version=': 0, '>': 409, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7226272', 'n_tokens_mistral': 16898, 'n_tokens_neox': 15974, 'n_words': 3658}