├── .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