on 1afcf6e help sign in
213 lines 6.7 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 bufferObject = {
100 numIndices: List.length(bufferElems),
101 buffers: buffers
102 };
104 return bufferObject;
106 }
108 function drawGL(gl,state) {
110 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
112 function drawModel(model) {
114 var program = model.program;
115 gl.useProgram(program);
117 var numUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
118 for (var i = 0; i < numUniforms; i += 1) {
119 var uniform = gl.getActiveUniform(program, i);
120 var uniformLocation = gl.getUniformLocation(program, uniform.name);
121 switch (uniform.type) {
122 case gl.FLOAT_MAT4:
123 gl.uniformMatrix4fv(uniformLocation, false, model.uniforms[uniform.name]);
124 break;
125 default:
126 console.log("Unsupported uniform type: " + uniform.type);
127 break;
128 }
129 }
131 var numIndices = model.buffer.numIndices;
132 var indices = List.toArray(List.range(0,numIndices));
134 console.log("Created index buffer");
135 var indexBuffer = gl.createBuffer();
136 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
137 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
139 var numAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
140 for (var i = 0; i < numAttributes; i += 1) {
141 var attribute = gl.getActiveAttrib(program, i);
142 var attribLocation = gl.getAttribLocation(program, attribute.name);
143 gl.enableVertexAttribArray(attribLocation);
144 attributeBuffer = model.buffer.buffers[attribute.name];
146 switch (attribute.type) {
147 case gl.FLOAT_VEC3:
148 gl.bindBuffer(gl.ARRAY_BUFFER, attributeBuffer);
149 gl.vertexAttribPointer(attribLocation, 3, gl.FLOAT, false, 0, 0);
150 break;
151 default:
152 console.log("Unsupported attribute type: " + attribute.type);
153 break;
154 }
155 }
157 gl.drawElements(gl.TRIANGLES, numIndices, gl.UNSIGNED_SHORT, 0);
159 }
161 List.each(drawModel, state.models);
163 }
165 function webgl(sDimensions, sDraw) {
167 var node = newNode('canvas');
168 var gl = node.getContext('webgl');
169 var sGL = Signal.constant(gl);
171 var application = F2(function(f,x) { return f(x); });
172 var sModels = A3(Signal.lift2,application,sDraw,sGL);
174 function makeGLelement(dimensions, models, gl) {
176 var w = dimensions._0;
177 var h = dimensions._1;
179 function render(state) {
180 drawGL(gl,state);
181 return node;
182 }
184 function update(_node, oldState, newState) {
185 drawGL(gl,newState)
186 }
188 var elem = {
189 ctor: 'Custom',
190 type: 'WebGL',
191 render: render,
192 update: update,
193 model: {
194 models: models,
195 }
196 };
198 return A3(newElement, w, h, elem);
200 }
202 return A4(Signal.lift3,F3(makeGLelement),sDimensions,sModels,sGL);
204 }
206 return elm.Native.Graphics.WebGL.values = {
207 link:F3(link),
208 bind:F3(bind),
209 encapsulate:F3(encapsulate),
210 webgl:F2(webgl)
211 };
213};