UNPKG

5.98 kBJavaScriptView Raw
1'use strict'
2
3var createUniformWrapper = require('./lib/create-uniforms')
4var createAttributeWrapper = require('./lib/create-attributes')
5var makeReflect = require('./lib/reflect')
6var shaderCache = require('./lib/shader-cache')
7var runtime = require('./lib/runtime-reflect')
8
9//Shader object
10function Shader(gl) {
11 this.gl = gl
12
13 //Default initialize these to null
14 this._vref =
15 this._fref =
16 this._relink =
17 this.vertShader =
18 this.fragShader =
19 this.program =
20 this.attributes =
21 this.uniforms =
22 this.types = null
23}
24
25var proto = Shader.prototype
26
27proto.bind = function() {
28 if(!this.program) {
29 this._relink()
30 }
31 this.gl.useProgram(this.program)
32}
33
34proto.dispose = function() {
35 if(this._fref) {
36 this._fref.dispose()
37 }
38 if(this._vref) {
39 this._vref.dispose()
40 }
41 this.attributes =
42 this.types =
43 this.vertShader =
44 this.fragShader =
45 this.program =
46 this._relink =
47 this._fref =
48 this._vref = null
49}
50
51function compareAttributes(a, b) {
52 if(a.name < b.name) {
53 return -1
54 }
55 return 1
56}
57
58//Update export hook for glslify-live
59proto.update = function(
60 vertSource
61 , fragSource
62 , uniforms
63 , attributes) {
64
65 //If only one object passed, assume glslify style output
66 if(!fragSource || arguments.length === 1) {
67 var obj = vertSource
68 vertSource = obj.vertex
69 fragSource = obj.fragment
70 uniforms = obj.uniforms
71 attributes = obj.attributes
72 }
73
74 var wrapper = this
75 var gl = wrapper.gl
76
77 //Compile vertex and fragment shaders
78 var pvref = wrapper._vref
79 wrapper._vref = shaderCache.shader(gl, gl.VERTEX_SHADER, vertSource)
80 if(pvref) {
81 pvref.dispose()
82 }
83 wrapper.vertShader = wrapper._vref.shader
84 var pfref = this._fref
85 wrapper._fref = shaderCache.shader(gl, gl.FRAGMENT_SHADER, fragSource)
86 if(pfref) {
87 pfref.dispose()
88 }
89 wrapper.fragShader = wrapper._fref.shader
90
91 //If uniforms/attributes is not specified, use RT reflection
92 if(!uniforms || !attributes) {
93
94 //Create initial test program
95 var testProgram = gl.createProgram()
96 gl.attachShader(testProgram, wrapper.fragShader)
97 gl.attachShader(testProgram, wrapper.vertShader)
98 gl.linkProgram(testProgram)
99 if(!gl.getProgramParameter(testProgram, gl.LINK_STATUS)) {
100 var errLog = gl.getProgramInfoLog(testProgram)
101 console.error('gl-shader: Error linking program:', errLog)
102 throw new Error('gl-shader: Error linking program:' + errLog)
103 }
104
105 //Load data from runtime
106 uniforms = uniforms || runtime.uniforms(gl, testProgram)
107 attributes = attributes || runtime.attributes(gl, testProgram)
108
109 //Release test program
110 gl.deleteProgram(testProgram)
111 }
112
113 //Sort attributes lexicographically
114 // overrides undefined WebGL behavior for attribute locations
115 attributes = attributes.slice()
116 attributes.sort(compareAttributes)
117
118 //Convert attribute types, read out locations
119 var attributeUnpacked = []
120 var attributeNames = []
121 var attributeLocations = []
122 for(var i=0; i<attributes.length; ++i) {
123 var attr = attributes[i]
124 if(attr.type.indexOf('mat') >= 0) {
125 var size = attr.type.charAt(attr.type.length-1)|0
126 var locVector = new Array(size)
127 for(var j=0; j<size; ++j) {
128 locVector[j] = attributeLocations.length
129 attributeNames.push(attr.name + '[' + j + ']')
130 if(typeof attr.location === 'number') {
131 attributeLocations.push(attr.location + j)
132 } else if(Array.isArray(attr.location) &&
133 attr.location.length === size &&
134 typeof attr.location[j] === 'number') {
135 attributeLocations.push(attr.location[j]|0)
136 } else {
137 attributeLocations.push(-1)
138 }
139 }
140 attributeUnpacked.push({
141 name: attr.name,
142 type: attr.type,
143 locations: locVector
144 })
145 } else {
146 attributeUnpacked.push({
147 name: attr.name,
148 type: attr.type,
149 locations: [ attributeLocations.length ]
150 })
151 attributeNames.push(attr.name)
152 if(typeof attr.location === 'number') {
153 attributeLocations.push(attr.location|0)
154 } else {
155 attributeLocations.push(-1)
156 }
157 }
158 }
159
160 //For all unspecified attributes, assign them lexicographically min attribute
161 var curLocation = 0
162 for(var i=0; i<attributeLocations.length; ++i) {
163 if(attributeLocations[i] < 0) {
164 while(attributeLocations.indexOf(curLocation) >= 0) {
165 curLocation += 1
166 }
167 attributeLocations[i] = curLocation
168 }
169 }
170
171 //Rebuild program and recompute all uniform locations
172 var uniformLocations = new Array(uniforms.length)
173 function relink() {
174 wrapper.program = shaderCache.program(
175 gl
176 , wrapper._vref
177 , wrapper._fref
178 , attributeNames
179 , attributeLocations)
180
181 for(var i=0; i<uniforms.length; ++i) {
182 uniformLocations[i] = gl.getUniformLocation(
183 wrapper.program
184 , uniforms[i].name)
185 }
186 }
187
188 //Perform initial linking, reuse program used for reflection
189 relink()
190
191 //Save relinking procedure, defer until runtime
192 wrapper._relink = relink
193
194 //Generate type info
195 wrapper.types = {
196 uniforms: makeReflect(uniforms),
197 attributes: makeReflect(attributes)
198 }
199
200 //Generate attribute wrappers
201 wrapper.attributes = createAttributeWrapper(
202 gl
203 , wrapper
204 , attributeUnpacked
205 , attributeLocations)
206
207 //Generate uniform wrappers
208 Object.defineProperty(wrapper, 'uniforms', createUniformWrapper(
209 gl
210 , wrapper
211 , uniforms
212 , uniformLocations))
213}
214
215//Compiles and links a shader program with the given attribute and vertex list
216function createShader(
217 gl
218 , vertSource
219 , fragSource
220 , uniforms
221 , attributes) {
222
223 var shader = new Shader(gl)
224
225 shader.update(
226 vertSource
227 , fragSource
228 , uniforms
229 , attributes)
230
231 return shader
232}
233
234module.exports = createShader
\No newline at end of file