commit
message
Improved comments, added WebGL detection.
author
ben <[email protected]>
date
2014-01-04 02:36:13
stats
4 file(s) changed,
168 insertions(+),
100 deletions(-)
files
index.html
js/hexagon.js
js/main.js
js/vendor/Detector.js
1diff --git a/index.html b/index.html
2index b30baf0..4642cfc 100644
3--- a/index.html
4+++ b/index.html
5@@ -123,7 +123,8 @@
6 </div>
7
8
9- <script src="js/vendor/three.min.js"></script>
10+ <script src="js/vendor/three.min.js"></script>
11+ <script src="js/vendor/Detector.js"></script>
12 <script src="js/vendor/stats.min.js"></script>
13 <script src="js/vendor/jquery.min.js"></script>
14 <script src="js/vendor/moment.min.js"></script>
15diff --git a/js/hexagon.js b/js/hexagon.js
16index 2559290..38f8f5c 100644
17--- a/js/hexagon.js
18+++ b/js/hexagon.js
19@@ -43,14 +43,11 @@ function newHexagon(size, thickness) {
20 object.faces.push( new THREE.Face3( 7, 4, 8) );
21
22 object.computeFaceNormals();
23- // object.computeVertexNormals();
24- // object.computeBoundingSphere();
25
26 return object;
27 }
28
29
30-
31 function newFloorHexagon(size, thickness) {
32 var object = new THREE.Geometry();
33
34@@ -69,30 +66,7 @@ function newFloorHexagon(size, thickness) {
35 object.faces.push( new THREE.Face3( 1, 4, 5) );
36 object.faces.push( new THREE.Face3( 2, 3, 4) );
37
38- // object.faces.push( new THREE.Face3( 10, 1, 0) );
39- // object.faces.push( new THREE.Face3( 0, 11, 10) );
40- //
41- // object.faces.push( new THREE.Face3( 5, 6, 0) );
42- // object.faces.push( new THREE.Face3( 6, 11, 0) );
43- //
44- // object.faces.push( new THREE.Face3( 2, 1, 10) );
45- // object.faces.push( new THREE.Face3( 10, 9, 2) );
46- //
47- // object.faces.push( new THREE.Face3( 3, 2, 9) );
48- // object.faces.push( new THREE.Face3( 9, 8, 3) );
49- //
50- // object.faces.push( new THREE.Face3( 5, 4, 7) );
51- // object.faces.push( new THREE.Face3( 7, 6, 5) );
52- //
53- // object.faces.push( new THREE.Face3( 4, 3, 7) );
54- // object.faces.push( new THREE.Face3( 3, 8, 7) );
55- //
56- // object.faces.push( new THREE.Face3( 8, 4, 3) );
57- // object.faces.push( new THREE.Face3( 7, 4, 8) );
58- //
59 object.computeFaceNormals();
60- // object.computeVertexNormals();
61- // object.computeBoundingSphere();
62-
63+
64 return object;
65 }
66diff --git a/js/main.js b/js/main.js
67index b9b69c6..266c02a 100644
68--- a/js/main.js
69+++ b/js/main.js
70@@ -1,30 +1,26 @@
71+//Scene variables
72 var camera, scene, renderer;
73 var mesh, light;
74 var dirLight, hemiLight;
75 var controls;
76-var cross;
77+var delta;
78 var projector, raycaster, intersects;
79-
80-var radius = 6371;
81-var tilt = 0.41;
82-var rotationSpeed = 0.6;
83-
84 var mouse = new THREE.Vector2(), INTERSECTED;
85 var clock = new THREE.Clock();
86
87-//HEXAGON CONSTANTS
88+//Hexagon constants
89 var SIZE = 12;
90 var THICKNESS = 5;
91 var HEIGHT = SIZE*2;
92 var WIDTH = (Math.sqrt(3)/2) * HEIGHT;
93
94-//BOARD CONTSTANTS
95+//Board Constants
96 var xCount = 40;
97 var yCount = 40;
98 var zCount = 40;
99 var board;
100
101-//TOOLS
102+//Tools
103 var TOOLS = {
104 add: 0,
105 remove: 1
106@@ -34,15 +30,17 @@ var currentHexagonPosition = {x:0, y:0, z:0};
107 var phantomHexagon;
108 var hexcount = 0;
109 var currentGame;
110+
111+//Game element to stamp out in the DOM
112 var gameElement = $('.modal-body.list').html();
113
114-//COLORS
115+//Colors
116 var COLORS = [0xFFFFFF, 0xFAFAFA, 0xF6F6F6, 0xF1F1F1, 0xEDEDED, 0xE8E8E8];
117 var currentColor = 0xE32818;
118 var sky = 0xBFE6FF;
119 var ground = 0x333333;
120
121-
122+//Set the draw div to be the height of the window
123 $('#draw').css('height', window.innerWidth - $('.nav').height());
124
125 init();
126@@ -50,6 +48,7 @@ hud();
127 animate();
128 firstLoad();
129
130+//Places the heads up display
131 function hud() {
132 var hud = $('.hud');
133 hud.css('left', ((window.innerWidth/2) - (hud.width()/2)));
134@@ -58,9 +57,11 @@ function hud() {
135 }
136
137 function firstLoad() {
138+ //If this is a first time user, trigger the welcome modal.
139 if (localStorage.hex == undefined) {
140 $('#welcomeModal').modal('toggle');
141 }
142+ //Find which game we'll be saving to
143 for (var i = 1; i < 30; i++) {
144 var name = 'game' + i;
145 if (!localStorage.hasOwnProperty(name)) {
146@@ -71,33 +72,37 @@ function firstLoad() {
147 }
148
149 function init() {
150+ //WebGL detection and redirection
151+ if (!Detector.webgl) {
152+ window.location = "http://get.webgl.org";
153+ }
154
155- //CAMERA
156- camera = new THREE.PerspectiveCamera( 39, window.innerWidth / window.innerHeight, 1, 2000 );
157+ //Camera initialization
158+ camera = new THREE.PerspectiveCamera( 39, window.innerWidth / window.innerHeight, 1, 2000 );
159 camera.eulerOrder = "YXZ"
160- camera.position.z = 200;
161+ camera.position.z = 200;
162 camera.position.y = 40;
163 camera.position.x = 100;
164 camera.lookAt(getHexagonPositionFromLocation(Math.floor(xCount/2), 0, Math.floor(zCount/2)));
165-
166- //CONTROLS
167- controls = new THREE.FlyControls( camera );
168+
169+ //Controls
170+ controls = new THREE.FlyControls(camera);
171 controls.movementSpeed = 70;
172- controls.domElement = draw;
173- controls.rollSpeed = Math.PI / 7;
174- controls.autoForward = false;
175- controls.dragToLook = false;
176+ controls.domElement = draw;
177+ controls.rollSpeed = Math.PI / 7;
178+ controls.autoForward = false;
179+ controls.dragToLook = false;
180
181- //SCENE
182- scene = new THREE.Scene();
183+ //Scene
184+ scene = new THREE.Scene();
185 scene.fog = new THREE.Fog(0xffffff, 500, 1200);
186
187- //LIGHTS
188+ //Lights
189 hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
190- hemiLight.color.setHSL( 0.6, 1, 0.6 );
191- hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
192- hemiLight.position.set( 0, 500, 0 );
193- scene.add( hemiLight );
194+ hemiLight.color.setHSL( 0.6, 1, 0.6 );
195+ hemiLight.groundColor.setHSL( 0.095, 1, 0.75 );
196+ hemiLight.position.set( 0, 500, 0 );
197+ scene.add( hemiLight );
198 dirLight = new THREE.DirectionalLight( 0xffffff, 1 );
199 dirLight.color.setHSL( 0.1, 1, 0.95 );
200 dirLight.position.set( -1, 1.75, 1 );
201@@ -116,19 +121,18 @@ function init() {
202 dirLight.shadowDarkness = 0.35;
203
204
205- // GROUND
206- var ground = new THREE.Mesh(new THREE.PlaneGeometry(50000, 50000),
207- new THREE.MeshPhongMaterial({ambient: ground, color: ground, specular: ground}) );
208+ //Ground
209+ var ground = new THREE.Mesh(new THREE.PlaneGeometry(50000, 50000), new THREE.MeshPhongMaterial({ambient: ground, color: ground, specular: ground}) );
210 ground.name = 'ground';
211 ground.rotation.x = -Math.PI/2;
212- ground.position.y = 0;
213- scene.add( ground );
214- ground.receiveShadow = true;
215+ ground.position.y = 0;
216+ scene.add( ground );
217+ ground.receiveShadow = true;
218
219- //BOARD
220+ //Board to store hexagon colors for loading, saving
221 board = new Board(xCount, zCount, yCount);
222-
223- //INITIALIZING HEXAGONS
224+
225+ //Initializing floor hexagons
226 for (var x = 0; x < board.width; x++) {
227 for (var z = 0; z < board.depth; z++) {
228 var hexagon = newFloorHexagon(SIZE, THICKNESS);
229@@ -144,38 +148,42 @@ function init() {
230 }
231 }
232
233- //SELECTOR HEXAGON
234+ //Phantom hexagon to act as selector for adding and removing.
235 var hexagon = newHexagon(SIZE, THICKNESS);
236 phantomHexagon = new THREE.Mesh(hexagon, new THREE.MeshNormalMaterial( { color: currentColor, emissive: currentColor, ambient: currentColor, transparent: true, opacity: 0 } ));
237 scene.add(phantomHexagon);
238 phantomHexagon.name = 'phantomHexagon';
239
240- //MOUSE INTERACTION
241+ //Projector and raycaster for instersection with mouse location
242 projector = new THREE.Projector();
243 raycaster = new THREE.Raycaster();
244
245- //EVENT HANDLING
246+ //Bind events
247 bindEvents();
248
249- //RENDERING
250+ //Engage the rendered
251 renderer = new THREE.WebGLRenderer( { antialias: false } );
252- renderer.setSize( window.innerWidth, window.innerHeight );
253- draw.appendChild( renderer.domElement );
254+ renderer.setSize( window.innerWidth, window.innerHeight );
255+ draw.appendChild( renderer.domElement );
256 renderer.setClearColor( sky, 1 );
257 renderer.gammaInput = true;
258 renderer.gammaOutput = true;
259 renderer.physicallyBasedShading = true;
260 renderer.shadowMapEnabled = false;
261- renderer.shadowMapCullFace = THREE.CullFaceBack;
262- document.body.appendChild( renderer.domElement );
263+ renderer.shadowMapCullFace = THREE.CullFaceBack;
264+ document.body.appendChild( renderer.domElement );
265 }
266
267+//Binding common mouse events
268 function bindEvents() {
269- window.addEventListener('resize', onWindowResize, false);
270+ //Handle apsect ratios when the user resizes
271+ window.addEventListener('resize', onWindowResize, false);
272+ //Change location of phantom hexagon on mouse move
273 $('#draw').on('mousemove', onDocumentMouseMove);
274+ //Handle mouse clicks
275 $('#draw').on('click', onDocumentMouseClick);
276
277- //ADD HEXAGON BUTTON
278+ //Select 'add hexagon' tool
279 $('.button.add').on('click', function(e) {
280 //remove is not active
281 var button = $('.button.remove');
282@@ -192,7 +200,7 @@ function bindEvents() {
283 currentTool = TOOLS.add;
284 });
285
286- //REMOVE HEXAGON BUTTON
287+ //Select 'remove hexagon' tool
288 $('.button.remove').on('click', function(e) {
289 //add is not active
290 var button = $('.button.add');
291@@ -209,14 +217,14 @@ function bindEvents() {
292 currentTool = TOOLS.remove;
293 });
294
295- //SAVE SCENE
296+ //Save the current scene to local storage
297 $('.button.save').on('click', function(e) {
298 localStorage.hex = true;
299 var game = {tiles: board.getActiveTiles(), date: moment().format('MMMM Do YYYY, h:mm a')};
300 localStorage[currentGame] = JSON.stringify(game);
301 });
302
303- //LOAD SCENE
304+ //Trigger the load modal, and populated it with saved games
305 $('.button.load').on('click', function(e) {
306 $('.modal-body.list').empty();
307 for (var i = 1; i < 30; i++) {
308@@ -240,7 +248,7 @@ function bindEvents() {
309 $('#loadModal').modal('toggle');
310 });
311
312- //NEW SCENE
313+ //Wipe the current game, start a new localStorage game
314 $('.button.new').on('click', function(e) {
315 clearScene();
316 resetScene();
317@@ -253,11 +261,12 @@ function bindEvents() {
318 }
319 });
320
321- //INFO
322+ //Show welcome modal for more information
323 $('.button.info').on('click', function(e) {
324 $('#welcomeModal').modal('show');
325 });
326
327+ //Load demo game
328 $('.demo').on('click', function(e) {
329 $('#welcomeModal').modal('hide');
330 clearScene();
331@@ -265,7 +274,7 @@ function bindEvents() {
332 loadGame(demos[event.target.id].tiles);
333 });
334
335- //ZOOM CONTROLS
336+ //Bind mouse wheel for zoom/perspective control
337 $("#draw").bind('mousewheel', function (e) {
338 if(e.originalEvent.wheelDelta /120 > 0) {
339 if (camera.fov < 60)
340@@ -277,7 +286,7 @@ function bindEvents() {
341 }
342 });
343
344- //Key binding
345+ //Binding the enter key to add a hexagon
346 $(document).on('keypress', function (event) {
347 if (event.keyCode == 13) {
348 switch (currentTool) {
349@@ -291,7 +300,7 @@ function bindEvents() {
350 }
351 });
352
353- //Color picker
354+ //Binding the collor picker
355 $('.picker').colorpicker({color: '#0066cc'})
356 .on('changeColor', function(ev) {
357 currentColor = parseInt(ev.color.toHex().replace('#', '0x'));
358@@ -306,13 +315,17 @@ function bindEvents() {
359 });
360 }
361
362+//Handling mouse moves
363 function onDocumentMouseMove( event ) {
364+ //When the mouse is over the game, and not the color picker, hide color picker
365 $('.picker').colorpicker('hide');
366- event.preventDefault();
367- mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
368- mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
369+ event.preventDefault();
370+ //Capture mouse location
371+ mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
372+ mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
373 }
374
375+//Routing mouse click events based on tool
376 function onDocumentMouseClick() {
377 switch (currentTool) {
378 case TOOLS.remove:
379@@ -324,6 +337,7 @@ function onDocumentMouseClick() {
380 }
381 }
382
383+//Reset the 'floor' hexagons for a new scene
384 function resetScene() {
385 for (var x = 0; x < board.width; x++) {
386 for (var z = 0; z < board.depth; z++) {
387@@ -341,11 +355,12 @@ function resetScene() {
388 }
389 }
390
391+//Load a saved game
392 function loadGame(tiles) {
393 clearScene();
394 resetScene();
395
396-
397+ //Add the hexagons one by one
398 for (var i = 0; i < tiles.length; i++) {
399 var hexagon = newHexagon(SIZE, THICKNESS);
400 var mesh = new THREE.Mesh(hexagon, new THREE.MeshLambertMaterial(
401@@ -362,6 +377,7 @@ function loadGame(tiles) {
402 }
403 }
404
405+//Clears an entire scene, including the floor.
406 function clearScene() {
407 board = new Board(xCount, zCount, yCount);
408 var removeList = [];
409@@ -376,11 +392,13 @@ function clearScene() {
410 updateHexcount(0);
411 }
412
413+//Push the hexagon count to the HUD
414 function updateHexcount(number) {
415 hexcount = number;
416 $('.hexcount').text(hexcount + ' hexagons');
417 }
418
419+//Remove the selected hexagon
420 function removeHexagon() {
421 if ((INTERSECTED.name != 'ground' && INTERSECTED.name != 'floor') && intersects[1].object.name !== 'phantomHexagon') {
422 scene.remove(intersects[1].object);
423@@ -391,6 +409,7 @@ function removeHexagon() {
424 }
425 }
426
427+//Add a hexagon at the appropriate location
428 function addHexagon() {
429 if (INTERSECTED.name != 'ground') {
430 var hexagon = newHexagon(SIZE, THICKNESS);
431@@ -409,7 +428,7 @@ function addHexagon() {
432 }
433 }
434
435-//SELECTOR - selects hexagons
436+//Places the phantomHexagon at the appropriate location, and keeps track of the foremost intersected hexagon
437 function selector() {
438 var mouseVector = new THREE.Vector3(mouse.x, mouse.y, 1);
439 projector.unprojectVector(mouseVector, camera);
440@@ -441,12 +460,14 @@ function selector() {
441 }
442 }
443
444+//Set the phantomHexagons board location
445 function setPhantomPosition(x, y, z) {
446 phantomHexagon.position.x = x;
447 phantomHexagon.position.y = y;
448 phantomHexagon.position.z = z;
449 }
450
451+//Get a hexagons real-world position based upon its board location
452 function getHexagonPositionFromLocation(x, y, z) {
453 var position = new THREE.Vector3();
454 if (z % 2 == 0) {
455@@ -460,6 +481,7 @@ function getHexagonPositionFromLocation(x, y, z) {
456 return position;
457 }
458
459+//Ensures the user doesn't fly the camera below the board, or too far in any direction.
460 function checkCameraBoundries() {
461 // //Y Boundries.
462 if (camera.position.y < 10) {
463@@ -487,21 +509,24 @@ function checkCameraBoundries() {
464 }
465 }
466
467+//When the user resizes the window, we handle the camera's aspect ratio
468 function onWindowResize() {
469- camera.aspect = window.innerWidth / window.innerHeight;
470- camera.updateProjectionMatrix();
471- renderer.setSize( window.innerWidth, window.innerHeight );
472+ camera.aspect = window.innerWidth / window.innerHeight;
473+ camera.updateProjectionMatrix();
474+ renderer.setSize( window.innerWidth, window.innerHeight );
475 }
476
477+//Perform selector update, control update, camera boundry checks, and render
478 function animate() {
479 selector();
480- requestAnimationFrame( animate );
481+ delta = clock.getDelta();
482+ controls.update(delta);
483+ checkCameraBoundries();
484+ requestAnimationFrame(animate);
485 render();
486 }
487
488+//Render
489 function render() {
490- var delta = clock.getDelta();
491- controls.update( delta );
492- checkCameraBoundries();
493- renderer.render( scene, camera );
494+ renderer.render(scene, camera);
495 }
496\ No newline at end of file
497diff --git a/js/vendor/Detector.js b/js/vendor/Detector.js
498new file mode 100644
499index 0000000..02e49e0
500--- /dev/null
501+++ b/js/vendor/Detector.js
502@@ -0,0 +1,59 @@
503+/**
504+ * @author alteredq / http://alteredqualia.com/
505+ * @author mr.doob / http://mrdoob.com/
506+ */
507+
508+var Detector = {
509+
510+ canvas: !! window.CanvasRenderingContext2D,
511+ webgl: ( function () { try { var canvas = document.createElement( 'canvas' ); return !! window.WebGLRenderingContext && ( canvas.getContext( 'webgl' ) || canvas.getContext( 'experimental-webgl' ) ); } catch( e ) { return false; } } )(),
512+ workers: !! window.Worker,
513+ fileapi: window.File && window.FileReader && window.FileList && window.Blob,
514+
515+ getWebGLErrorMessage: function () {
516+
517+ var element = document.createElement( 'div' );
518+ element.id = 'webgl-error-message';
519+ element.style.fontFamily = 'monospace';
520+ element.style.fontSize = '13px';
521+ element.style.fontWeight = 'normal';
522+ element.style.textAlign = 'center';
523+ element.style.background = '#fff';
524+ element.style.color = '#000';
525+ element.style.padding = '1.5em';
526+ element.style.width = '400px';
527+ element.style.margin = '5em auto 0';
528+
529+ if ( ! this.webgl ) {
530+
531+ element.innerHTML = window.WebGLRenderingContext ? [
532+ 'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br />',
533+ 'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
534+ ].join( '\n' ) : [
535+ 'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000">WebGL</a>.<br/>',
536+ 'Find out how to get it <a href="http://get.webgl.org/" style="color:#000">here</a>.'
537+ ].join( '\n' );
538+
539+ }
540+
541+ return element;
542+
543+ },
544+
545+ addGetWebGLMessage: function ( parameters ) {
546+
547+ var parent, id, element;
548+
549+ parameters = parameters || {};
550+
551+ parent = parameters.parent !== undefined ? parameters.parent : document.body;
552+ id = parameters.id !== undefined ? parameters.id : 'oldie';
553+
554+ element = Detector.getWebGLErrorMessage();
555+ element.id = id;
556+
557+ parent.appendChild( element );
558+
559+ }
560+
561+};
562\ No newline at end of file