on c54cd59 help sign in
207 lines 6.5 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 var uniforms = glModel.uniforms;
91 va:q
92 for (var uName in uniforms) {
93 var uLoc = gl.getUniformLocation(program, uName);
94 var active = gl.getActiveUniform(program, uName);
95 }
98 var attributes = glModel.attributes;
100 }
102 List.each(drawModel, model.glModels);
104 }
106 /*
107 * Called for new node, caches lots of stuff
108 */
109 function render(model) {
110 drawGL(model);
111 return model.node;
112 }
114 /*
115 * Called at existing node
116 */
117 function update(canvasNode, oldModel, newModel) {
118 drawGL(newModel)
119 }
121 function makeGL(w,h) {
122 var node = newNode('canvas');
123 var gl = node.getContext('webgl');
124 return Signal.constant({w:w,h:h,gl:gl,node:node});
125 }
127 function bufferMesh(triangles, context) {
128 var indices = [];
129 var positions = [];
130 var colors = [];
132 function pushTriangle(n, node) {
133 if (node.ctor === "[]") return;
134 var tri = node._0;
135 for (var i = 0; i < 3; i+= 1) {
136 indices.push(3 * n + i);
137 var vertex = tri['_' + i];
138 for (var j = 0; j < 3; j += 1) {
139 positions.push(vertex.pos[j]);
140 }
141 colors.push(vertex.color._0 / 256);
142 colors.push(vertex.color._1 / 256);
143 colors.push(vertex.color._2 / 256);
144 colors.push(vertex.color._3);
145 }
146 pushTriangle(n+1,node._1);
147 }
149 pushTriangle(0,triangles);
151 var gl = context.gl;
153 var indexBuffer = gl.createBuffer();
154 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
155 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
157 var vertexPosBuffer = gl.createBuffer();
158 gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
159 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
161 var vertexColorBuffer = gl.createBuffer();
162 gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
163 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
165 return {
166 indexBuffer: indexBuffer,
167 vertexPosBuffer: vertexPosBuffer,
168 vertexColorBuffer: vertexColorBuffer,
169 numIndices: indices.length,
170 };
172 }
174 function webgl(context, glModels) {
176 return A3(newElement, context.w, context.h, {
177 ctor: 'Custom',
178 type: 'WebGL',
179 render: render,
180 update: update,
181 model: {
182 aspect: context.w/context.h,
183 node: context.node,
184 gl: context.gl,
185 glModels: glModels,
186 },
187 });
189 }
191 function linkModel(program, uniforms, attributes) {
192 return {
193 program: program,
194 uniforms: uniforms,
195 attributes: attributes,
196 };
197 }
199 return elm.Native.Graphics.WebGL.values = {
200 makeGL:F2(makeGL),
201 bufferMesh:F2(bufferMesh),
202 webgl:F2(webgl),
203 linkProgram:F3(linkProgram),
204 linkModel:F3(linkModel),
205 };
207};