@@ -1,299 +1,303 @@
1Elm.Native.Graphics.WebGL = {};
1Elm.Native.Graphics.WebGL = {};
2Elm.Native.Graphics.WebGL.make = function(elm) {
2Elm.Native.Graphics.WebGL.make = function(elm) {
4− // LOG LEVEL
4+ // LOG LEVEL
6− elm.Native = elm.Native || {};
6+ elm.Native = elm.Native || {};
7− elm.Native.Graphics = elm.Native.Graphics || {};
7+ elm.Native.Graphics = elm.Native.Graphics || {};
8− elm.Native.Graphics.WebGL = elm.Native.Graphics.WebGL || {};
8+ elm.Native.Graphics.WebGL = elm.Native.Graphics.WebGL || {};
9− if (elm.Native.Graphics.WebGL.values) return elm.Native.Graphics.WebGL.values;
9+ if (elm.Native.Graphics.WebGL.values) return elm.Native.Graphics.WebGL.values;
11− var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
11+ var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
13− var Signal = Elm.Signal.make(elm);
13+ var Signal = Elm.Signal.make(elm);
14− var newElement = Elm.Graphics.Element.make(elm).newElement;
14+ var newElement = Elm.Graphics.Element.make(elm).newElement;
15− var Utils = Elm.Native.Utils.make(elm);
15+ var Utils = Elm.Native.Utils.make(elm);
16− var Tuple2 = Utils.Tuple2;
16+ var Tuple2 = Utils.Tuple2;
17− var MJS = Elm.Native.MJS.make(elm);
17+ var MJS = Elm.Native.MJS.make(elm);
18− var List = Elm.Native.List.make(elm);
18+ var List = Elm.Native.List.make(elm);
20− function encapsulate(program, buffer, uniforms) {
20+ function model(vert, frag, buffer, uniforms) {
22− return model = {
22+ return model = {
23− program: program,
23+ vert: vert,
24− buffer: buffer,
25+ buffer: buffer,
25− uniforms: uniforms
26+ uniforms: uniforms
31+ function do_compile (gl, src, tipe) {
33+ var shader = gl.createShader(tipe);
34+ console.log("Created shader");
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);
30− function link (vSrc, fSrc) {
43+ return shader;
32− var guid = Utils.guid();
45+ }
34− //console.log("Wrapped program #" + guid);
47+ function do_link (gl, vshader, fshader) {
36− return program = {
49+ var program = gl.createProgram();
37− guid: guid,
50+ console.log("Created program");
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);
44− function do_link (gl, vSrc, fSrc) {
59+ return program;
46− function createShader(str, type) {
61+ }
48− var shader = gl.createShader(type);
63+ function do_bind (gl, program, bufferElems) {
50− gl.shaderSource(shader, str);
65+ var buffers = {};
51− gl.compileShader(shader);
52− var compile = gl.COMPILE_STATUS;
53− if (!gl.getShaderParameter(shader,compile)) {
54− throw gl.getShaderInfoLog(shader);
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) {
59− };
73+ // Might want to invert the loop
74+ // to build the array buffer first
75+ // and then bind each one-at-a-time
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]);
88+ var array = new Float32Array(data);
61− var vshader = createShader(vSrc, gl.VERTEX_SHADER);
90+ var buffer = gl.createBuffer();
62− var fshader = createShader(fSrc, gl.FRAGMENT_SHADER);
63− var program = gl.createProgram();
64− //console.log("Created shaders and program");
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);
66− gl.attachShader(program, vshader);
95+ buffers[attribute.name] = buffer;
67− gl.attachShader(program, fshader);
68− gl.linkProgram(program);
69− if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
70− throw gl.getProgramInfoLog(program);
73− return program;
97+ break;
100+ console.log("Bad buffer type");
77− function bind (bufferElems) {
104+ }
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);
113+ var bufferObject = {
114+ numIndices: numIndices,
115+ indexBuffer: indexBuffer,
81− //console.log("Wrapped buffer #" + guid);
119+ return bufferObject;
85− bufferElems: bufferElems
88− }
123+ function drawGL(model) {
90− function do_bind (gl, program, bufferElems) {
125+ var gl = model.cache.gl;
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) {
100− // Might want to invert the loop
101− // to build the array buffer first
102− // and then bind each one-at-a-time
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]);
115− var array = new Float32Array(data);
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);
122− buffers[attribute.name] = buffer;
127− console.log("Bad buffer type");
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");
133− var numIndices = 3 * List.length(bufferElems);
131+ function drawModel(m) {
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);
140− var bufferObject = {
133+ var program;
141− numIndices: numIndices,
134+ if (m.vert.id && m.frag.id) {
142− indexBuffer: indexBuffer,
135+ var progid = m.vert.id + '#' + m.frag.id;
143− buffers: buffers
136+ program = model.cache.programs[progid];
146− return bufferObject;
141+ var vshader = undefined;
143+ vshader = model.cache.shaders[m.vert.id];
145+ m.vert.id = Utils.guid();
149+ vshader = do_compile(gl, m.vert.src, gl.VERTEX_SHADER);
150+ model.cache.shaders[m.vert.id] = vshader;
153+ var fshader = undefined;
155+ fshader = model.cache.shaders[m.frag.id];
157+ m.frag.id = Utils.guid();
150− function drawGL(model) {
160+ if (!fshader) {
151−
161+ fshader = do_compile(gl, m.frag.src, gl.FRAGMENT_SHADER);
152− var gl = model.cache.gl;
162+ model.cache.shaders[m.frag.id] = fshader;
154− gl.viewport(0, 0, model.w, model.h);
155− gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
156− //console.log("Drawing");
158− function drawModel(m) {
160− var program = model.cache.programs[m.program.guid];
162− program = do_link(gl, m.program.vSrc, m.program.fSrc);
163− model.cache.programs[m.program.guid] = program;
166− gl.useProgram(program);
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) {
174− gl.uniform1i(uniformLocation, m.uniforms[uniform.name]);
177− gl.uniform1f(uniformLocation, m.uniforms[uniform.name]);
180− gl.uniform3fv(uniformLocation, m.uniforms[uniform.name]);
183− gl.uniformMatrix4fv(uniformLocation, false, m.uniforms[uniform.name]);
186− console.log("Unsupported uniform type: " + uniform.type);
191− var buffer = model.cache.buffers[m.buffer.guid];
193− buffer = do_bind(gl, program, m.buffer.bufferElems);
194− model.cache.buffers[m.buffer.guid] = buffer;
197− var numIndices = buffer.numIndices;
198− var indexBuffer = buffer.indexBuffer;
199− gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
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];
208− switch (attribute.type) {
210− gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
211− gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
214− console.log("Unsupported attribute type: " + attribute.type);
219− gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
165+ program = do_link(gl, vshader, fshader);
166+ var progid = m.vert.id + '#' + m.frag.id;
167+ model.cache.programs[progid] = program;
171+ gl.useProgram(program);
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) {
179+ gl.uniform1i(uniformLocation, m.uniforms[uniform.name]);
182+ gl.uniform1f(uniformLocation, m.uniforms[uniform.name]);
185+ gl.uniform3fv(uniformLocation, m.uniforms[uniform.name]);
188+ gl.uniformMatrix4fv(uniformLocation, false, m.uniforms[uniform.name]);
191+ console.log("Unsupported uniform type: " + uniform.type);
196+ var buffer = model.cache.buffers[m.buffer.guid];
198+ buffer = do_bind(gl, program, m.buffer);
199+ model.cache.buffers[m.buffer.guid] = buffer;
202+ var numIndices = buffer.numIndices;
203+ var indexBuffer = buffer.indexBuffer;
204+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
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];
213+ switch (attribute.type) {
215+ gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
216+ gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
219+ console.log("Unsupported attribute type: " + attribute.type);
223− List.each(drawModel, model.models);
224+ gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
227− function webgl(dimensions, models) {
228+ List.each(drawModel, model.models);
229− if (!window.WebGLRenderingContext) {
230− throw new Error("It appears your browser does not support WebGL! http://get.webgl.org/troubleshooting");
234− var w = dimensions._0;
232+ function webgl(dimensions, models) {
235− var h = dimensions._1;
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");
239− var div = newNode('div');
239+ var w = dimensions._0;
240− div.style.overflow = 'hidden';
240+ var h = dimensions._1;
241− var canvas = newNode('canvas');
242− var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
243− gl.enable(gl.DEPTH_TEST);
245− model.cache.gl = gl;
242+ function render(model) {
246− model.cache.canvas = canvas;
247− model.cache.programs = [];
248− model.cache.buffers = [];
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);
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 = [];
254− }
256+ update(div, model, model);
256− function update(div, oldModel, newModel) {
258+ return div;
258− newModel.cache = oldModel.cache;
260+ }
260− var canvas = newModel.cache.canvas;
262+ function update(div, oldModel, newModel) {
262− canvas.style.width = oldModel.w + 'px';
264+ newModel.cache = oldModel.cache;
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;
269− drawGL(newModel);
266+ var canvas = newModel.cache.canvas;
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;
273− }
275+ drawGL(newModel);
275− var elem = {
277+ div.appendChild(canvas);
288− return A3(newElement, w, h, elem);
292− return elm.Native.Graphics.WebGL.values = {
281+ var elem = {
293− link:F2(link),
282+ ctor: 'Custom',
294− bind:bind,
283+ type: 'WebGL',
295− encapsulate:F3(encapsulate),
284+ render: render,
296− webgl:F2(webgl)
285+ update: update,
294+ return A3(newElement, w, h, elem);
298+ return elm.Native.Graphics.WebGL.values = {