UNPKG

5.46 kBJavaScriptView Raw
1'use strict'
2
3var coallesceUniforms = require('./reflect')
4
5module.exports = createUniformWrapper
6
7//Binds a function and returns a value
8function identity(x) {
9 var c = new Function('y', 'return function(){return y}')
10 return c(x)
11}
12
13function makeVector(length, fill) {
14 var result = new Array(length)
15 for(var i=0; i<length; ++i) {
16 result[i] = fill
17 }
18 return result
19}
20
21//Create shims for uniforms
22function createUniformWrapper(gl, wrapper, uniforms, locations) {
23
24 function makeGetter(index) {
25 var proc = new Function(
26 'gl'
27 , 'wrapper'
28 , 'locations'
29 , 'return function(){return gl.getUniform(wrapper.program,locations[' + index + '])}')
30 return proc(gl, wrapper, locations)
31 }
32
33 function makePropSetter(path, index, type) {
34 switch(type) {
35 case 'bool':
36 case 'int':
37 case 'sampler2D':
38 case 'samplerCube':
39 return 'gl.uniform1i(locations[' + index + '],obj' + path + ')'
40 case 'float':
41 return 'gl.uniform1f(locations[' + index + '],obj' + path + ')'
42 default:
43 var vidx = type.indexOf('vec')
44 if(0 <= vidx && vidx <= 1 && type.length === 4 + vidx) {
45 var d = type.charCodeAt(type.length-1) - 48
46 if(d < 2 || d > 4) {
47 throw new Error('gl-shader: Invalid data type')
48 }
49 switch(type.charAt(0)) {
50 case 'b':
51 case 'i':
52 return 'gl.uniform' + d + 'iv(locations[' + index + '],obj' + path + ')'
53 case 'v':
54 return 'gl.uniform' + d + 'fv(locations[' + index + '],obj' + path + ')'
55 default:
56 throw new Error('gl-shader: Unrecognized data type for vector ' + name + ': ' + type)
57 }
58 } else if(type.indexOf('mat') === 0 && type.length === 4) {
59 var d = type.charCodeAt(type.length-1) - 48
60 if(d < 2 || d > 4) {
61 throw new Error('gl-shader: Invalid uniform dimension type for matrix ' + name + ': ' + type)
62 }
63 return 'gl.uniformMatrix' + d + 'fv(locations[' + index + '],false,obj' + path + ')'
64 } else {
65 throw new Error('gl-shader: Unknown uniform data type for ' + name + ': ' + type)
66 }
67 break
68 }
69 }
70
71 function enumerateIndices(prefix, type) {
72 if(typeof type !== 'object') {
73 return [ [prefix, type] ]
74 }
75 var indices = []
76 for(var id in type) {
77 var prop = type[id]
78 var tprefix = prefix
79 if(parseInt(id) + '' === id) {
80 tprefix += '[' + id + ']'
81 } else {
82 tprefix += '.' + id
83 }
84 if(typeof prop === 'object') {
85 indices.push.apply(indices, enumerateIndices(tprefix, prop))
86 } else {
87 indices.push([tprefix, prop])
88 }
89 }
90 return indices
91 }
92
93 function makeSetter(type) {
94 var code = [ 'return function updateProperty(obj){' ]
95 var indices = enumerateIndices('', type)
96 for(var i=0; i<indices.length; ++i) {
97 var item = indices[i]
98 var path = item[0]
99 var idx = item[1]
100 if(locations[idx]) {
101 code.push(makePropSetter(path, idx, uniforms[idx].type))
102 }
103 }
104 code.push('return obj}')
105 var proc = new Function('gl', 'locations', code.join('\n'))
106 return proc(gl, locations)
107 }
108
109 function defaultValue(type) {
110 switch(type) {
111 case 'bool':
112 return false
113 case 'int':
114 case 'sampler2D':
115 case 'samplerCube':
116 return 0
117 case 'float':
118 return 0.0
119 default:
120 var vidx = type.indexOf('vec')
121 if(0 <= vidx && vidx <= 1 && type.length === 4 + vidx) {
122 var d = type.charCodeAt(type.length-1) - 48
123 if(d < 2 || d > 4) {
124 throw new Error('gl-shader: Invalid data type')
125 }
126 if(type.charAt(0) === 'b') {
127 return makeVector(d, false)
128 }
129 return makeVector(d, 0)
130 } else if(type.indexOf('mat') === 0 && type.length === 4) {
131 var d = type.charCodeAt(type.length-1) - 48
132 if(d < 2 || d > 4) {
133 throw new Error('gl-shader: Invalid uniform dimension type for matrix ' + name + ': ' + type)
134 }
135 return makeVector(d*d, 0)
136 } else {
137 throw new Error('gl-shader: Unknown uniform data type for ' + name + ': ' + type)
138 }
139 break
140 }
141 }
142
143 function storeProperty(obj, prop, type) {
144 if(typeof type === 'object') {
145 var child = processObject(type)
146 Object.defineProperty(obj, prop, {
147 get: identity(child),
148 set: makeSetter(type),
149 enumerable: true,
150 configurable: false
151 })
152 } else {
153 if(locations[type]) {
154 Object.defineProperty(obj, prop, {
155 get: makeGetter(type),
156 set: makeSetter(type),
157 enumerable: true,
158 configurable: false
159 })
160 } else {
161 obj[prop] = defaultValue(uniforms[type].type)
162 }
163 }
164 }
165
166 function processObject(obj) {
167 var result
168 if(Array.isArray(obj)) {
169 result = new Array(obj.length)
170 for(var i=0; i<obj.length; ++i) {
171 storeProperty(result, i, obj[i])
172 }
173 } else {
174 result = {}
175 for(var id in obj) {
176 storeProperty(result, id, obj[id])
177 }
178 }
179 return result
180 }
181
182 //Return data
183 var coallesced = coallesceUniforms(uniforms, true)
184 return {
185 get: identity(processObject(coallesced)),
186 set: makeSetter(coallesced),
187 enumerable: true,
188 configurable: true
189 }
190}