on master help sign in
updated the native code to work. TODO buffer sharing
commitc3462d2bbfcd8d542d25c0e895b97eadb72e83bc authorJohn P Mayer Jr <john.p.mayer.jr@gmail.com> dateTue 25 Feb 2014, 16:12 (13 years ago) parentd288733
2 files changed+241−236
libraries/Graphics/WebGL.elm+4−3 libraries/Native/Graphics/WebGL.js+237−233
libraries/Graphics/WebGL.elm+4−3
@@ -1,4 +1,5 @@
1−module Graphics.WebGL (link, mapTriangle, zipTriangle, bind, encapsulate, webgl) where
1+
2+module Graphics.WebGL (mapTriangle, zipTriangle, model, webgl) where
23
34{-| WebGL -}
45
@@ -13,9 +14,9 @@ mapTriangle f (x,y,z) = (f x, f y, f z)
1314zipTriangle : (a -> b -> c) -> Triangle a -> Triangle b -> Triangle c
1415zipTriangle f (x,y,z) (x',y',z') = (f x x', f y y', f z z')
1516
16−data Shader attr unif vary = Dummy_Shader
17+data Shader attr unif vary = Shader
1718
18−data Model = Dummy_Model
19+data Model = Model
1920
2021model : Shader attr unif vary -> Shader {} unif vary -> [Triangle attr] -> unif -> Model
2122model = Native.Graphics.WebGL.model
libraries/Native/Graphics/WebGL.js+237−233
@@ -1,299 +1,303 @@
11Elm.Native.Graphics.WebGL = {};
22Elm.Native.Graphics.WebGL.make = function(elm) {
33
4− // LOG LEVEL
4+ // LOG LEVEL
55
6− elm.Native = elm.Native || {};
7− elm.Native.Graphics = elm.Native.Graphics || {};
8− elm.Native.Graphics.WebGL = elm.Native.Graphics.WebGL || {};
9− if (elm.Native.Graphics.WebGL.values) return elm.Native.Graphics.WebGL.values;
6+ elm.Native = elm.Native || {};
7+ elm.Native.Graphics = elm.Native.Graphics || {};
8+ elm.Native.Graphics.WebGL = elm.Native.Graphics.WebGL || {};
9+ if (elm.Native.Graphics.WebGL.values) return elm.Native.Graphics.WebGL.values;
1010
11− var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
11+ var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
1212
13− var Signal = Elm.Signal.make(elm);
14− var newElement = Elm.Graphics.Element.make(elm).newElement;
15− var Utils = Elm.Native.Utils.make(elm);
16− var Tuple2 = Utils.Tuple2;
17− var MJS = Elm.Native.MJS.make(elm);
18− var List = Elm.Native.List.make(elm);
13+ var Signal = Elm.Signal.make(elm);
14+ var newElement = Elm.Graphics.Element.make(elm).newElement;
15+ var Utils = Elm.Native.Utils.make(elm);
16+ var Tuple2 = Utils.Tuple2;
17+ var MJS = Elm.Native.MJS.make(elm);
18+ var List = Elm.Native.List.make(elm);
1919
20− function encapsulate(program, buffer, uniforms) {
20+ function model(vert, frag, buffer, uniforms) {
2121
22− return model = {
23− program: program,
24− buffer: buffer,
25− uniforms: uniforms
26− };
22+ return model = {
23+ vert: vert,
24+ frag: frag,
25+ buffer: buffer,
26+ uniforms: uniforms
27+ };
28+
29+ }
30+
31+ function do_compile (gl, src, tipe) {
32+
33+ var shader = gl.createShader(tipe);
34+ console.log("Created shader");
2735
36+ gl.shaderSource(shader, src);
37+ gl.compileShader(shader);
38+ var compile = gl.COMPILE_STATUS;
39+ if (!gl.getShaderParameter(shader,compile)) {
40+ throw gl.getShaderInfoLog(shader);
2841 }
2942
30− function link (vSrc, fSrc) {
43+ return shader;
3144
32− var guid = Utils.guid();
45+ }
3346
34− //console.log("Wrapped program #" + guid);
47+ function do_link (gl, vshader, fshader) {
3548
36− return program = {
37− guid: guid,
38− vSrc: vSrc,
39− fSrc: fSrc
40− };
49+ var program = gl.createProgram();
50+ console.log("Created program");
4151
52+ gl.attachShader(program, vshader);
53+ gl.attachShader(program, fshader);
54+ gl.linkProgram(program);
55+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
56+ throw gl.getProgramInfoLog(program);
4257 }
4358
44− function do_link (gl, vSrc, fSrc) {
59+ return program;
4560
46− function createShader(str, type) {
61+ }
4762
48− var shader = gl.createShader(type);
63+ function do_bind (gl, program, bufferElems) {
4964
50− gl.shaderSource(shader, str);
51− gl.compileShader(shader);
52− var compile = gl.COMPILE_STATUS;
53− if (!gl.getShaderParameter(shader,compile)) {
54− throw gl.getShaderInfoLog(shader);
55− }
65+ var buffers = {};
5666
57− return shader;
67+ var attributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
68+ for (var i = 0; i < attributes; i += 1) {
69+ var attribute = gl.getActiveAttrib(program, i);
70+ switch (attribute.type) {
71+ case gl.FLOAT_VEC3:
5872
59− };
73+ // Might want to invert the loop
74+ // to build the array buffer first
75+ // and then bind each one-at-a-time
76+ var data = [];
77+ List.each(function(elem){
78+ data.push(elem._0[attribute.name][0]);
79+ data.push(elem._0[attribute.name][1]);
80+ data.push(elem._0[attribute.name][2]);
81+ data.push(elem._1[attribute.name][0]);
82+ data.push(elem._1[attribute.name][1]);
83+ data.push(elem._1[attribute.name][2]);
84+ data.push(elem._2[attribute.name][0]);
85+ data.push(elem._2[attribute.name][1]);
86+ data.push(elem._2[attribute.name][2]);
87+ }, bufferElems);
88+ var array = new Float32Array(data);
6089
61− var vshader = createShader(vSrc, gl.VERTEX_SHADER);
62− var fshader = createShader(fSrc, gl.FRAGMENT_SHADER);
63− var program = gl.createProgram();
64− //console.log("Created shaders and program");
90+ var buffer = gl.createBuffer();
91+ console.log("Created attribute buffer " + attribute.name);
92+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
93+ gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
6594
66− gl.attachShader(program, vshader);
67− gl.attachShader(program, fshader);
68− gl.linkProgram(program);
69− if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
70− throw gl.getProgramInfoLog(program);
71− }
95+ buffers[attribute.name] = buffer;
7296
73− return program;
97+ break;
7498
75− }
99+ default:
100+ console.log("Bad buffer type");
101+ break;
102+ }
76103
77− function bind (bufferElems) {
104+ }
78105
79− var guid = Utils.guid();
106+ var numIndices = 3 * List.length(bufferElems);
107+ var indices = List.toArray(List.range(0, numIndices - 1));
108+ console.log("Created index buffer");
109+ var indexBuffer = gl.createBuffer();
110+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
111+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
112+
113+ var bufferObject = {
114+ numIndices: numIndices,
115+ indexBuffer: indexBuffer,
116+ buffers: buffers
117+ };
80118
81− //console.log("Wrapped buffer #" + guid);
119+ return bufferObject;
82120
83− return buffer = {
84− guid: guid,
85− bufferElems: bufferElems
86− };
121+ }
87122
88− }
123+ function drawGL(model) {
89124
90− function do_bind (gl, program, bufferElems) {
91−
92− var buffers = {};
93−
94− var attributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
95− for (var i = 0; i < attributes; i += 1) {
96− var attribute = gl.getActiveAttrib(program, i);
97− switch (attribute.type) {
98− case gl.FLOAT_VEC3:
99−
100− // Might want to invert the loop
101− // to build the array buffer first
102− // and then bind each one-at-a-time
103− var data = [];
104− List.each(function(elem){
105− data.push(elem._0[attribute.name][0]);
106− data.push(elem._0[attribute.name][1]);
107− data.push(elem._0[attribute.name][2]);
108− data.push(elem._1[attribute.name][0]);
109− data.push(elem._1[attribute.name][1]);
110− data.push(elem._1[attribute.name][2]);
111− data.push(elem._2[attribute.name][0]);
112− data.push(elem._2[attribute.name][1]);
113− data.push(elem._2[attribute.name][2]);
114− }, bufferElems);
115− var array = new Float32Array(data);
116−
117− var buffer = gl.createBuffer();
118− //console.log("Created attribute buffer " + attribute.name);
119− gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
120− gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
121−
122− buffers[attribute.name] = buffer;
123−
124− break;
125−
126− default:
127− console.log("Bad buffer type");
128− break;
129− }
125+ var gl = model.cache.gl;
130126
131− }
127+ gl.viewport(0, 0, model.w, model.h);
128+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
129+ console.log("Drawing");
132130
133− var numIndices = 3 * List.length(bufferElems);
134− var indices = List.toArray(List.range(0, numIndices - 1));
135− //console.log("Created index buffer");
136− var indexBuffer = gl.createBuffer();
137− gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
138− gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
131+ function drawModel(m) {
139132
140− var bufferObject = {
141− numIndices: numIndices,
142− indexBuffer: indexBuffer,
143− buffers: buffers
144− };
133+ var program;
134+ if (m.vert.id && m.frag.id) {
135+ var progid = m.vert.id + '#' + m.frag.id;
136+ program = model.cache.programs[progid];
137+ }
138+
139+ if (!program) {
145140
146− return bufferObject;
141+ var vshader = undefined;
142+ if (m.vert.id) {
143+ vshader = model.cache.shaders[m.vert.id];
144+ } else {
145+ m.vert.id = Utils.guid();
146+ }
147+
148+ if (!vshader) {
149+ vshader = do_compile(gl, m.vert.src, gl.VERTEX_SHADER);
150+ model.cache.shaders[m.vert.id] = vshader;
151+ }
147152
148− }
153+ var fshader = undefined;
154+ if (m.frag.id) {
155+ fshader = model.cache.shaders[m.frag.id];
156+ } else {
157+ m.frag.id = Utils.guid();
158+ }
149159
150− function drawGL(model) {
151−
152− var gl = model.cache.gl;
153−
154− gl.viewport(0, 0, model.w, model.h);
155− gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
156− //console.log("Drawing");
157−
158− function drawModel(m) {
159−
160− var program = model.cache.programs[m.program.guid];
161− if (!program) {
162− program = do_link(gl, m.program.vSrc, m.program.fSrc);
163− model.cache.programs[m.program.guid] = program;
164− }
165−
166− gl.useProgram(program);
167−
168− var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
169− for (var i = 0; i < numUniforms; i += 1) {
170− var uniform = gl.getActiveUniform(program, i);
171− var uniformLocation = gl.getUniformLocation(program, uniform.name);
172− switch (uniform.type) {
173− case gl.INT:
174− gl.uniform1i(uniformLocation, m.uniforms[uniform.name]);
175− break;
176− case gl.FLOAT:
177− gl.uniform1f(uniformLocation, m.uniforms[uniform.name]);
178− break;
179− case gl.FLOAT_VEC3:
180− gl.uniform3fv(uniformLocation, m.uniforms[uniform.name]);
181− break;
182− case gl.FLOAT_MAT4:
183− gl.uniformMatrix4fv(uniformLocation, false, m.uniforms[uniform.name]);
184− break;
185− default:
186− console.log("Unsupported uniform type: " + uniform.type);
187− break;
188− }
189− }
190−
191− var buffer = model.cache.buffers[m.buffer.guid];
192− if (!buffer) {
193− buffer = do_bind(gl, program, m.buffer.bufferElems);
194− model.cache.buffers[m.buffer.guid] = buffer;
195− }
196−
197− var numIndices = buffer.numIndices;
198− var indexBuffer = buffer.indexBuffer;
199− gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
200−
201− var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
202− for (var i = 0; i < numAttributes; i += 1) {
203− var attribute = gl.getActiveAttrib(program, i);
204− var attribLocation = gl.getAttribLocation(program, attribute.name);
205− gl.enableVertexAttribArray(attribLocation);
206− attributeBuffer = buffer.buffers[attribute.name];
207−
208− switch (attribute.type) {
209− case gl.FLOAT_VEC3:
210− gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
211− gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
212− break;
213− default:
214− console.log("Unsupported attribute type: " + attribute.type);
215− break;
216− }
217− }
218−
219− gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
160+ if (!fshader) {
161+ fshader = do_compile(gl, m.frag.src, gl.FRAGMENT_SHADER);
162+ model.cache.shaders[m.frag.id] = fshader;
163+ }
220164
165+ program = do_link(gl, vshader, fshader);
166+ var progid = m.vert.id + '#' + m.frag.id;
167+ model.cache.programs[progid] = program;
168+
169+ }
170+
171+ gl.useProgram(program);
172+
173+ var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
174+ for (var i = 0; i < numUniforms; i += 1) {
175+ var uniform = gl.getActiveUniform(program, i);
176+ var uniformLocation = gl.getUniformLocation(program, uniform.name);
177+ switch (uniform.type) {
178+ case gl.INT:
179+ gl.uniform1i(uniformLocation, m.uniforms[uniform.name]);
180+ break;
181+ case gl.FLOAT:
182+ gl.uniform1f(uniformLocation, m.uniforms[uniform.name]);
183+ break;
184+ case gl.FLOAT_VEC3:
185+ gl.uniform3fv(uniformLocation, m.uniforms[uniform.name]);
186+ break;
187+ case gl.FLOAT_MAT4:
188+ gl.uniformMatrix4fv(uniformLocation, false, m.uniforms[uniform.name]);
189+ break;
190+ default:
191+ console.log("Unsupported uniform type: " + uniform.type);
192+ break;
221193 }
194+ }
195+
196+ var buffer = model.cache.buffers[m.buffer.guid];
197+ if (!buffer) {
198+ buffer = do_bind(gl, program, m.buffer);
199+ model.cache.buffers[m.buffer.guid] = buffer;
200+ }
201+
202+ var numIndices = buffer.numIndices;
203+ var indexBuffer = buffer.indexBuffer;
204+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
205+
206+ var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
207+ for (var i = 0; i < numAttributes; i += 1) {
208+ var attribute = gl.getActiveAttrib(program, i);
209+ var attribLocation = gl.getAttribLocation(program, attribute.name);
210+ gl.enableVertexAttribArray(attribLocation);
211+ attributeBuffer = buffer.buffers[attribute.name];
212+
213+ switch (attribute.type) {
214+ case gl.FLOAT_VEC3:
215+ gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
216+ gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
217+ break;
218+ default:
219+ console.log("Unsupported attribute type: " + attribute.type);
220+ break;
221+ }
222+ }
222223
223− List.each(drawModel, model.models);
224+ gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
224225
225226 }
226227
227− function webgl(dimensions, models) {
228+ List.each(drawModel, model.models);
228229
229− if (!window.WebGLRenderingContext) {
230− throw new Error("It appears your browser does not support WebGL! http://get.webgl.org/troubleshooting");
231− return;
232− }
230+ }
233231
234− var w = dimensions._0;
235− var h = dimensions._1;
232+ function webgl(dimensions, models) {
236233
237− function render(model) {
234+ if (!window.WebGLRenderingContext) {
235+ throw new Error("It appears your browser does not support WebGL! http://get.webgl.org/troubleshooting");
236+ return;
237+ }
238238
239− var div = newNode('div');
240− div.style.overflow = 'hidden';
241− var canvas = newNode('canvas');
242− var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
243− gl.enable(gl.DEPTH_TEST);
239+ var w = dimensions._0;
240+ var h = dimensions._1;
244241
245− model.cache.gl = gl;
246− model.cache.canvas = canvas;
247− model.cache.programs = [];
248− model.cache.buffers = [];
242+ function render(model) {
249243
250− update(div, model, model);
244+ var div = newNode('div');
245+ div.style.overflow = 'hidden';
246+ var canvas = newNode('canvas');
247+ var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
248+ gl.enable(gl.DEPTH_TEST);
251249
252− return div;
250+ model.cache.gl = gl;
251+ model.cache.canvas = canvas;
252+ model.cache.shaders = [];
253+ model.cache.programs = {};
254+ model.cache.buffers = [];
253255
254− }
256+ update(div, model, model);
255257
256− function update(div, oldModel, newModel) {
258+ return div;
257259
258− newModel.cache = oldModel.cache;
260+ }
259261
260− var canvas = newModel.cache.canvas;
262+ function update(div, oldModel, newModel) {
261263
262− canvas.style.width = oldModel.w + 'px';
263− canvas.style.height = oldModel.h + 'px';
264− canvas.style.display = "block";
265− canvas.style.position = "absolute";
266− canvas.width = oldModel.w;
267− canvas.height = oldModel.h;
264+ newModel.cache = oldModel.cache;
268265
269− drawGL(newModel);
266+ var canvas = newModel.cache.canvas;
270267
271− div.appendChild(canvas);
268+ canvas.style.width = oldModel.w + 'px';
269+ canvas.style.height = oldModel.h + 'px';
270+ canvas.style.display = "block";
271+ canvas.style.position = "absolute";
272+ canvas.width = oldModel.w;
273+ canvas.height = oldModel.h;
272274
273− }
275+ drawGL(newModel);
274276
275− var elem = {
276− ctor: 'Custom',
277− type: 'WebGL',
278− render: render,
279− update: update,
280− model: {
281− models: models,
282− cache: {},
283− w: w,
284− h: h,
285− }
286− };
287−
288− return A3(newElement, w, h, elem);
277+ div.appendChild(canvas);
289278
290279 }
291280
292− return elm.Native.Graphics.WebGL.values = {
293− link:F2(link),
294− bind:bind,
295− encapsulate:F3(encapsulate),
296− webgl:F2(webgl)
281+ var elem = {
282+ ctor: 'Custom',
283+ type: 'WebGL',
284+ render: render,
285+ update: update,
286+ model: {
287+ models: models,
288+ cache: {},
289+ w: w,
290+ h: h,
291+ }
297292 };
298293
294+ return A3(newElement, w, h, elem);
295+
296+ }
297+
298+ return elm.Native.Graphics.WebGL.values = {
299+ model:F4(model),
300+ webgl:F2(webgl)
301+ };
302+
299303};