0
|
1 /*
|
|
2 * Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
|
3 *
|
|
4 * Redistribution and use in source and binary forms, with or without
|
|
5 * modification, are permitted provided that the following conditions
|
|
6 * are met:
|
|
7 * 1. Redistributions of source code must retain the above copyright
|
|
8 * notice, this list of conditions and the following disclaimer.
|
|
9 * 2. Redistributions in binary form must reproduce the above copyright
|
|
10 * notice, this list of conditions and the following disclaimer in the
|
|
11 * documentation and/or other materials provided with the distribution.
|
|
12 *
|
|
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
|
|
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
|
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
24 */
|
|
25
|
|
26 //
|
|
27 // initWebGL
|
|
28 //
|
|
29 // Initialize the Canvas element with the passed name as a WebGL object and return the
|
|
30 // WebGLRenderingContext.
|
|
31 //
|
|
32 // Load shaders with the passed names and create a program with them. Return this program
|
|
33 // in the 'program' property of the returned context.
|
|
34 //
|
|
35 // For each string in the passed attribs array, bind an attrib with that name at that index.
|
|
36 // Once the attribs are bound, link the program and then use it.
|
|
37 //
|
|
38 // Set the clear color to the passed array (4 values) and set the clear depth to the passed value.
|
|
39 // Enable depth testing and blending with a blend func of (SRC_ALPHA, ONE_MINUS_SRC_ALPHA)
|
|
40 //
|
|
41 // A console function is added to the context: console(string). This can be replaced
|
|
42 // by the caller. By default, it maps to the window.console() function on WebKit and to
|
|
43 // an empty function on other browsers.
|
|
44 //
|
|
45 function initWebGL(canvasName, vshader, fshader, attribs, clearColor, clearDepth)
|
|
46 {
|
|
47 var canvas = document.getElementById(canvasName);
|
|
48 var gl = WebGLUtils.setupWebGL(canvas);
|
|
49 if (!gl) {
|
|
50 return null;
|
|
51 }
|
|
52
|
|
53 // Add a console
|
|
54 gl.console = ("console" in window) ? window.console : { log: function() { } };
|
|
55
|
|
56 // create our shaders
|
|
57 var vertexShader = loadShader(gl, vshader);
|
|
58 var fragmentShader = loadShader(gl, fshader);
|
|
59
|
|
60 if (!vertexShader || !fragmentShader)
|
|
61 return null;
|
|
62
|
|
63 // Create the program object
|
|
64 gl.program = gl.createProgram();
|
|
65
|
|
66 if (!gl.program)
|
|
67 return null;
|
|
68
|
|
69 // Attach our two shaders to the program
|
|
70 gl.attachShader (gl.program, vertexShader);
|
|
71 gl.attachShader (gl.program, fragmentShader);
|
|
72
|
|
73 // Bind attributes
|
|
74 for (var i = 0; i < attribs.length; ++i)
|
|
75 gl.bindAttribLocation (gl.program, i, attribs[i]);
|
|
76
|
|
77 // Link the program
|
|
78 gl.linkProgram(gl.program);
|
|
79
|
|
80 // Check the link status
|
|
81 var linked = gl.getProgramParameter(gl.program, gl.LINK_STATUS);
|
|
82 if (!linked) {
|
|
83 // something went wrong with the link
|
|
84 var error = gl.getProgramInfoLog (gl.program);
|
|
85 gl.console.log("Error in program linking:"+error);
|
|
86
|
|
87 gl.deleteProgram(gl.program);
|
|
88 gl.deleteProgram(fragmentShader);
|
|
89 gl.deleteProgram(vertexShader);
|
|
90
|
|
91 return null;
|
|
92 }
|
|
93
|
|
94 gl.useProgram(gl.program);
|
|
95
|
|
96 gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
|
97 gl.clearDepth(clearDepth);
|
|
98
|
|
99 gl.enable(gl.DEPTH_TEST);
|
|
100 gl.enable(gl.BLEND);
|
|
101 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
102
|
|
103 return gl;
|
|
104 }
|
|
105
|
|
106 //
|
|
107 // loadShader
|
|
108 //
|
|
109 // 'shaderId' is the id of a <script> element containing the shader source string.
|
|
110 // Load this shader and return the WebGLShader object corresponding to it.
|
|
111 //
|
|
112 function loadShader(ctx, shaderId)
|
|
113 {
|
|
114 var shaderScript = document.getElementById(shaderId);
|
|
115 if (!shaderScript) {
|
|
116 ctx.console.log("*** Error: shader script '"+shaderId+"' not found");
|
|
117 return null;
|
|
118 }
|
|
119
|
|
120 if (shaderScript.type == "x-shader/x-vertex")
|
|
121 var shaderType = ctx.VERTEX_SHADER;
|
|
122 else if (shaderScript.type == "x-shader/x-fragment")
|
|
123 var shaderType = ctx.FRAGMENT_SHADER;
|
|
124 else {
|
|
125 ctx.console.log("*** Error: shader script '"+shaderId+"' of undefined type '"+shaderScript.type+"'");
|
|
126 return null;
|
|
127 }
|
|
128
|
|
129 // Create the shader object
|
|
130 var shader = ctx.createShader(shaderType);
|
|
131 if (shader == null) {
|
|
132 ctx.console.log("*** Error: unable to create shader '"+shaderId+"'");
|
|
133 return null;
|
|
134 }
|
|
135
|
|
136 // Load the shader source
|
|
137 ctx.shaderSource(shader, shaderScript.text);
|
|
138
|
|
139 // Compile the shader
|
|
140 ctx.compileShader(shader);
|
|
141
|
|
142 // Check the compile status
|
|
143 var compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
|
|
144 if (!compiled) {
|
|
145 // Something went wrong during compilation; get the error
|
|
146 var error = ctx.getShaderInfoLog(shader);
|
|
147 ctx.console.log("*** Error compiling shader '"+shaderId+"':"+error);
|
|
148 ctx.deleteShader(shader);
|
|
149 return null;
|
|
150 }
|
|
151
|
|
152 return shader;
|
|
153 }
|
|
154
|
|
155 //
|
|
156 // makeBox
|
|
157 //
|
|
158 // Create a box with vertices, normals and texCoords. Create VBOs for each as well as the index array.
|
|
159 // Return an object with the following properties:
|
|
160 //
|
|
161 // normalObject WebGLBuffer object for normals
|
|
162 // texCoordObject WebGLBuffer object for texCoords
|
|
163 // vertexObject WebGLBuffer object for vertices
|
|
164 // indexObject WebGLBuffer object for indices
|
|
165 // numIndices The number of indices in the indexObject
|
|
166 //
|
|
167 function makeBox(ctx)
|
|
168 {
|
|
169 // box
|
|
170 // v6----- v5
|
|
171 // /| /|
|
|
172 // v1------v0|
|
|
173 // | | | |
|
|
174 // | |v7---|-|v4
|
|
175 // |/ |/
|
|
176 // v2------v3
|
|
177 //
|
|
178 // vertex coords array
|
|
179 var vertices = new Float32Array(
|
|
180 [ 1, 1, 1, -1, 1, 1, -1,-1, 1, 1,-1, 1, // v0-v1-v2-v3 front
|
|
181 1, 1, 1, 1,-1, 1, 1,-1,-1, 1, 1,-1, // v0-v3-v4-v5 right
|
|
182 1, 1, 1, 1, 1,-1, -1, 1,-1, -1, 1, 1, // v0-v5-v6-v1 top
|
|
183 -1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1, 1, // v1-v6-v7-v2 left
|
|
184 -1,-1,-1, 1,-1,-1, 1,-1, 1, -1,-1, 1, // v7-v4-v3-v2 bottom
|
|
185 1,-1,-1, -1,-1,-1, -1, 1,-1, 1, 1,-1 ] // v4-v7-v6-v5 back
|
|
186 );
|
|
187
|
|
188 // normal array
|
|
189 var normals = new Float32Array(
|
|
190 [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front
|
|
191 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
|
|
192 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top
|
|
193 -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left
|
|
194 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, // v7-v4-v3-v2 bottom
|
|
195 0, 0,-1, 0, 0,-1, 0, 0,-1, 0, 0,-1 ] // v4-v7-v6-v5 back
|
|
196 );
|
|
197
|
|
198
|
|
199 // texCoord array
|
|
200 var texCoords = new Float32Array(
|
|
201 [ 1, 1, 0, 1, 0, 0, 1, 0, // v0-v1-v2-v3 front
|
|
202 0, 1, 0, 0, 1, 0, 1, 1, // v0-v3-v4-v5 right
|
|
203 1, 0, 1, 1, 0, 1, 0, 0, // v0-v5-v6-v1 top
|
|
204 1, 1, 0, 1, 0, 0, 1, 0, // v1-v6-v7-v2 left
|
|
205 0, 0, 1, 0, 1, 1, 0, 1, // v7-v4-v3-v2 bottom
|
|
206 0, 0, 1, 0, 1, 1, 0, 1 ] // v4-v7-v6-v5 back
|
|
207 );
|
|
208
|
|
209 // index array
|
|
210 var indices = new Uint8Array(
|
|
211 [ 0, 1, 2, 0, 2, 3, // front
|
|
212 4, 5, 6, 4, 6, 7, // right
|
|
213 8, 9,10, 8,10,11, // top
|
|
214 12,13,14, 12,14,15, // left
|
|
215 16,17,18, 16,18,19, // bottom
|
|
216 20,21,22, 20,22,23 ] // back
|
|
217 );
|
|
218
|
|
219 var retval = { };
|
|
220
|
|
221 retval.normalObject = ctx.createBuffer();
|
|
222 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
|
|
223 ctx.bufferData(ctx.ARRAY_BUFFER, normals, ctx.STATIC_DRAW);
|
|
224
|
|
225 retval.texCoordObject = ctx.createBuffer();
|
|
226 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
|
|
227 ctx.bufferData(ctx.ARRAY_BUFFER, texCoords, ctx.STATIC_DRAW);
|
|
228
|
|
229 retval.vertexObject = ctx.createBuffer();
|
|
230 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
|
|
231 ctx.bufferData(ctx.ARRAY_BUFFER, vertices, ctx.STATIC_DRAW);
|
|
232
|
|
233 ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
|
|
234
|
|
235 retval.indexObject = ctx.createBuffer();
|
|
236 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
|
|
237 ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, indices, ctx.STATIC_DRAW);
|
|
238 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
|
|
239
|
|
240 retval.numIndices = indices.length;
|
|
241
|
|
242 return retval;
|
|
243 }
|
|
244
|
|
245 //
|
|
246 // makeSphere
|
|
247 //
|
|
248 // Create a sphere with the passed number of latitude and longitude bands and the passed radius.
|
|
249 // Sphere has vertices, normals and texCoords. Create VBOs for each as well as the index array.
|
|
250 // Return an object with the following properties:
|
|
251 //
|
|
252 // normalObject WebGLBuffer object for normals
|
|
253 // texCoordObject WebGLBuffer object for texCoords
|
|
254 // vertexObject WebGLBuffer object for vertices
|
|
255 // indexObject WebGLBuffer object for indices
|
|
256 // numIndices The number of indices in the indexObject
|
|
257 //
|
|
258 function makeSphere(ctx, radius, lats, longs)
|
|
259 {
|
|
260 var geometryData = [ ];
|
|
261 var normalData = [ ];
|
|
262 var texCoordData = [ ];
|
|
263 var indexData = [ ];
|
|
264
|
|
265 for (var latNumber = 0; latNumber <= lats; ++latNumber) {
|
|
266 for (var longNumber = 0; longNumber <= longs; ++longNumber) {
|
|
267 var theta = latNumber * Math.PI / lats;
|
|
268 var phi = longNumber * 2 * Math.PI / longs;
|
|
269 var sinTheta = Math.sin(theta);
|
|
270 var sinPhi = Math.sin(phi);
|
|
271 var cosTheta = Math.cos(theta);
|
|
272 var cosPhi = Math.cos(phi);
|
|
273
|
|
274 var x = cosPhi * sinTheta;
|
|
275 var y = cosTheta;
|
|
276 var z = sinPhi * sinTheta;
|
|
277 var u = 1-(longNumber/longs);
|
|
278 var v = latNumber/lats;
|
|
279
|
|
280 normalData.push(x);
|
|
281 normalData.push(y);
|
|
282 normalData.push(z);
|
|
283 texCoordData.push(u);
|
|
284 texCoordData.push(v);
|
|
285 geometryData.push(radius * x);
|
|
286 geometryData.push(radius * y);
|
|
287 geometryData.push(radius * z);
|
|
288 }
|
|
289 }
|
|
290
|
|
291 for (var latNumber = 0; latNumber < lats; ++latNumber) {
|
|
292 for (var longNumber = 0; longNumber < longs; ++longNumber) {
|
|
293 var first = (latNumber * (longs+1)) + longNumber;
|
|
294 var second = first + longs + 1;
|
|
295 indexData.push(first);
|
|
296 indexData.push(second);
|
|
297 indexData.push(first+1);
|
|
298
|
|
299 indexData.push(second);
|
|
300 indexData.push(second+1);
|
|
301 indexData.push(first+1);
|
|
302 }
|
|
303 }
|
|
304
|
|
305 var retval = { };
|
|
306
|
|
307 retval.normalObject = ctx.createBuffer();
|
|
308 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.normalObject);
|
|
309 ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(normalData), ctx.STATIC_DRAW);
|
|
310
|
|
311 retval.texCoordObject = ctx.createBuffer();
|
|
312 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.texCoordObject);
|
|
313 ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(texCoordData), ctx.STATIC_DRAW);
|
|
314
|
|
315 retval.vertexObject = ctx.createBuffer();
|
|
316 ctx.bindBuffer(ctx.ARRAY_BUFFER, retval.vertexObject);
|
|
317 ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(geometryData), ctx.STATIC_DRAW);
|
|
318
|
|
319 retval.numIndices = indexData.length;
|
|
320 retval.indexObject = ctx.createBuffer();
|
|
321 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, retval.indexObject);
|
|
322 ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), ctx.STREAM_DRAW);
|
|
323
|
|
324 return retval;
|
|
325 }
|
|
326
|
|
327 //
|
|
328 // loadObj
|
|
329 //
|
|
330 // Load a .obj file from the passed URL. Return an object with a 'loaded' property set to false.
|
|
331 // When the object load is complete, the 'loaded' property becomes true and the following
|
|
332 // properties are set:
|
|
333 //
|
|
334 // normalObject WebGLBuffer object for normals
|
|
335 // texCoordObject WebGLBuffer object for texCoords
|
|
336 // vertexObject WebGLBuffer object for vertices
|
|
337 // indexObject WebGLBuffer object for indices
|
|
338 // numIndices The number of indices in the indexObject
|
|
339 //
|
|
340 function loadObj(ctx, url)
|
|
341 {
|
|
342 var obj = { loaded : false };
|
|
343 obj.ctx = ctx;
|
|
344 var req = new XMLHttpRequest();
|
|
345 req.obj = obj;
|
|
346 req.onreadystatechange = function () { processLoadObj(req) };
|
|
347 req.open("GET", url, true);
|
|
348 req.send(null);
|
|
349 return obj;
|
|
350 }
|
|
351
|
|
352 function processLoadObj(req)
|
|
353 {
|
|
354 req.obj.ctx.console.log("req="+req)
|
|
355 // only if req shows "complete"
|
|
356 if (req.readyState == 4) {
|
|
357 doLoadObj(req.obj, req.responseText);
|
|
358 }
|
|
359 }
|
|
360
|
|
361 function doLoadObj(obj, text)
|
|
362 {
|
|
363 vertexArray = [ ];
|
|
364 normalArray = [ ];
|
|
365 textureArray = [ ];
|
|
366 indexArray = [ ];
|
|
367
|
|
368 var vertex = [ ];
|
|
369 var normal = [ ];
|
|
370 var texture = [ ];
|
|
371 var facemap = { };
|
|
372 var index = 0;
|
|
373
|
|
374 // This is a map which associates a range of indices with a name
|
|
375 // The name comes from the 'g' tag (of the form "g NAME"). Indices
|
|
376 // are part of one group until another 'g' tag is seen. If any indices
|
|
377 // come before a 'g' tag, it is given the group name "_unnamed"
|
|
378 // 'group' is an object whose property names are the group name and
|
|
379 // whose value is a 2 element array with [<first index>, <num indices>]
|
|
380 var groups = { };
|
|
381 var currentGroup = [-1, 0];
|
|
382 groups["_unnamed"] = currentGroup;
|
|
383
|
|
384 var lines = text.split("\n");
|
|
385 for (var lineIndex in lines) {
|
|
386 var line = lines[lineIndex].replace(/[ \t]+/g, " ").replace(/\s\s*$/, "");
|
|
387
|
|
388 // ignore comments
|
|
389 if (line[0] == "#")
|
|
390 continue;
|
|
391
|
|
392 var array = line.split(" ");
|
|
393 if (array[0] == "g") {
|
|
394 // new group
|
|
395 currentGroup = [indexArray.length, 0];
|
|
396 groups[array[1]] = currentGroup;
|
|
397 }
|
|
398 else if (array[0] == "v") {
|
|
399 // vertex
|
|
400 vertex.push(parseFloat(array[1]));
|
|
401 vertex.push(parseFloat(array[2]));
|
|
402 vertex.push(parseFloat(array[3]));
|
|
403 }
|
|
404 else if (array[0] == "vt") {
|
|
405 // normal
|
|
406 texture.push(parseFloat(array[1]));
|
|
407 texture.push(parseFloat(array[2]));
|
|
408 }
|
|
409 else if (array[0] == "vn") {
|
|
410 // normal
|
|
411 normal.push(parseFloat(array[1]));
|
|
412 normal.push(parseFloat(array[2]));
|
|
413 normal.push(parseFloat(array[3]));
|
|
414 }
|
|
415 else if (array[0] == "f") {
|
|
416 // face
|
|
417 if (array.length != 4) {
|
|
418 obj.ctx.console.log("*** Error: face '"+line+"' not handled");
|
|
419 continue;
|
|
420 }
|
|
421
|
|
422 for (var i = 1; i < 4; ++i) {
|
|
423 if (!(array[i] in facemap)) {
|
|
424 // add a new entry to the map and arrays
|
|
425 var f = array[i].split("/");
|
|
426 var vtx, nor, tex;
|
|
427
|
|
428 if (f.length == 1) {
|
|
429 vtx = parseInt(f[0]) - 1;
|
|
430 nor = vtx;
|
|
431 tex = vtx;
|
|
432 }
|
|
433 else if (f.length = 3) {
|
|
434 vtx = parseInt(f[0]) - 1;
|
|
435 tex = parseInt(f[1]) - 1;
|
|
436 nor = parseInt(f[2]) - 1;
|
|
437 }
|
|
438 else {
|
|
439 obj.ctx.console.log("*** Error: did not understand face '"+array[i]+"'");
|
|
440 return null;
|
|
441 }
|
|
442
|
|
443 // do the vertices
|
|
444 var x = 0;
|
|
445 var y = 0;
|
|
446 var z = 0;
|
|
447 if (vtx * 3 + 2 < vertex.length) {
|
|
448 x = vertex[vtx*3];
|
|
449 y = vertex[vtx*3+1];
|
|
450 z = vertex[vtx*3+2];
|
|
451 }
|
|
452 vertexArray.push(x);
|
|
453 vertexArray.push(y);
|
|
454 vertexArray.push(z);
|
|
455
|
|
456 // do the textures
|
|
457 x = 0;
|
|
458 y = 0;
|
|
459 if (tex * 2 + 1 < texture.length) {
|
|
460 x = texture[tex*2];
|
|
461 y = texture[tex*2+1];
|
|
462 }
|
|
463 textureArray.push(x);
|
|
464 textureArray.push(y);
|
|
465
|
|
466 // do the normals
|
|
467 x = 0;
|
|
468 y = 0;
|
|
469 z = 1;
|
|
470 if (nor * 3 + 2 < normal.length) {
|
|
471 x = normal[nor*3];
|
|
472 y = normal[nor*3+1];
|
|
473 z = normal[nor*3+2];
|
|
474 }
|
|
475 normalArray.push(x);
|
|
476 normalArray.push(y);
|
|
477 normalArray.push(z);
|
|
478
|
|
479 facemap[array[i]] = index++;
|
|
480 }
|
|
481
|
|
482 indexArray.push(facemap[array[i]]);
|
|
483 currentGroup[1]++;
|
|
484 }
|
|
485 }
|
|
486 }
|
|
487
|
|
488 // set the VBOs
|
|
489 obj.normalObject = obj.ctx.createBuffer();
|
|
490 obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.normalObject);
|
|
491 obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(normalArray), obj.ctx.STATIC_DRAW);
|
|
492
|
|
493 obj.texCoordObject = obj.ctx.createBuffer();
|
|
494 obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.texCoordObject);
|
|
495 obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(textureArray), obj.ctx.STATIC_DRAW);
|
|
496
|
|
497 obj.vertexObject = obj.ctx.createBuffer();
|
|
498 obj.ctx.bindBuffer(obj.ctx.ARRAY_BUFFER, obj.vertexObject);
|
|
499 obj.ctx.bufferData(obj.ctx.ARRAY_BUFFER, new Float32Array(vertexArray), obj.ctx.STATIC_DRAW);
|
|
500
|
|
501 obj.numIndices = indexArray.length;
|
|
502 obj.indexObject = obj.ctx.createBuffer();
|
|
503 obj.ctx.bindBuffer(obj.ctx.ELEMENT_ARRAY_BUFFER, obj.indexObject);
|
|
504 obj.ctx.bufferData(obj.ctx.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexArray), obj.ctx.STREAM_DRAW);
|
|
505
|
|
506 obj.groups = groups;
|
|
507
|
|
508 obj.loaded = true;
|
|
509 }
|
|
510
|
|
511 //
|
|
512 // loadImageTexture
|
|
513 //
|
|
514 // Load the image at the passed url, place it in a new WebGLTexture object and return the WebGLTexture.
|
|
515 //
|
|
516 function loadImageTexture(ctx, url)
|
|
517 {
|
|
518 var texture = ctx.createTexture();
|
|
519 texture.image = new Image();
|
|
520 texture.image.onload = function() { doLoadImageTexture(ctx, texture.image, texture) }
|
|
521 texture.image.src = url;
|
|
522 return texture;
|
|
523 }
|
|
524
|
|
525 function doLoadImageTexture(ctx, image, texture)
|
|
526 {
|
|
527 ctx.bindTexture(ctx.TEXTURE_2D, texture);
|
|
528 ctx.texImage2D(
|
|
529 ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image);
|
|
530 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR);
|
|
531 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR);
|
|
532 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE);
|
|
533 ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE);
|
|
534 //ctx.generateMipmap(ctx.TEXTURE_2D)
|
|
535 ctx.bindTexture(ctx.TEXTURE_2D, null);
|
|
536 }
|
|
537
|
|
538 //
|
|
539 // Framerate object
|
|
540 //
|
|
541 // This object keeps track of framerate and displays it as the innerHTML text of the
|
|
542 // HTML element with the passed id. Once created you call snapshot at the end
|
|
543 // of every rendering cycle. Every 500ms the framerate is updated in the HTML element.
|
|
544 //
|
|
545 Framerate = function(id)
|
|
546 {
|
|
547 this.numFramerates = 10;
|
|
548 this.framerateUpdateInterval = 500;
|
|
549 this.id = id;
|
|
550
|
|
551 this.renderTime = -1;
|
|
552 this.framerates = [ ];
|
|
553 self = this;
|
|
554 var fr = function() { self.updateFramerate() }
|
|
555 setInterval(fr, this.framerateUpdateInterval);
|
|
556 }
|
|
557
|
|
558 Framerate.prototype.updateFramerate = function()
|
|
559 {
|
|
560 var tot = 0;
|
|
561 for (var i = 0; i < this.framerates.length; ++i)
|
|
562 tot += this.framerates[i];
|
|
563
|
|
564 var framerate = tot / this.framerates.length;
|
|
565 framerate = Math.round(framerate);
|
|
566 document.getElementById(this.id).innerHTML = "Framerate:"+framerate+"fps";
|
|
567 }
|
|
568
|
|
569 Framerate.prototype.snapshot = function()
|
|
570 {
|
|
571 if (this.renderTime < 0)
|
|
572 this.renderTime = new Date().getTime();
|
|
573 else {
|
|
574 var newTime = new Date().getTime();
|
|
575 var t = newTime - this.renderTime;
|
|
576 var framerate = 1000/t;
|
|
577 this.framerates.push(framerate);
|
|
578 while (this.framerates.length > this.numFramerates)
|
|
579 this.framerates.shift();
|
|
580 this.renderTime = newTime;
|
|
581 }
|
|
582 }
|