on 3e2d2e9 help sign in
271 lines 8.3 kB history raw
1Elm.Native.Graphics.WebGL = {};
2Elm.Native.Graphics.WebGL.make = function(elm) {
4 // LOG LEVEL
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;
11 var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
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);
20 function encapsulate(program, buffer, uniforms) {
22 return model = {
23 program: program,
24 buffer: buffer,
25 uniforms: uniforms
26 };
28 }
30 function link (vSrc, fSrc) {
32 var guid = Utils.guid();
34 console.log("Wrapped program #" + guid);
36 return program = {
37 guid: guid,
38 vSrc: vSrc,
39 fSrc: fSrc
40 };
42 }
44 function do_link (gl, vSrc, fSrc) {
46 function createShader(str, type) {
48 var shader = gl.createShader(type);
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 }
57 return shader;
59 };
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");
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 }
73 return program;
75 }
77 function bind (bufferElems) {
79 var guid = Utils.guid();
81 console.log("Wrapped buffer #" + guid);
83 return buffer = {
84 guid: guid,
85 bufferElems: bufferElems
86 };
88 }
90 function do_bind (gl, program, bufferElems) {
92 var buffers = {};
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:
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);
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;
124 break;
126 default:
127 console.log("Bad buffer type");
128 break;
129 }
131 }
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);
140 var bufferObject = {
141 numIndices: numIndices,
142 indexBuffer: indexBuffer,
143 buffers: buffers
144 };
146 return bufferObject;
148 }
150 function drawGL(model) {
152 var gl = model.cache.gl;
154 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
155 console.log("Drawing");
157 function drawModel(m) {
159 var program = model.cache.programs[m.program.guid];
160 if (!program) {
161 program = do_link(gl, m.program.vSrc, m.program.fSrc);
162 model.cache.programs[m.program.guid] = program;
163 }
165 gl.useProgram(program);
167 var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
168 for (var i = 0; i < numUniforms; i += 1) {
169 var uniform = gl.getActiveUniform(program, i);
170 var uniformLocation = gl.getUniformLocation(program, uniform.name);
171 switch (uniform.type) {
172 case gl.FLOAT_MAT4:
173 gl.uniformMatrix4fv(uniformLocation, false, m.uniforms[uniform.name]);
174 break;
175 default:
176 console.log("Unsupported uniform type: " + uniform.type);
177 break;
178 }
179 }
181 var buffer = model.cache.buffers[m.buffer.guid];
182 if (!buffer) {
183 buffer = do_bind(gl, program, m.buffer.bufferElems);
184 model.cache.buffers[m.buffer.guid] = buffer;
185 }
187 var numIndices = buffer.numIndices;
188 var indexBuffer = buffer.indexBuffer;
189 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
191 var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
192 for (var i = 0; i < numAttributes; i += 1) {
193 var attribute = gl.getActiveAttrib(program, i);
194 var attribLocation = gl.getAttribLocation(program, attribute.name);
195 gl.enableVertexAttribArray(attribLocation);
196 attributeBuffer = buffer.buffers[attribute.name];
198 switch (attribute.type) {
199 case gl.FLOAT_VEC3:
200 gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
201 gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
202 break;
203 default:
204 console.log("Unsupported attribute type: " + attribute.type);
205 break;
206 }
207 }
209 gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
211 }
213 List.each(drawModel, model.models);
215 }
217 function webgl(dimensions, models) {
219 if (!window.WebGLRenderingContext) {
220 throw new Error("It appears your browser does not support WebGL! http://get.webgl.org/troubleshooting");
221 return;
222 }
224 var w = dimensions._0;
225 var h = dimensions._1;
227 function render(model) {
229 var node = newNode('canvas');
230 var gl = node.getContext('webgl') || node.getContext('experimental-webgl');
231 gl.enable(gl.DEPTH_TEST);
233 model.cache.gl = gl;
234 model.cache.programs = [];
235 model.cache.buffers = [];
237 drawGL(model);
238 return node;
240 }
242 function update(_node, oldModel, newModel) {
244 newModel.cache = oldModel.cache;
245 drawGL(newModel);
247 }
249 var elem = {
250 ctor: 'Custom',
251 type: 'WebGL',
252 render: render,
253 update: update,
254 model: {
255 models: models,
256 cache: {},
257 }
258 };
260 return A3(newElement, w, h, elem);
262 }
264 return elm.Native.Graphics.WebGL.values = {
265 link:F2(link),
266 bind:bind,
267 encapsulate:F3(encapsulate),
268 webgl:F2(webgl)
269 };
271};