├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── example └── example.js ├── index.js ├── lib ├── GLError.js ├── create-attributes.js ├── create-uniforms.js ├── reflect.js ├── runtime-reflect.js └── shader-cache.js ├── package.json └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | package-lock.json 16 | node_modules/* -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/* 16 | example/* 17 | screenshot.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013 Mikola Lysenko 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gl-shader 2 | ========= 3 | A wrapper for WebGL shaders. Part of [stack.gl](http://stack.gl) 4 | 5 | # Example 6 | 7 | Try it out now in your browser: [http://stackgl.github.io/gl-shader/](http://stackgl.github.io/gl-shader/) 8 | 9 | ```javascript 10 | var shell = require('gl-now')() 11 | var createShader = require('gl-shader') 12 | var shader, buffer 13 | 14 | shell.on('gl-init', function() { 15 | var gl = shell.gl 16 | 17 | //Create shader 18 | shader = createShader(gl, 19 | 'attribute vec3 position;\ 20 | varying vec2 uv;\ 21 | void main() {\ 22 | gl_Position = vec4(position, 1.0);\ 23 | uv = position.xy;\ 24 | }', 25 | 'precision highp float;\ 26 | uniform float t;\ 27 | varying vec2 uv;\ 28 | void main() {\ 29 | gl_FragColor = vec4(0.5*(uv+1.0), 0.5*(cos(t)+1.0), 1.0);\ 30 | }') 31 | 32 | //Create vertex buffer 33 | buffer = gl.createBuffer() 34 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer) 35 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 36 | -1, 0, 0, 37 | 0, -1, 0, 38 | 1, 1, 0 39 | ]), gl.STATIC_DRAW) 40 | }) 41 | 42 | shell.on('gl-render', function(t) { 43 | var gl = shell.gl 44 | 45 | //Bind shader 46 | shader.bind() 47 | 48 | //Set attributes 49 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer) 50 | shader.attributes.position.pointer() 51 | 52 | //Set uniforms 53 | shader.uniforms.t += 0.01 54 | 55 | //Draw 56 | gl.drawArrays(gl.TRIANGLES, 0, 3) 57 | }) 58 | ``` 59 | 60 | Here is the result: 61 | 62 | 63 | 64 | # Install 65 | 66 | npm install gl-shader 67 | 68 | # API 69 | 70 | ```javascript 71 | var createShader = require('gl-shader') 72 | ``` 73 | 74 | 75 | ### Constructor 76 | 77 | There are two main usages for the constructor. First, 78 | 79 | #### `var shader = createShader(gl, vertexSource, fragmentSource[, uniforms, attributes])` 80 | 81 | Constructs a wrapped shader object with shims for all of the uniforms and attributes in the program. 82 | 83 | * `gl` is the webgl context in which the program will be created 84 | * `vertexSource` is the source code for the vertex shader 85 | * `fragmentSource` is the source code for the fragment shader 86 | * `uniforms` is an (optional) list of all uniforms exported by the shader program 87 | * `attributes` is an (optional) list of all attributes exported by the shader program 88 | 89 | The optional `uniforms` and `attributes` arrays have the following format. This will be extracted at run-time from the shader, so you can typically omit the `uniforms` and `attributes` arguments. 90 | 91 | ```js 92 | { 93 | uniforms: [ 94 | { type: 'mat4', name: 'projection' }, 95 | { type: 'sampler2D', name: 'texture0' } 96 | ], 97 | attributes: [ 98 | { type: 'vec3', name: 'position' } 99 | ] 100 | } 101 | ``` 102 | 103 | You can specify a default `location` number for each attribute, otherwise WebGL will bind it automatically. 104 | 105 | **Returns** A compiled shader object. 106 | 107 | #### `var shader = createShader(gl, opt)` 108 | 109 | The same as above, but takes an object instead of a parameter list. 110 | 111 | * `gl` is a WebGL context 112 | * `opt.vertex` a vertex shader source 113 | * `opt.fragment` a fragment shader source 114 | * `opt.uniforms` (optional) a list of uniforms 115 | * `opt.attributes` (optional) a list of attributes 116 | 117 | **Returns** A wrapped shader object 118 | 119 | ### Methods 120 | 121 | #### `shader.bind()` 122 | Binds the shader for rendering 123 | 124 | #### `shader.update(vertSource,fragSource[,uniforms,attributes])` 125 | Rebuilds the shader object with new vertex and fragment shaders (same behavior as constructor) 126 | 127 | #### `shader.update(opt)` 128 | Rebuilds the shader object with new vertex and fragment shaders (same behavior as constructor) 129 | 130 | #### `shader.dispose()` 131 | Deletes the shader program and associated resources. 132 | 133 | ### Properties 134 | 135 | #### `gl` 136 | The WebGL context associated to the shader 137 | 138 | #### `program` 139 | A reference to the underlying program object in the WebGL context 140 | 141 | #### `vertShader` 142 | A reference to the underlying vertex shader object 143 | 144 | #### `fragShader` 145 | A reference to the underlying fragment shader object 146 | 147 | ### Uniforms 148 | The uniforms for the shader program are packaged up as properties in the `shader.uniforms` object. The shader must be bound before the uniforms are assigned. For example, to update a scalar uniform you can just assign to it: 149 | 150 | ```javascript 151 | shader.bind() 152 | shader.uniforms.scalar = 1.0 153 | ``` 154 | 155 | While you can update vector uniforms by writing an array to them: 156 | 157 | ```javascript 158 | shader.uniforms.vector = [1,0,1,0] 159 | ``` 160 | 161 | Matrix uniforms must have their arrays flattened first: 162 | 163 | ```javascript 164 | shader.uniforms.matrix = [ 1, 0, 1, 0, 165 | 0, 1, 0, 0, 166 | 0, 0, 1, 1, 167 | 0, 0, 0, 1 ] 168 | ``` 169 | 170 | You can read the value of uniform too if the underlying shader is currently bound. For example, 171 | 172 | ```javascript 173 | shader.bind() 174 | console.log(shader.uniforms.scalar) 175 | console.log(shader.uniforms.vector) 176 | console.log(shader.uniforms.matrix) 177 | ``` 178 | 179 | Struct uniforms can also be accessed using the normal dot property syntax: 180 | 181 | ```javascript 182 | shader.uniforms.light[0].color = [1, 0, 0, 1] 183 | ``` 184 | 185 | It is also possible to initialize uniforms in bulk by assigning an object: 186 | 187 | ```javascript 188 | shader.uniforms = { 189 | model: [1, 0, 0, 0, 190 | 0, 1, 0, 0, 191 | 0, 0, 1, 0, 192 | 0, 0, 0, 1], 193 | color: [1, 0, 1, 1] 194 | } 195 | ``` 196 | 197 | The contents of uniform values are lost when a shader is unbound. 198 | 199 | ### Attributes 200 | 201 | The basic idea behind the attribute interface is similar to that for uniforms, however because attributes can be either a constant value or get values from a vertex array they have a slightly more complicated interface. All of the attributes are stored in the `shader.attributes` property. 202 | 203 | #### `attrib = constant` 204 | For non-array attributes you can set the constant value to be broadcast across all vertices. For example, to set the vertex color of a shader to a constant you could do: 205 | 206 | ```javascript 207 | shader.attributes.color = [1, 0, 0, 1] 208 | ``` 209 | 210 | This internally uses [`gl.vertexAttribnf`](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttrib.xml). Setting the attribute will also call `gl.disableVertexAttribArray` on the attribute's location. 211 | 212 | #### `attrib.location` 213 | This property accesses the location of the attribute. You can assign/read from it to modify the location of the attribute. For example, you can update the location by doing: 214 | 215 | ```javascript 216 | attrib.location = 0 217 | ``` 218 | 219 | Or you can read the currently bound location back by just accessing it: 220 | 221 | ```javascript 222 | console.log(attrib.location) 223 | ``` 224 | 225 | **WARNING** Changing the attribute location requires recompiling the program. This recompilation is deferred until the next call to `.bind()` 226 | 227 | #### `attrib.pointer([type, normalized, stride, offset])` 228 | A shortcut for `gl.vertexAttribPointer`/`gl.enableVertexAttribArray`. See the [OpenGL man page for details on how this works](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttribPointer.xml). The main difference here is that the WebGL context, size and index are known and so these parameters are bound. 229 | 230 | * `type` is the type of the pointer (default `gl.FLOAT`) 231 | * `normalized` specifies whether fixed-point data values should be normalized (`true`) or converted directly as fixed-point values (`false`) when they are accessed. (Default `false`) 232 | * `stride` the byte offset between consecutive generic vertex attributes. (Default: `0`) 233 | * `offset` offset of the first element of the array in bytes. (Default `0`) 234 | 235 | #### Matrix attributes 236 | 237 | Matrix attributes are also supported, however there are a few subtle difference. Due to WebGL limitations, d-dimensional matrix attributes require d separate attribute locations. If `matrix` is a matrix attribute, then the rows of the matrix can be accessed independently using: 238 | 239 | ```javascript 240 | //First row of matrix 241 | shader.attributes.matrix[0] 242 | 243 | //Second row 244 | shader.attributes.matrix[1] 245 | 246 | // ... etc. 247 | ``` 248 | 249 | The interface for these attributes is identical to the above interfaces for vector attributes (support constant setters, `.pointer()`, and `.location`). 250 | 251 | There is also a bulk interface which simplifies working with the matrix as a whole unit. For example, it is possible to update the location of each row of the matrix simultaneously by assigning it a vector value: 252 | 253 | ```javascript 254 | shader.attributes.matrix.location = [1, 2, 3, 4] 255 | ``` 256 | 257 | Similarly, if the matrix attribute is stored as a contiguous range in memory, the pointer for each row can be set using `.pointer()`. For example, if `matrix` is a 4x4 matrix attribute then, 258 | 259 | ```javascript 260 | shader.attributes.matrix.pointer(gl.FLOAT, false, 16, 0) 261 | ``` 262 | 263 | is equivalent to, 264 | 265 | ```javascript 266 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 0) 267 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 4) 268 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 8) 269 | shader.attributes.matrix[0].pointer(gl.FLOAT, false, 16, 12) 270 | ``` 271 | 272 | ### Reflection 273 | 274 | Finally, the library supports some reflection capabilities. The set of all uniforms and data types are stored in the "type" property of the shader object, 275 | 276 | ```javascript 277 | console.log(shader.types) 278 | ``` 279 | 280 | This reflects the uniform and attribute parameters that were passed to the shader constructor. 281 | 282 | ## Acknowledgements 283 | 284 | (c) 2013-2015 Mikola Lysenko. MIT License 285 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | var shell = require("gl-now")() 2 | var makeShader = require("../index.js") 3 | var shader 4 | var buffer 5 | 6 | shell.on("gl-init", function() { 7 | var gl = shell.gl 8 | 9 | //Create shader 10 | shader = makeShader(gl, 11 | "attribute vec3 position;\ 12 | attribute vec3 color;\ 13 | uniform mat4 matrix;\ 14 | varying vec3 fcolor;\ 15 | void main() {\ 16 | gl_Position = matrix * vec4(position, 1.0);\ 17 | fcolor = color;\ 18 | }", 19 | "precision highp float;\ 20 | uniform vec3 tp;\ 21 | varying vec3 fcolor;\ 22 | void main() {\ 23 | gl_FragColor = vec4(fcolor + tp, 1.0);\ 24 | }") 25 | 26 | shader.attributes.position.location = 0 27 | shader.attributes.color.location = 1 28 | 29 | //Create vertex buffer 30 | buffer = gl.createBuffer() 31 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer) 32 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 33 | -1, 0, 0, 34 | 0, -1, 0, 35 | 1, 1, 0 36 | ]), gl.STATIC_DRAW) 37 | }) 38 | 39 | shell.on("gl-render", function(t) { 40 | var gl = shell.gl 41 | 42 | //Bind shader 43 | shader.bind() 44 | 45 | //Set attributes 46 | gl.bindBuffer(gl.ARRAY_BUFFER, buffer) 47 | shader.attributes.position.pointer() 48 | shader.attributes.color = [1, 0, 1] 49 | 50 | //Set uniforms 51 | shader.uniforms.tp = [Math.cos(0.001 * Date.now()), 1, 0] 52 | shader.uniforms.matrix = [1, 0, 0, 0, 53 | 0, 1, 0, 0, 54 | 0, 0, 1, 0, 55 | 0, 0, 0, 1] 56 | 57 | //Draw 58 | gl.drawArrays(gl.TRIANGLES, 0, 3) 59 | }) -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var createUniformWrapper = require('./lib/create-uniforms') 4 | var createAttributeWrapper = require('./lib/create-attributes') 5 | var makeReflect = require('./lib/reflect') 6 | var shaderCache = require('./lib/shader-cache') 7 | var runtime = require('./lib/runtime-reflect') 8 | var GLError = require("./lib/GLError") 9 | 10 | //Shader object 11 | function Shader(gl) { 12 | this.gl = gl 13 | this.gl.lastAttribCount = 0 // fixme where else should we store info, safe but not nice on the gl object 14 | 15 | //Default initialize these to null 16 | this._vref = 17 | this._fref = 18 | this._relink = 19 | this.vertShader = 20 | this.fragShader = 21 | this.program = 22 | this.attributes = 23 | this.uniforms = 24 | this.types = null 25 | } 26 | 27 | var proto = Shader.prototype 28 | 29 | proto.bind = function() { 30 | if(!this.program) { 31 | this._relink() 32 | } 33 | 34 | // ensuring that we have the right number of enabled vertex attributes 35 | var i 36 | var newAttribCount = this.gl.getProgramParameter(this.program, this.gl.ACTIVE_ATTRIBUTES) // more robust approach 37 | //var newAttribCount = Object.keys(this.attributes).length // avoids the probably immaterial introspection slowdown 38 | var oldAttribCount = this.gl.lastAttribCount 39 | if(newAttribCount > oldAttribCount) { 40 | for(i = oldAttribCount; i < newAttribCount; i++) { 41 | this.gl.enableVertexAttribArray(i) 42 | } 43 | } else if(oldAttribCount > newAttribCount) { 44 | for(i = newAttribCount; i < oldAttribCount; i++) { 45 | this.gl.disableVertexAttribArray(i) 46 | } 47 | } 48 | 49 | this.gl.lastAttribCount = newAttribCount 50 | 51 | this.gl.useProgram(this.program) 52 | } 53 | 54 | proto.dispose = function() { 55 | 56 | // disabling vertex attributes so new shader starts with zero 57 | // and it's also useful if all shaders are disposed but the 58 | // gl context is reused for subsequent replotting 59 | var oldAttribCount = this.gl.lastAttribCount 60 | for (var i = 0; i < oldAttribCount; i++) { 61 | this.gl.disableVertexAttribArray(i) 62 | } 63 | this.gl.lastAttribCount = 0 64 | 65 | if(this._fref) { 66 | this._fref.dispose() 67 | } 68 | if(this._vref) { 69 | this._vref.dispose() 70 | } 71 | this.attributes = 72 | this.types = 73 | this.vertShader = 74 | this.fragShader = 75 | this.program = 76 | this._relink = 77 | this._fref = 78 | this._vref = null 79 | } 80 | 81 | function compareAttributes(a, b) { 82 | if(a.name < b.name) { 83 | return -1 84 | } 85 | return 1 86 | } 87 | 88 | //Update export hook for glslify-live 89 | proto.update = function( 90 | vertSource 91 | , fragSource 92 | , uniforms 93 | , attributes) { 94 | 95 | //If only one object passed, assume glslify style output 96 | if(!fragSource || arguments.length === 1) { 97 | var obj = vertSource 98 | vertSource = obj.vertex 99 | fragSource = obj.fragment 100 | uniforms = obj.uniforms 101 | attributes = obj.attributes 102 | } 103 | 104 | var wrapper = this 105 | var gl = wrapper.gl 106 | 107 | //Compile vertex and fragment shaders 108 | var pvref = wrapper._vref 109 | wrapper._vref = shaderCache.shader(gl, gl.VERTEX_SHADER, vertSource) 110 | if(pvref) { 111 | pvref.dispose() 112 | } 113 | wrapper.vertShader = wrapper._vref.shader 114 | var pfref = this._fref 115 | wrapper._fref = shaderCache.shader(gl, gl.FRAGMENT_SHADER, fragSource) 116 | if(pfref) { 117 | pfref.dispose() 118 | } 119 | wrapper.fragShader = wrapper._fref.shader 120 | 121 | //If uniforms/attributes is not specified, use RT reflection 122 | if(!uniforms || !attributes) { 123 | 124 | //Create initial test program 125 | var testProgram = gl.createProgram() 126 | gl.attachShader(testProgram, wrapper.fragShader) 127 | gl.attachShader(testProgram, wrapper.vertShader) 128 | gl.linkProgram(testProgram) 129 | if(!gl.getProgramParameter(testProgram, gl.LINK_STATUS)) { 130 | var errLog = gl.getProgramInfoLog(testProgram) 131 | throw new GLError(errLog, 'Error linking program:' + errLog) 132 | } 133 | 134 | //Load data from runtime 135 | uniforms = uniforms || runtime.uniforms(gl, testProgram) 136 | attributes = attributes || runtime.attributes(gl, testProgram) 137 | 138 | //Release test program 139 | gl.deleteProgram(testProgram) 140 | } 141 | 142 | //Sort attributes lexicographically 143 | // overrides undefined WebGL behavior for attribute locations 144 | attributes = attributes.slice() 145 | attributes.sort(compareAttributes) 146 | 147 | //Convert attribute types, read out locations 148 | var attributeUnpacked = [] 149 | var attributeNames = [] 150 | var attributeLocations = [] 151 | var i 152 | for(i=0; i= 0) { 155 | var size = attr.type.charAt(attr.type.length-1)|0 156 | var locVector = new Array(size) 157 | for(var j=0; j= 0) { 195 | curLocation += 1 196 | } 197 | attributeLocations[i] = curLocation 198 | } 199 | } 200 | 201 | //Rebuild program and recompute all uniform locations 202 | var uniformLocations = new Array(uniforms.length) 203 | function relink() { 204 | wrapper.program = shaderCache.program( 205 | gl 206 | , wrapper._vref 207 | , wrapper._fref 208 | , attributeNames 209 | , attributeLocations) 210 | 211 | for(var i=0; i= 0) { 251 | var d = type.charCodeAt(type.length-1) - 48 252 | if(d < 2 || d > 4) { 253 | throw new GLError('', 'Invalid data type for attribute ' + name + ': ' + type) 254 | } 255 | addVectorAttribute( 256 | gl 257 | , wrapper 258 | , locs[0] 259 | , locations 260 | , d 261 | , obj 262 | , name) 263 | } else if(type.indexOf('mat') >= 0) { 264 | var d = type.charCodeAt(type.length-1) - 48 265 | if(d < 2 || d > 4) { 266 | throw new GLError('', 'Invalid data type for attribute ' + name + ': ' + type) 267 | } 268 | addMatrixAttribute( 269 | gl 270 | , wrapper 271 | , locs 272 | , locations 273 | , d 274 | , obj 275 | , name) 276 | } else { 277 | throw new GLError('', 'Unknown data type for attribute ' + name + ': ' + type) 278 | } 279 | break 280 | } 281 | } 282 | return obj 283 | } 284 | -------------------------------------------------------------------------------- /lib/create-uniforms.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var coallesceUniforms = require('./reflect') 4 | var GLError = require("./GLError") 5 | 6 | module.exports = createUniformWrapper 7 | 8 | //Binds a function and returns a value 9 | function identity(x) { 10 | return function() { 11 | return x 12 | } 13 | } 14 | 15 | function makeVector(length, fill) { 16 | var result = new Array(length) 17 | for(var i=0; i 4) { 77 | throw new GLError('', 'Invalid data type') 78 | } 79 | switch(t.charAt(0)) { 80 | case 'b': 81 | case 'i': 82 | gl['uniform' + d + 'iv'](locations[idx], objPath) 83 | break 84 | case 'v': 85 | gl['uniform' + d + 'fv'](locations[idx], objPath) 86 | break 87 | default: 88 | throw new GLError('', 'Unrecognized data type for vector ' + name + ': ' + t) 89 | } 90 | } else if(t.indexOf('mat') === 0 && t.length === 4) { 91 | d = t.charCodeAt(t.length-1) - 48 92 | if(d < 2 || d > 4) { 93 | throw new GLError('', 'Invalid uniform dimension type for matrix ' + name + ': ' + t) 94 | } 95 | gl['uniformMatrix' + d + 'fv'](locations[idx], false, objPath) 96 | break 97 | } else { 98 | throw new GLError('', 'Unknown uniform data type for ' + name + ': ' + t) 99 | } 100 | } 101 | } 102 | } 103 | } 104 | } 105 | 106 | function enumerateIndices(prefix, type) { 107 | if(typeof type !== 'object') { 108 | return [ [prefix, type] ] 109 | } 110 | var indices = [] 111 | for(var id in type) { 112 | var prop = type[id] 113 | var tprefix = prefix 114 | if(parseInt(id) + '' === id) { 115 | tprefix += '[' + id + ']' 116 | } else { 117 | tprefix += '.' + id 118 | } 119 | if(typeof prop === 'object') { 120 | indices.push.apply(indices, enumerateIndices(tprefix, prop)) 121 | } else { 122 | indices.push([tprefix, prop]) 123 | } 124 | } 125 | return indices 126 | } 127 | 128 | 129 | function defaultValue(type) { 130 | switch(type) { 131 | case 'bool': 132 | return false 133 | case 'int': 134 | case 'sampler2D': 135 | case 'samplerCube': 136 | return 0 137 | case 'float': 138 | return 0.0 139 | default: 140 | var vidx = type.indexOf('vec') 141 | if(0 <= vidx && vidx <= 1 && type.length === 4 + vidx) { 142 | var d = type.charCodeAt(type.length-1) - 48 143 | if(d < 2 || d > 4) { 144 | throw new GLError('', 'Invalid data type') 145 | } 146 | if(type.charAt(0) === 'b') { 147 | return makeVector(d, false) 148 | } 149 | return makeVector(d, 0) 150 | } else if(type.indexOf('mat') === 0 && type.length === 4) { 151 | var d = type.charCodeAt(type.length-1) - 48 152 | if(d < 2 || d > 4) { 153 | throw new GLError('', 'Invalid uniform dimension type for matrix ' + name + ': ' + type) 154 | } 155 | return makeVector(d*d, 0) 156 | } else { 157 | throw new GLError('', 'Unknown uniform data type for ' + name + ': ' + type) 158 | } 159 | } 160 | } 161 | 162 | function storeProperty(obj, prop, type) { 163 | if(typeof type === 'object') { 164 | var child = processObject(type) 165 | Object.defineProperty(obj, prop, { 166 | get: identity(child), 167 | set: makeSetter(type), 168 | enumerable: true, 169 | configurable: false 170 | }) 171 | } else { 172 | if(locations[type]) { 173 | Object.defineProperty(obj, prop, { 174 | get: makeGetter(type), 175 | set: makeSetter(type), 176 | enumerable: true, 177 | configurable: false 178 | }) 179 | } else { 180 | obj[prop] = defaultValue(uniforms[type].type) 181 | } 182 | } 183 | } 184 | 185 | function processObject(obj) { 186 | var result 187 | if(Array.isArray(obj)) { 188 | result = new Array(obj.length) 189 | for(var i=0; i 1) { 19 | if(!(x[0] in o)) { 20 | o[x[0]] = [] 21 | } 22 | o = o[x[0]] 23 | for(var k=1; k 1) { 48 | for(var j=0; j