on 087562e help sign in
245 lines 8.6 kB history raw
1Elm.Native.Graphics.WebGL = {};
2Elm.Native.Graphics.WebGL.make = function(elm) {
4 elm.Native = elm.Native || {};
5 elm.Native.Graphics = elm.Native.Graphics || {};
6 elm.Native.Graphics.WebGL = elm.Native.Graphics.WebGL || {};
7 if (elm.Native.Graphics.WebGL.values) return elm.Native.Graphics.WebGL.values;
9 var newNode = ElmRuntime.use(ElmRuntime.Render.Utils).newElement;
11 var Signal = Elm.Signal.make(elm);
12 var newElement = Elm.Graphics.Element.make(elm).newElement;
13 var Utils = Elm.Native.Utils.make(elm);
14 var Tuple2 = Utils.Tuple2;
15 var MJS = Elm.Native.MJS.make(elm);
16 var List = Elm.Native.List.make(elm);
18 function createShader(gl, str, type) {
19 var shader = gl.createShader(type);
20 gl.shaderSource(shader, str);
21 gl.compileShader(shader);
23 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
24 throw gl.getShaderInfoLog(shader);
25 }
27 return shader;
28 };
30 function linkProgram(vSrc, fSrc, context) {
31 var gl = context.gl;
32 var vshader = createShader(gl, vSrc, gl.VERTEX_SHADER);
33 var fshader = createShader(gl, fSrc, gl.FRAGMENT_SHADER);
34 var program = gl.createProgram()
35 gl.attachShader(program, vshader);
36 gl.attachShader(program, fshader);
37 gl.linkProgram(program);
38 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
39 throw gl.getProgramInfoLog(program);
40 }
41 return program;
42 }
44 function drawGL(model) {
45 var aspect = model.aspect;
47 var gl = model.gl;
48 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
50 var program = model.program;
52 function drawMesh(mesh, sceneMatrix) {
53 gl.useProgram(program.programPtr);
55 gl.enableVertexAttribArray(program.vertexPositionAttribute);
56 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indexBuffer);
57 gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexPosBuffer);
58 gl.vertexAttribPointer(program.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
60 gl.enableVertexAttribArray(program.vertexColorAttribute);
61 gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexColorBuffer);
62 gl.vertexAttribPointer(program.vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
64 gl.uniformMatrix4fv(program.sceneMatrixUniform, false, sceneMatrix);
66 gl.drawElements(gl.TRIANGLES, mesh.numIndices, gl.UNSIGNED_SHORT, 0);
67 }
69 var sceneMatrixStack = [MJS.M4x4.identity];
71 function drawScene(scene,n) {
72 switch(scene.ctor) {
73 case 'SceneLeaf':
74 drawMesh(scene._0, sceneMatrixStack[n]);
75 break;
76 default:
77 var m = scene._0;
78 sceneMatrixStack[n+1] = MJS.M4x4.mul(sceneMatrixStack[n],m)
79 function drawChild(c) {
80 drawScene(c,n+1);
81 }
82 var children = scene._1;
83 List.each(drawChild, children);
84 break;
85 }
86 }
88 function drawModel(glModel) {
89 var program = glModel.program;
90 gl.useProgram(program);
92 var activeUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
93 for (var i = 0; i < activeUniforms; i += 1) {
94 var uniform = gl.getActiveUniform(program, i);
95 var uniformLocation = gl.getUniformLocation(program, uniform.name);
96 switch (uniform.type) {
97 case gl.FLOAT_MAT4:
98 gl.uniformMatrix4fv(uniformLocation, false, glModel.uniforms[uniform.name]);
99 break;
100 default:
101 console.log("Unsupported uniform type: " + uniform.type);
102 break;
103 }
104 }
106 var numIndices = List.length(glModel.attributes);
107 var indices = List.toArray(List.range(0,numIndices));
108 var indexBuffer = gl.createBuffer();
109 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
110 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
112 var activeAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
113 for (var i = 0; i < activeAttributes; i += 1) {
114 var attribute = gl.getActiveAttrib(program, i);
115 var attribLocation = gl.getAttribLocation(program, attribute.name);
116 gl.enableVertexAttribArray(attribLocation);
117 switch (attribute.type) {
118 case gl.FLOAT_VEC3:
119 var data = [];
120 List.each(function(elem){
121 data.push(elem[attribute.name][0]);
122 data.push(elem[attribute.name][1]);
123 data.push(elem[attribute.name][2]);
124 }, glModel.attributes);
125 var attributeBuffer = gl.createBuffer();
126 gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
127 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
128 gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
129 break;
130 default:
131 console.log("Unsupported attribute type: " + attribute.type);
132 break;
133 }
134 }
136 gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
138 }
140 List.each(drawModel, model.glModels);
142 }
144 /*
145 * Called for new node, caches lots of stuff
146 */
147 function render(model) {
148 drawGL(model);
149 return model.node;
150 }
152 /*
153 * Called at existing node
154 */
155 function update(canvasNode, oldModel, newModel) {
156 drawGL(newModel)
157 }
159 function makeGL(w,h) {
160 var node = newNode('canvas');
161 var gl = node.getContext('webgl');
162 return Signal.constant({w:w,h:h,gl:gl,node:node});
163 }
165 function bufferMesh(triangles, context) {
166 var indices = [];
167 var positions = [];
168 var colors = [];
170 function pushTriangle(n, node) {
171 if (node.ctor === "[]") return;
172 var tri = node._0;
173 for (var i = 0; i < 3; i+= 1) {
174 indices.push(3 * n + i);
175 var vertex = tri['_' + i];
176 for (var j = 0; j < 3; j += 1) {
177 positions.push(vertex.pos[j]);
178 }
179 colors.push(vertex.color._0 / 256);
180 colors.push(vertex.color._1 / 256);
181 colors.push(vertex.color._2 / 256);
182 colors.push(vertex.color._3);
183 }
184 pushTriangle(n+1,node._1);
185 }
187 pushTriangle(0,triangles);
189 var gl = context.gl;
191 var indexBuffer = gl.createBuffer();
192 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
193 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
195 var vertexPosBuffer = gl.createBuffer();
196 gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
197 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
199 var vertexColorBuffer = gl.createBuffer();
200 gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
201 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
203 return {
204 indexBuffer: indexBuffer,
205 vertexPosBuffer: vertexPosBuffer,
206 vertexColorBuffer: vertexColorBuffer,
207 numIndices: indices.length,
208 };
210 }
212 function webgl(context, glModels) {
214 return A3(newElement, context.w, context.h, {
215 ctor: 'Custom',
216 type: 'WebGL',
217 render: render,
218 update: update,
219 model: {
220 aspect: context.w/context.h,
221 node: context.node,
222 gl: context.gl,
223 glModels: glModels,
224 },
225 });
227 }
229 function linkModel(program, uniforms, attributes) {
230 return {
231 program: program,
232 uniforms: uniforms,
233 attributes: attributes,
234 };
235 }
237 return elm.Native.Graphics.WebGL.values = {
238 makeGL:F2(makeGL),
239 bufferMesh:F2(bufferMesh),
240 webgl:F2(webgl),
241 linkProgram:F3(linkProgram),
242 linkModel:F3(linkModel),
243 };
245};