bsp viewer
[tar-legacy.git] / MCDV_Web / main.html
1 <head>
2
3 </head>
4
5 <body>
6
7 <canvas id="glCanvas" width="640" height="480"></canvas>
8
9 </body>
10
11 <script src="gl-matrix.js"></script>
12 <script>
13 var cubeRotation = 0.0;
14
15 main();
16
17 //
18 // Start here
19 //
20 function main() {
21 const canvas = document.querySelector('#glcanvas');
22 const gl = canvas.getContext('webgl');
23
24 // If we don't have a GL context, give up now
25
26 if (!gl) {
27 alert('Unable to initialize WebGL. Your browser or machine may not support it.');
28 return;
29 }
30
31 // Vertex shader program
32
33 const vsSource = `
34 attribute vec4 aVertexPosition;
35 attribute vec2 aTextureCoord;
36 uniform mat4 uModelViewMatrix;
37 uniform mat4 uProjectionMatrix;
38 varying highp vec2 vTextureCoord;
39 void main(void) {
40 gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
41 vTextureCoord = aTextureCoord;
42 }
43 `;
44
45 // Fragment shader program
46
47 const fsSource = `
48 varying highp vec2 vTextureCoord;
49 uniform sampler2D uSampler;
50 void main(void) {
51 gl_FragColor = texture2D(uSampler, vTextureCoord);
52 }
53 `;
54
55 // Initialize a shader program; this is where all the lighting
56 // for the vertices and so forth is established.
57 const shaderProgram = initShaderProgram(gl, vsSource, fsSource);
58
59 // Collect all the info needed to use the shader program.
60 // Look up which attributes our shader program is using
61 // for aVertexPosition, aTextureCoord and also
62 // look up uniform locations.
63 const programInfo = {
64 program: shaderProgram,
65 attribLocations: {
66 vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
67 textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
68 },
69 uniformLocations: {
70 projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
71 modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'),
72 uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
73 },
74 };
75
76 // Here's where we call the routine that builds all the
77 // objects we'll be drawing.
78 const buffers = initBuffers(gl);
79
80 const texture = loadTexture(gl, 'cubetexture.png');
81
82 var then = 0;
83
84 // Draw the scene repeatedly
85 function render(now) {
86 now *= 0.001; // convert to seconds
87 const deltaTime = now - then;
88 then = now;
89
90 drawScene(gl, programInfo, buffers, texture, deltaTime);
91
92 requestAnimationFrame(render);
93 }
94 requestAnimationFrame(render);
95 }
96
97 //
98 // initBuffers
99 //
100 // Initialize the buffers we'll need. For this demo, we just
101 // have one object -- a simple three-dimensional cube.
102 //
103 function initBuffers(gl) {
104
105 // Create a buffer for the cube's vertex positions.
106
107 const positionBuffer = gl.createBuffer();
108
109 // Select the positionBuffer as the one to apply buffer
110 // operations to from here out.
111
112 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
113
114 // Now create an array of positions for the cube.
115
116 const positions = [
117 // Front face
118 -1.0, -1.0, 1.0,
119 1.0, -1.0, 1.0,
120 1.0, 1.0, 1.0,
121 -1.0, 1.0, 1.0,
122
123 // Back face
124 -1.0, -1.0, -1.0,
125 -1.0, 1.0, -1.0,
126 1.0, 1.0, -1.0,
127 1.0, -1.0, -1.0,
128
129 // Top face
130 -1.0, 1.0, -1.0,
131 -1.0, 1.0, 1.0,
132 1.0, 1.0, 1.0,
133 1.0, 1.0, -1.0,
134
135 // Bottom face
136 -1.0, -1.0, -1.0,
137 1.0, -1.0, -1.0,
138 1.0, -1.0, 1.0,
139 -1.0, -1.0, 1.0,
140
141 // Right face
142 1.0, -1.0, -1.0,
143 1.0, 1.0, -1.0,
144 1.0, 1.0, 1.0,
145 1.0, -1.0, 1.0,
146
147 // Left face
148 -1.0, -1.0, -1.0,
149 -1.0, -1.0, 1.0,
150 -1.0, 1.0, 1.0,
151 -1.0, 1.0, -1.0,
152 ];
153
154 // Now pass the list of positions into WebGL to build the
155 // shape. We do this by creating a Float32Array from the
156 // JavaScript array, then use it to fill the current buffer.
157
158 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
159
160 // Now set up the texture coordinates for the faces.
161
162 const textureCoordBuffer = gl.createBuffer();
163 gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
164
165 const textureCoordinates = [
166 // Front
167 0.0, 0.0,
168 1.0, 0.0,
169 1.0, 1.0,
170 0.0, 1.0,
171 // Back
172 0.0, 0.0,
173 1.0, 0.0,
174 1.0, 1.0,
175 0.0, 1.0,
176 // Top
177 0.0, 0.0,
178 1.0, 0.0,
179 1.0, 1.0,
180 0.0, 1.0,
181 // Bottom
182 0.0, 0.0,
183 1.0, 0.0,
184 1.0, 1.0,
185 0.0, 1.0,
186 // Right
187 0.0, 0.0,
188 1.0, 0.0,
189 1.0, 1.0,
190 0.0, 1.0,
191 // Left
192 0.0, 0.0,
193 1.0, 0.0,
194 1.0, 1.0,
195 0.0, 1.0,
196 ];
197
198 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
199 gl.STATIC_DRAW);
200
201 // Build the element array buffer; this specifies the indices
202 // into the vertex arrays for each face's vertices.
203
204 const indexBuffer = gl.createBuffer();
205 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
206
207 // This array defines each face as two triangles, using the
208 // indices into the vertex array to specify each triangle's
209 // position.
210
211 const indices = [
212 0, 1, 2, 0, 2, 3, // front
213 4, 5, 6, 4, 6, 7, // back
214 8, 9, 10, 8, 10, 11, // top
215 12, 13, 14, 12, 14, 15, // bottom
216 16, 17, 18, 16, 18, 19, // right
217 20, 21, 22, 20, 22, 23, // left
218 ];
219
220 // Now send the element array to GL
221
222 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
223 new Uint16Array(indices), gl.STATIC_DRAW);
224
225 return {
226 position: positionBuffer,
227 textureCoord: textureCoordBuffer,
228 indices: indexBuffer,
229 };
230 }
231
232 //
233 // Initialize a texture and load an image.
234 // When the image finished loading copy it into the texture.
235 //
236 function loadTexture(gl, url) {
237 const texture = gl.createTexture();
238 gl.bindTexture(gl.TEXTURE_2D, texture);
239
240 // Because images have to be download over the internet
241 // they might take a moment until they are ready.
242 // Until then put a single pixel in the texture so we can
243 // use it immediately. When the image has finished downloading
244 // we'll update the texture with the contents of the image.
245 const level = 0;
246 const internalFormat = gl.RGBA;
247 const width = 1;
248 const height = 1;
249 const border = 0;
250 const srcFormat = gl.RGBA;
251 const srcType = gl.UNSIGNED_BYTE;
252 const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
253 gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
254 width, height, border, srcFormat, srcType,
255 pixel);
256
257 const image = new Image();
258 image.onload = function() {
259 gl.bindTexture(gl.TEXTURE_2D, texture);
260 gl.texImage2D(gl.TEXTURE_2D, level, internalFormat,
261 srcFormat, srcType, image);
262
263 // WebGL1 has different requirements for power of 2 images
264 // vs non power of 2 images so check if the image is a
265 // power of 2 in both dimensions.
266 if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
267 // Yes, it's a power of 2. Generate mips.
268 gl.generateMipmap(gl.TEXTURE_2D);
269 } else {
270 // No, it's not a power of 2. Turn of mips and set
271 // wrapping to clamp to edge
272 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
273 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
274 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
275 }
276 };
277 image.src = url;
278
279 return texture;
280 }
281
282 function isPowerOf2(value) {
283 return (value & (value - 1)) == 0;
284 }
285
286 //
287 // Draw the scene.
288 //
289 function drawScene(gl, programInfo, buffers, texture, deltaTime) {
290 gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
291 gl.clearDepth(1.0); // Clear everything
292 gl.enable(gl.DEPTH_TEST); // Enable depth testing
293 gl.depthFunc(gl.LEQUAL); // Near things obscure far things
294
295 // Clear the canvas before we start drawing on it.
296
297 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
298
299 // Create a perspective matrix, a special matrix that is
300 // used to simulate the distortion of perspective in a camera.
301 // Our field of view is 45 degrees, with a width/height
302 // ratio that matches the display size of the canvas
303 // and we only want to see objects between 0.1 units
304 // and 100 units away from the camera.
305
306 const fieldOfView = 45 * Math.PI / 180; // in radians
307 const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
308 const zNear = 0.1;
309 const zFar = 100.0;
310 const projectionMatrix = mat4.create();
311
312 // note: glmatrix.js always has the first argument
313 // as the destination to receive the result.
314 mat4.perspective(projectionMatrix,
315 fieldOfView,
316 aspect,
317 zNear,
318 zFar);
319
320 // Set the drawing position to the "identity" point, which is
321 // the center of the scene.
322 const modelViewMatrix = mat4.create();
323
324 // Now move the drawing position a bit to where we want to
325 // start drawing the square.
326
327 mat4.translate(modelViewMatrix, // destination matrix
328 modelViewMatrix, // matrix to translate
329 [-0.0, 0.0, -6.0]); // amount to translate
330 mat4.rotate(modelViewMatrix, // destination matrix
331 modelViewMatrix, // matrix to rotate
332 cubeRotation, // amount to rotate in radians
333 [0, 0, 1]); // axis to rotate around (Z)
334 mat4.rotate(modelViewMatrix, // destination matrix
335 modelViewMatrix, // matrix to rotate
336 cubeRotation * .7,// amount to rotate in radians
337 [0, 1, 0]); // axis to rotate around (X)
338
339 // Tell WebGL how to pull out the positions from the position
340 // buffer into the vertexPosition attribute
341 {
342 const numComponents = 3;
343 const type = gl.FLOAT;
344 const normalize = false;
345 const stride = 0;
346 const offset = 0;
347 gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
348 gl.vertexAttribPointer(
349 programInfo.attribLocations.vertexPosition,
350 numComponents,
351 type,
352 normalize,
353 stride,
354 offset);
355 gl.enableVertexAttribArray(
356 programInfo.attribLocations.vertexPosition);
357 }
358
359 // Tell WebGL how to pull out the texture coordinates from
360 // the texture coordinate buffer into the textureCoord attribute.
361 {
362 const numComponents = 2;
363 const type = gl.FLOAT;
364 const normalize = false;
365 const stride = 0;
366 const offset = 0;
367 gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
368 gl.vertexAttribPointer(
369 programInfo.attribLocations.textureCoord,
370 numComponents,
371 type,
372 normalize,
373 stride,
374 offset);
375 gl.enableVertexAttribArray(
376 programInfo.attribLocations.textureCoord);
377 }
378
379 // Tell WebGL which indices to use to index the vertices
380 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
381
382 // Tell WebGL to use our program when drawing
383
384 gl.useProgram(programInfo.program);
385
386 // Set the shader uniforms
387
388 gl.uniformMatrix4fv(
389 programInfo.uniformLocations.projectionMatrix,
390 false,
391 projectionMatrix);
392 gl.uniformMatrix4fv(
393 programInfo.uniformLocations.modelViewMatrix,
394 false,
395 modelViewMatrix);
396
397 // Specify the texture to map onto the faces.
398
399 // Tell WebGL we want to affect texture unit 0
400 gl.activeTexture(gl.TEXTURE0);
401
402 // Bind the texture to texture unit 0
403 gl.bindTexture(gl.TEXTURE_2D, texture);
404
405 // Tell the shader we bound the texture to texture unit 0
406 gl.uniform1i(programInfo.uniformLocations.uSampler, 0);
407
408 {
409 const vertexCount = 36;
410 const type = gl.UNSIGNED_SHORT;
411 const offset = 0;
412 gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
413 }
414
415 // Update the rotation for the next draw
416
417 cubeRotation += deltaTime;
418 }
419
420 //
421 // Initialize a shader program, so WebGL knows how to draw our data
422 //
423 function initShaderProgram(gl, vsSource, fsSource) {
424 const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
425 const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
426
427 // Create the shader program
428
429 const shaderProgram = gl.createProgram();
430 gl.attachShader(shaderProgram, vertexShader);
431 gl.attachShader(shaderProgram, fragmentShader);
432 gl.linkProgram(shaderProgram);
433
434 // If creating the shader program failed, alert
435
436 if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
437 alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram));
438 return null;
439 }
440
441 return shaderProgram;
442 }
443
444 //
445 // creates a shader of the given type, uploads the source and
446 // compiles it.
447 //
448 function loadShader(gl, type, source) {
449 const shader = gl.createShader(type);
450
451 // Send the source to the shader object
452
453 gl.shaderSource(shader, source);
454
455 // Compile the shader program
456
457 gl.compileShader(shader);
458
459 // See if it compiled successfully
460
461 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
462 alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader));
463 gl.deleteShader(shader);
464 return null;
465 }
466
467 return shader;
468 }
469 </script>