on 3c338bd help sign in
221 lines 7.0 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 encapsulate(program, buffer, uniforms) {
20 var model = {
21 program: program,
22 buffer: buffer,
23 uniforms: uniforms
24 };
26 return model;
28 }
30 function link (gl, vSrc, fSrc) {
32 function createShader(str, type) {
34 var shader = gl.createShader(type);
36 gl.shaderSource(shader, str);
37 gl.compileShader(shader);
38 var compile = gl.COMPILE_STATUS;
39 if (!gl.getShaderParameter(shader,compile)) {
40 throw gl.getShaderInfoLog(shader);
41 }
43 return shader;
45 };
47 var vshader = createShader(vSrc, gl.VERTEX_SHADER);
48 var fshader = createShader(fSrc, gl.FRAGMENT_SHADER);
49 var program = gl.createProgram();
51 gl.attachShader(program, vshader);
52 gl.attachShader(program, fshader);
53 gl.linkProgram(program);
54 if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
55 throw gl.getProgramInfoLog(program);
56 }
58 return program;
60 }
62 function bind (gl, program, bufferElems) {
64 var buffers = {};
66 var attributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
67 for (var i = 0; i < attributes; i += 1) {
68 var attribute = gl.getActiveAttrib(program, i);
69 switch (attribute.type) {
70 case gl.FLOAT_VEC3:
72 // Might want to invert the loop
73 // to build the array buffer first
74 // and then bind each one-at-a-time
75 var data = [];
76 List.each(function(elem){
77 data.push(elem[attribute.name][0]);
78 data.push(elem[attribute.name][1]);
79 data.push(elem[attribute.name][2]);
80 }, bufferElems);
81 var array = new Float32Array(data);
83 var buffer = gl.createBuffer();
84 console.log("Created attribute buffer " + attribute.name);
85 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
86 gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
88 buffers[attribute.name] = buffer;
90 break;
92 default:
93 console.log("Bad buffer type");
94 break;
95 }
97 }
99 var numIndices = List.length(bufferElems);
100 var indices = List.toArray(List.range(0,numIndices));
101 console.log("Created index buffer");
102 var indexBuffer = gl.createBuffer();
103 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
104 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
106 var bufferObject = {
107 numIndices: List.length(bufferElems),
108 indexBuffer: indexBuffer,
109 buffers: buffers
110 };
112 return bufferObject;
114 }
116 function drawGL(gl,state) {
118 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
120 function drawModel(model) {
122 var program = model.program;
123 gl.useProgram(program);
125 var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
126 for (var i = 0; i < numUniforms; i += 1) {
127 var uniform = gl.getActiveUniform(program, i);
128 var uniformLocation = gl.getUniformLocation(program, uniform.name);
129 switch (uniform.type) {
130 case gl.FLOAT_MAT4:
131 gl.uniformMatrix4fv(uniformLocation, false, model.uniforms[uniform.name]);
132 break;
133 default:
134 console.log("Unsupported uniform type: " + uniform.type);
135 break;
136 }
137 }
139 var numIndices = model.buffer.numIndices;
140 var indexBuffer = model.buffer.indexBuffer;
141 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
143 var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
144 for (var i = 0; i < numAttributes; i += 1) {
145 var attribute = gl.getActiveAttrib(program, i);
146 var attribLocation = gl.getAttribLocation(program, attribute.name);
147 gl.enableVertexAttribArray(attribLocation);
148 attributeBuffer = model.buffer.buffers[attribute.name];
150 switch (attribute.type) {
151 case gl.FLOAT_VEC3:
152 gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
153 gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
154 break;
155 default:
156 console.log("Unsupported attribute type: " + attribute.type);
157 break;
158 }
159 }
161 gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
163 }
165 List.each(drawModel, state.models);
167 }
169 function webgl(sDimensions, sfDraw) {
171 if (!window.WebGLRenderingContext) {
172 throw new Error("It appears your browser does not support WebGL! http://get.webgl.org/troubleshooting");
173 return;
174 }
176 var node = newNode('canvas');
177 var gl = node.getContext('webgl');
178 var sGL = Signal.constant(gl);
180 var sModels = sfDraw(sGL);
182 function makeGLelement(dimensions, models, gl) {
184 var w = dimensions._0;
185 var h = dimensions._1;
187 function render(state) {
188 drawGL(gl,state);
189 return node;
190 }
192 function update(_node, oldState, newState) {
193 drawGL(gl,newState)
194 }
196 var elem = {
197 ctor: 'Custom',
198 type: 'WebGL',
199 render: render,
200 update: update,
201 model: {
202 models: models,
203 }
204 };
206 return A3(newElement, w, h, elem);
208 }
210 return A4(Signal.lift3,F3(makeGLelement),sDimensions,sModels,sGL);
212 }
214 return elm.Native.Graphics.WebGL.values = {
215 link:F3(link),
216 bind:F3(bind),
217 encapsulate:F3(encapsulate),
218 webgl:F2(webgl)
219 };
221};