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