on 517b17a help sign in
228 lines 7.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(gl, program) {
31 var vshader = createShader(gl, program.vshaderSource, gl.VERTEX_SHADER);
32 var fshader = createShader(gl, program.fshaderSource, gl.FRAGMENT_SHADER);
33 gl.attachShader(program, vshader);
34 gl.attachShader(program, fshader);
35 gl.linkProgram(program);
36 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
37 throw gl.getProgramInfoLog(program);
38 }
39 }
41 function createProgram(gl, vstr, fstr) {
42 var program = gl.createProgram();
43 var vshader = createShader(gl, vstr, gl.VERTEX_SHADER);
44 var fshader = createShader(gl, fstr, gl.FRAGMENT_SHADER);
45 gl.attachShader(program, vshader);
46 gl.attachShader(program, fshader);
47 gl.linkProgram(program);
49 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
50 throw gl.getProgramInfoLog(program);
51 }
53 return program;
54 };
56 var geoVert = "attribute vec3 aVertexPosition;\
57 attribute vec4 aVertexColor;\
58 \
59 uniform mat4 uSceneMatrix;\
60 \
61 varying vec4 vVertexColor;\
62 \
63 void main() {\
64 gl_Position = uSceneMatrix * vec4(aVertexPosition, 1.0);\
65 vVertexColor = aVertexColor;\
66 }"
68 var geoFrag = "precision mediump float;\
69 \
70 varying vec4 vVertexColor;\
71 \
72 void main() {\
73 gl_FragColor = vVertexColor;\
74 }"
76 function drawGL(model) {
77 var aspect = model.aspect;
79 var gl = model.gl;
80 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
82 var program = model.program;
84 function drawMesh(mesh, sceneMatrix) {
85 gl.useProgram(program.programPtr);
87 gl.enableVertexAttribArray(program.vertexPositionAttribute);
88 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, mesh.indexBuffer);
89 gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexPosBuffer);
90 gl.vertexAttribPointer(program.vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
92 gl.enableVertexAttribArray(program.vertexColorAttribute);
93 gl.bindBuffer(gl.ARRAY_BUFFER, mesh.vertexColorBuffer);
94 gl.vertexAttribPointer(program.vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
96 gl.uniformMatrix4fv(program.sceneMatrixUniform, false, sceneMatrix);
98 gl.drawElements(gl.TRIANGLES, mesh.numIndices, gl.UNSIGNED_SHORT, 0);
99 }
101 var sceneMatrixStack = [MJS.M4x4.identity];
103 function drawScene(scene,n) {
104 switch(scene.ctor) {
105 case 'Leaf':
106 drawMesh(scene._0, sceneMatrixStack[n]);
107 break;
108 default:
109 var m = scene._0;
110 sceneMatrixStack[n+1] = MJS.M4x4.mul(sceneMatrixStack[n],m)
111 function drawChild(c) {
112 drawScene(c,n+1);
113 }
114 var children = scene._1;
115 List.each(drawChild, children);
116 break;
117 }
118 }
120 var scene = model.scene;
121 drawScene(scene,0);
123 }
125 /*
126 * Called for new node, caches lots of stuff
127 */
128 function render(model) {
129 drawGL(model);
130 return model.node;
131 }
133 /*
134 * Called at existing node
135 */
136 function update(canvasNode, oldModel, newModel) {
137 drawGL(newModel)
138 }
140 function glContext(w,h) {
141 var node = newNode('canvas');
142 var gl = node.getContext('webgl');
143 var programPtr = createProgram(gl, geoVert, geoFrag);
144 var vertexPositionAttribute = gl.getAttribLocation(programPtr,'aVertexPosition');
145 var vertexColorAttribute = gl.getAttribLocation(programPtr,'aVertexColor');
146 var sceneMatrixUniform = gl.getUniformLocation(programPtr, 'uSceneMatrix');
147 var program = {
148 programPtr: programPtr,
149 vertexPositionAttribute: vertexPositionAttribute,
150 vertexColorAttribute: vertexColorAttribute,
151 sceneMatrixUniform: sceneMatrixUniform,
152 };
153 return Signal.constant({w:w,h:h,gl:gl,node:node,program:program});
154 }
156 function bindMesh(triangles, context) {
157 var indices = [];
158 var positions = [];
159 var colors = [];
161 function pushTriangle(n, node) {
162 if (node.ctor === "[]") return;
163 var tri = node._0;
164 var names = ['a','b','c'];
165 for (var i = 0; i < 3; i+= 1) {
166 indices.push(3 * n + i);
167 var vertex = tri[names[i]];
168 for (var j = 0; j < 3; j += 1) {
169 positions.push(vertex.pos[j]);
170 }
171 colors.push(vertex.color._0 / 256);
172 colors.push(vertex.color._1 / 256);
173 colors.push(vertex.color._2 / 256);
174 colors.push(vertex.color._3);
175 }
176 pushTriangle(n+1,node._1);
177 }
179 pushTriangle(0,triangles);
181 var gl = context.gl;
183 var indexBuffer = gl.createBuffer();
184 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
185 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
187 var vertexPosBuffer = gl.createBuffer();
188 gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
189 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
191 var vertexColorBuffer = gl.createBuffer();
192 gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
193 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
195 return {
196 indexBuffer: indexBuffer,
197 vertexPosBuffer: vertexPosBuffer,
198 vertexColorBuffer: vertexColorBuffer,
199 numIndices: indices.length,
200 };
202 }
204 function renderGL(context, scene) {
206 return A3(newElement, context.w, context.h, {
207 ctor: 'Custom',
208 type: 'WebGL',
209 render: render,
210 update: update,
211 model: {
212 aspect: context.w/context.h,
213 node: context.node,
214 gl: context.gl,
215 program: context.program,
216 scene: scene,
217 },
218 });
220 }
222 return elm.Native.Graphics.WebGL.values = {
223 glContext:F2(glContext),
224 bindMesh:F2(bindMesh),
225 renderGL:F2(renderGL),
226 };
228};