1 | 'use strict'
|
2 |
|
3 | module.exports = createAttributeWrapper
|
4 |
|
5 | function ShaderAttribute(
|
6 | gl
|
7 | , wrapper
|
8 | , index
|
9 | , locations
|
10 | , dimension
|
11 | , constFunc) {
|
12 | this._gl = gl
|
13 | this._wrapper = wrapper
|
14 | this._index = index
|
15 | this._locations = locations
|
16 | this._dimension = dimension
|
17 | this._constFunc = constFunc
|
18 | }
|
19 |
|
20 | var proto = ShaderAttribute.prototype
|
21 |
|
22 | proto.pointer = function setAttribPointer(
|
23 | type
|
24 | , normalized
|
25 | , stride
|
26 | , offset) {
|
27 |
|
28 | var self = this
|
29 | var gl = self._gl
|
30 | var location = self._locations[self._index]
|
31 |
|
32 | gl.vertexAttribPointer(
|
33 | location
|
34 | , self._dimension
|
35 | , type || gl.FLOAT
|
36 | , !!normalized
|
37 | , stride || 0
|
38 | , offset || 0)
|
39 | gl.enableVertexAttribArray(location)
|
40 | }
|
41 |
|
42 | proto.set = function(x0, x1, x2, x3) {
|
43 | return this._constFunc(this._locations[this._index], x0, x1, x2, x3)
|
44 | }
|
45 |
|
46 | Object.defineProperty(proto, 'location', {
|
47 | get: function() {
|
48 | return this._locations[this._index]
|
49 | }
|
50 | , set: function(v) {
|
51 | if(v !== this._locations[this._index]) {
|
52 | this._locations[this._index] = v|0
|
53 | this._wrapper.program = null
|
54 | }
|
55 | return v|0
|
56 | }
|
57 | })
|
58 |
|
59 |
|
60 | function addVectorAttribute(
|
61 | gl
|
62 | , wrapper
|
63 | , index
|
64 | , locations
|
65 | , dimension
|
66 | , obj
|
67 | , name) {
|
68 |
|
69 |
|
70 | var constFuncArgs = [ 'gl', 'v' ]
|
71 | var varNames = []
|
72 | for(var i=0; i<dimension; ++i) {
|
73 | constFuncArgs.push('x'+i)
|
74 | varNames.push('x'+i)
|
75 | }
|
76 | constFuncArgs.push(
|
77 | 'if(x0.length===void 0){return gl.vertexAttrib' +
|
78 | dimension + 'f(v,' +
|
79 | varNames.join() +
|
80 | ')}else{return gl.vertexAttrib' +
|
81 | dimension +
|
82 | 'fv(v,x0)}')
|
83 | var constFunc = Function.apply(null, constFuncArgs)
|
84 |
|
85 |
|
86 | var attr = new ShaderAttribute(
|
87 | gl
|
88 | , wrapper
|
89 | , index
|
90 | , locations
|
91 | , dimension
|
92 | , constFunc)
|
93 |
|
94 |
|
95 | Object.defineProperty(obj, name, {
|
96 | set: function(x) {
|
97 | gl.disableVertexAttribArray(locations[index])
|
98 | constFunc(gl, locations[index], x)
|
99 | return x
|
100 | }
|
101 | , get: function() {
|
102 | return attr
|
103 | }
|
104 | , enumerable: true
|
105 | })
|
106 | }
|
107 |
|
108 | function addMatrixAttribute(
|
109 | gl
|
110 | , wrapper
|
111 | , index
|
112 | , locations
|
113 | , dimension
|
114 | , obj
|
115 | , name) {
|
116 |
|
117 | var parts = new Array(dimension)
|
118 | var attrs = new Array(dimension)
|
119 | for(var i=0; i<dimension; ++i) {
|
120 | addVectorAttribute(
|
121 | gl
|
122 | , wrapper
|
123 | , index[i]
|
124 | , locations
|
125 | , dimension
|
126 | , parts
|
127 | , i)
|
128 | attrs[i] = parts[i]
|
129 | }
|
130 |
|
131 | Object.defineProperty(parts, 'location', {
|
132 | set: function(v) {
|
133 | if(Array.isArray(v)) {
|
134 | for(var i=0; i<dimension; ++i) {
|
135 | attrs[i].location = v[i]
|
136 | }
|
137 | } else {
|
138 | for(var i=0; i<dimension; ++i) {
|
139 | attrs[i].location = v + i
|
140 | }
|
141 | }
|
142 | return v
|
143 | }
|
144 | , get: function() {
|
145 | var result = new Array(dimension)
|
146 | for(var i=0; i<dimension; ++i) {
|
147 | result[i] = locations[index[i]]
|
148 | }
|
149 | return result
|
150 | }
|
151 | , enumerable: true
|
152 | })
|
153 |
|
154 | parts.pointer = function(type, normalized, stride, offset) {
|
155 | type = type || gl.FLOAT
|
156 | normalized = !!normalized
|
157 | stride = stride || (dimension * dimension)
|
158 | offset = offset || 0
|
159 | for(var i=0; i<dimension; ++i) {
|
160 | var location = locations[index[i]]
|
161 | gl.vertexAttribPointer(
|
162 | location
|
163 | , dimension
|
164 | , type
|
165 | , normalized
|
166 | , stride
|
167 | , offset + i * dimension)
|
168 | gl.enableVertexAttribArray(location)
|
169 | }
|
170 | }
|
171 |
|
172 | var scratch = new Array(dimension)
|
173 | var vertexAttrib = gl['vertexAttrib' + dimension + 'fv']
|
174 |
|
175 | Object.defineProperty(obj, name, {
|
176 | set: function(x) {
|
177 | for(var i=0; i<dimension; ++i) {
|
178 | var loc = locations[index[i]]
|
179 | gl.disableVertexAttribArray(loc)
|
180 | if(Array.isArray(x[0])) {
|
181 | vertexAttrib.call(gl, loc, x[i])
|
182 | } else {
|
183 | for(var j=0; j<dimension; ++j) {
|
184 | scratch[j] = x[dimension*i + j]
|
185 | }
|
186 | vertexAttrib.call(gl, loc, scratch)
|
187 | }
|
188 | }
|
189 | return x
|
190 | }
|
191 | , get: function() {
|
192 | return parts
|
193 | }
|
194 | , enumerable: true
|
195 | })
|
196 | }
|
197 |
|
198 |
|
199 | function createAttributeWrapper(
|
200 | gl
|
201 | , wrapper
|
202 | , attributes
|
203 | , locations) {
|
204 |
|
205 | var obj = {}
|
206 | for(var i=0, n=attributes.length; i<n; ++i) {
|
207 |
|
208 | var a = attributes[i]
|
209 | var name = a.name
|
210 | var type = a.type
|
211 | var locs = a.locations
|
212 |
|
213 | switch(type) {
|
214 | case 'bool':
|
215 | case 'int':
|
216 | case 'float':
|
217 | addVectorAttribute(
|
218 | gl
|
219 | , wrapper
|
220 | , locs[0]
|
221 | , locations
|
222 | , 1
|
223 | , obj
|
224 | , name)
|
225 | break
|
226 |
|
227 | default:
|
228 | if(type.indexOf('vec') >= 0) {
|
229 | var d = type.charCodeAt(type.length-1) - 48
|
230 | if(d < 2 || d > 4) {
|
231 | throw new Error('gl-shader: Invalid data type for attribute ' + name + ': ' + type)
|
232 | }
|
233 | addVectorAttribute(
|
234 | gl
|
235 | , wrapper
|
236 | , locs[0]
|
237 | , locations
|
238 | , d
|
239 | , obj
|
240 | , name)
|
241 | } else if(type.indexOf('mat') >= 0) {
|
242 | var d = type.charCodeAt(type.length-1) - 48
|
243 | if(d < 2 || d > 4) {
|
244 | throw new Error('gl-shader: Invalid data type for attribute ' + name + ': ' + type)
|
245 | }
|
246 | addMatrixAttribute(
|
247 | gl
|
248 | , wrapper
|
249 | , locs
|
250 | , locations
|
251 | , d
|
252 | , obj
|
253 | , name)
|
254 | } else {
|
255 | throw new Error('gl-shader: Unknown data type for attribute ' + name + ': ' + type)
|
256 | }
|
257 | break
|
258 | }
|
259 | }
|
260 | return obj
|
261 | }
|