on 7aa4a5a help sign in
227 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 'SceneLeaf':
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 makeGL(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 bufferMesh(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 for (var i = 0; i < 3; i+= 1) {
165 indices.push(3 * n + i);
166 var vertex = tri['_' + i];
167 for (var j = 0; j < 3; j += 1) {
168 positions.push(vertex.pos[j]);
169 }
170 colors.push(vertex.color._0 / 256);
171 colors.push(vertex.color._1 / 256);
172 colors.push(vertex.color._2 / 256);
173 colors.push(vertex.color._3);
174 }
175 pushTriangle(n+1,node._1);
176 }
178 pushTriangle(0,triangles);
180 var gl = context.gl;
182 var indexBuffer = gl.createBuffer();
183 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
184 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
186 var vertexPosBuffer = gl.createBuffer();
187 gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
188 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
190 var vertexColorBuffer = gl.createBuffer();
191 gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
192 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
194 return {
195 indexBuffer: indexBuffer,
196 vertexPosBuffer: vertexPosBuffer,
197 vertexColorBuffer: vertexColorBuffer,
198 numIndices: indices.length,
199 };
201 }
203 function webgl(context, scene) {
205 return A3(newElement, context.w, context.h, {
206 ctor: 'Custom',
207 type: 'WebGL',
208 render: render,
209 update: update,
210 model: {
211 aspect: context.w/context.h,
212 node: context.node,
213 gl: context.gl,
214 program: context.program,
215 scene: scene,
216 },
217 });
219 }
221 return elm.Native.Graphics.WebGL.values = {
222 makeGL:F2(makeGL),
223 bufferMesh:F2(bufferMesh),
224 webgl:F2(webgl),
225 };
227};