Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Port sandbox rendering into client proper

  • Loading branch information...
commit 1b5dc9e450f2f8afc2e59d310a7b0bce151edbf8 1 parent 4b1dfcb
@brendonh authored
View
3  client/index.html
@@ -6,7 +6,7 @@
<body>
- <div id="box">
+ <div id="sector">
Sorry, no canvas support.
</div>
@@ -16,7 +16,6 @@
</p>
<p>FPS: <strong class="fps">??</strong></p>
<p>Faces: <strong class="faces">??</strong></p>
- <p>Renderer: <strong class="renderer">??</strong></p>
</div>
</body>
View
13 client/js/dev/collections/SectorShips.js
@@ -0,0 +1,13 @@
+define([
+ "Backbone",
+ "models/Ship"
+], function(Backbone, Ship) {
+
+ var SectorShips = Backbone.Collection.extend({
+ model: Ship
+
+ });
+
+ return SectorShips;
+
+});
View
156 client/js/dev/index.js
@@ -6,7 +6,8 @@ require.config({
"router": "libs/router",
"Underscore": "libs/underscore-min",
"Backbone": "libs/backbone-min",
- "msgpack": "libs/msgpack"
+ "msgpack": "libs/msgpack",
+ "Three": "libs/Three"
},
"shim": {
"Underscore": {
@@ -16,6 +17,9 @@ require.config({
"Backbone": {
"deps": ["Underscore", "jquery"],
"exports": "Backbone"
+ },
+ "Three": {
+ "exports": "THREE"
}
},
"deps": ["index"],
@@ -25,8 +29,12 @@ require.config({
require([
"jquery",
"Backbone",
- "collections/Servers"
-], function($, Backbone, Servers) {
+ "collections/Servers",
+ "models/Sector",
+ "models/SectorRenderer",
+ "views/SectorRendererView",
+ "models/Ship"
+], function($, Backbone, Servers, Sector, SectorRenderer, SectorRendererView, Ship) {
var initialServer = "ws://dev.brendonh.org:9998/";
@@ -37,45 +45,121 @@ require([
}
servers.ensure(initialServer).done(startLogin);
-});
-function startLogin(server) {
- console.log("Connected!");
-
- var user = getQueryVariable('user');
- var password = getQueryVariable('password');
-
- if (!user || !password) {
- alert("Give user and password in query string");
- return;
+ function startLogin(server) {
+ console.log("Connected!");
+
+ var user = getQueryVariable('user');
+ var password = getQueryVariable('password');
+
+ if (!user || !password) {
+ alert("Give user and password in query string");
+ return;
+ }
+
+ server.callAPI("accounts", "login",
+ {"name": user,
+ "password": password})
+ .done(function(r) { afterLogin(server, r); });
}
-
- server.callAPI("accounts", "login",
- {"name": user,
- "password": password})
- .done(function(r) { afterLogin(server, r); });
-}
-
-function afterLogin(server, response) {
- var shipID = getQueryVariable('ship');
- if (!shipID) {
- server.callAPI("ships" ,"list")
- .done(function(shipResponse) {
- var ships = shipResponse["data"]["ships"];
- for (var i in ships) {
- var ship = ships[i];
- console.log(ship.name, ship.id);
- }
+
+ function afterLogin(server, response) {
+ var shipID = getQueryVariable('ship');
+ if (!shipID) {
+ server.callAPI("ships" ,"list")
+ .done(function(shipResponse) {
+ var ships = shipResponse["data"]["ships"];
+ for (var i in ships) {
+ var ship = ships[i];
+ console.log(ship.name, ship.id);
+ }
+ });
+ return;
+ }
+
+ server.callAPI("ships", "control", {"id": shipID})
+ .done(function() {
+ afterShip(server, shipID);
});
- return;
}
- server.callAPI("ships", "control", {"id": shipID})
- .done(function() {
- console.log("Ready!");
+ function afterShip(server, shipID) {
+ var sector = new Sector();
+
+ var renderer = new SectorRenderer({
+ "sector": sector
});
-}
-
+
+ var view = new SectorRendererView(
+ {"el": $("#sector"),
+ "model": renderer});
+ view.render();
+
+ var ship = new Ship({"id": shipID})
+ sector.get("ships").add(ship);
+
+ var ghost = new Ship({"id": "ghost"})
+ sector.get("ships").add(ghost);
+ ghost.thrust(true);
+ ghost.rotateRight(true);
+
+ window.onkeydown = function(e) {
+ if (e.keyCode == 38) ship.thrust(true);
+ else if (e.keyCode == 39) ship.rotateRight(true);
+ else if (e.keyCode == 37) ship.rotateLeft(true);
+ };
+
+ window.onkeyup = function(e) {
+ if (e.keyCode == 38) ship.thrust(false);
+ else if (e.keyCode == 39) ship.rotateRight(false);
+ else if (e.keyCode == 37) ship.rotateLeft(false);
+ };
+
+ var requestAnimFrame = (function(){
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function( callback ){
+ window.setTimeout(callback, 1000 / 60);
+ };
+ })();
+
+ var frames = 0;
+ var lastInfoTime = new Date().getTime();
+
+ function frame() {
+ sector.tick();
+ view.renderFrame();
+ info();
+ requestAnimFrame(frame);
+ }
+
+ function info() {
+ if (frames++ > 60) {
+ var time = new Date().getTime();
+ var delta = (time - lastInfoTime) / 1000;
+
+ $("#info .fps").html( Math.round((frames / delta)) );
+
+ frames = 0;
+ lastInfoTime = time;
+
+ var faces = 0;
+ sector.get("ships").each(function(ship) {
+ faces += ship.get("mesh").geometry.faces.length;
+ });
+
+ $("#info .faces").html(faces);
+ }
+ }
+
+ frame(frame);
+ }
+
+});
+
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
View
729 client/js/dev/libs/Three.js
729 additions, 0 deletions not shown
View
123 client/js/dev/models/CubeSet.js
@@ -0,0 +1,123 @@
+define([
+ "Three"
+], function(THREE) {
+
+ CubeSet = function(dim) {
+ this.dim = dim || 20;
+ this.cubes = [];
+ };
+
+ CubeSet.prototype.addAscii = function(lines, colors) {
+ var cx, cy;
+ for (var i = 0; i < lines.length; i++) {
+ var line = lines[i];
+ for (var j = 0; j < line.length; j++) {
+ if (line[j] == 'X') {
+ cx = j;
+ cy = i;
+ break;
+ }
+ }
+ }
+
+ for (var i = 0; i < lines.length; i++) {
+ var line = lines[i];
+ for (var j = 0; j < line.length; j++) {
+ if (line[j] == ' ') continue;
+ this.addCube(j - cx, cy - i, 0, colors[line[j]]);
+ }
+ }
+ }
+
+ CubeSet.prototype.addCube = function(x, y, z, color) {
+ this.cubes.push({'x': x, 'y': y, 'z': z, 'color': color});
+ }
+
+ CubeSet.prototype.toMesh = function() {
+ var geom = new THREE.Geometry();
+ geom.materials = [];
+
+ var dim = this.dim, dim_half = this.dim / 2;
+
+ var matsByColor = {};
+
+ var byPos = {};
+ for (var i = 0; i < this.cubes.length; i++) {
+ var cube = this.cubes[i];
+ byPos[[cube.x,cube.y,cube.z]] = true;
+ }
+
+ for (i = 0; i < this.cubes.length; i++) {
+ var cube = this.cubes[i];
+
+ var matIdx = matsByColor[cube.color];
+ if (matIdx === undefined) {
+ var mat = new THREE.MeshLambertMaterial({color: cube.color, overdraw: true });
+ geom.materials.push(mat);
+ matIdx = matsByColor = geom.materials.length - 1;
+ }
+
+ if (!byPos[[cube.x+1, cube.y, cube.z]])
+ this.buildPlane(geom, cube.x, cube.y, cube.z, 'z', 'y', 'x', - 1, - 1, dim, 1, matIdx ); // px
+
+ if (!byPos[[cube.x-1, cube.y, cube.z]])
+ this.buildPlane(geom, cube.x, cube.y, cube.z, 'z', 'y', 'x', 1, - 1, dim, -1, matIdx ); // nx
+
+ if (!byPos[[cube.x, cube.y+1, cube.z]])
+ this.buildPlane(geom, cube.x, cube.y, cube.z, 'x', 'z', 'y', 1, 1, dim, 1, matIdx ); // py
+
+ if (!byPos[[cube.x, cube.y-1, cube.z]])
+ this.buildPlane(geom, cube.x, cube.y, cube.z, 'x', 'z', 'y', 1, - 1, dim, -1, matIdx ); // ny
+
+ if (!byPos[[cube.x, cube.y, cube.z+1]])
+ this.buildPlane(geom, cube.x, cube.y, cube.z, 'x', 'y', 'z', 1, - 1, dim, 1, matIdx ); // pz
+
+ if (!byPos[[cube.x, cube.y, cube.z+-1]])
+ this.buildPlane(geom, cube.x, cube.y, cube.z, 'x', 'y', 'z', - 1, - 1, dim, -1, matIdx ); // nz
+ }
+
+ geom.computeCentroids();
+ geom.mergeVertices();
+
+ var mesh = new THREE.Mesh( geom, new THREE.MeshFaceMaterial() );
+ mesh.useQuaternion = true;
+
+ return mesh;
+ }
+
+ CubeSet.prototype.buildPlane = function(geom, x, y, z, u, v, w, udir, vdir, dim, depth, matIdx ) {
+ var dim_half = dim / 2;
+ var offset = geom.vertices.length;
+
+ for ( iy = 0; iy < 2; iy ++ ) {
+ for ( ix = 0; ix < 2; ix ++ ) {
+ var vector = new THREE.Vector3(dim * x, dim * y, dim * z);
+ vector[ u ] += ( ix * dim - dim_half ) * udir;
+ vector[ v ] += ( iy * dim - dim_half ) * vdir;
+ vector[ w ] += dim_half * depth;
+ geom.vertices.push( vector );
+ }
+ }
+
+ var normal = new THREE.Vector3();
+ normal[ w ] = depth > 0 ? 1 : - 1;
+
+ var face = new THREE.Face4( 0 + offset, 2 + offset, 3 + offset, 1 + offset );
+
+ face.normal.copy( normal );
+ face.vertexNormals.push( normal, normal, normal, normal );
+ face.materialIndex = matIdx;
+
+ geom.faces.push( face );
+ geom.faceVertexUvs[ 0 ].push( [
+ new THREE.UV( 0, 0 ),
+ new THREE.UV( 0, 1 ),
+ new THREE.UV( 1, 1 ),
+ new THREE.UV( 1, 0 )
+ ] );
+
+ }
+
+ return CubeSet;
+
+});
View
24 client/js/dev/models/Sector.js
@@ -0,0 +1,24 @@
+define([
+ "jquery",
+ "Backbone",
+ "Underscore",
+ "collections/SectorShips"
+], function($, Backbone, _, SectorShips) {
+ var Sector = Backbone.Model.extend({
+ idAttribute: "coordString",
+
+ initialize: function() {
+ this.set("ships", new SectorShips());
+ },
+
+ tick: function() {
+ this.get("ships").each(function(ship) {
+ ship.tick();
+ });
+ this.trigger("tick");
+ }
+
+ });
+
+ return Sector;
+});
View
105 client/js/dev/models/SectorRenderer.js
@@ -0,0 +1,105 @@
+define([
+ "Backbone",
+ "Three"
+], function(Backbone, THREE) {
+
+ var SectorRenderer = Backbone.Model.extend({
+
+ defaults: {
+ "width": 800,
+ "height": 600,
+ },
+
+ initialize: function() {
+ var scene = new THREE.Scene();
+
+ var camera = new THREE.PerspectiveCamera( 60, 800 / 600, 1, 2000 );
+ camera.position.z = 1000;
+ scene.add(camera);
+
+ var renderer = new THREE.CanvasRenderer();
+ renderer.setSize(this.get("width"), this.get("height"));
+
+ var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.0 );
+ directionalLight.position.set( 0.5, 0.2, -1 );
+ scene.add(directionalLight);
+
+ this.set({
+ "scene": scene,
+ "camera": camera,
+ "renderer": renderer
+ });
+
+ this.addDust();
+
+ this.get("sector").get("ships").on("add", this.addShip, this);
+
+ this.get("sector").on("tick", this.tick, this);
+
+ },
+
+ addShip: function(ship) {
+ this.get("scene").add( ship.get("mesh") );
+ },
+
+ addDust: function() {
+
+ var particleRender = function(context) {
+ context.beginPath();
+ context.arc( 0, 0, 1, 0, Math.PI * 2, true );
+ context.fill();
+ };
+
+ var count = 200,
+ particles = [],
+ pMaterial =
+ new THREE.ParticleCanvasMaterial( {
+ color: 0xffffff,
+ program: particleRender } );
+
+ var scene = this.get("scene");
+
+ for(var p = 0; p < count; p++) {
+ var particle = new THREE.Particle(pMaterial);
+
+ particle.position.x = -1000 + Math.random() * 2000;
+ particle.position.y = -1000 + Math.random() * 2000;
+ particle.position.z = Math.random() * 500;
+
+ particles.push(particle);
+ scene.add(particle);
+ }
+
+ this.set("dust", particles);
+ },
+
+ tick: function() {
+ var state = this.attributes;
+
+ var watchedShip = this.get("sector").get("ships").at(0).get("mesh");
+
+ state['camera'].position = watchedShip.position.clone();
+ state['camera'].position.z = -700;
+ state['camera'].lookAt(watchedShip.position);
+
+ for (var i = 0; i < state['dust'].length; i++) {
+ var p = state['dust'][i];
+
+ var relX = p.position.x - state['camera'].position.x;
+ var relY = p.position.y - state['camera'].position.y;
+
+ if (relX < -1000) p.position.x += 2000;
+ else if (relX > 1000) p.position.x -= 2000;
+
+ if (relY < -1000) p.position.y += 2000;
+ else if (relY > 1000) p.position.y -= 2000;
+
+ }
+ }
+
+
+ });
+
+ return SectorRenderer;
+
+});
View
84 client/js/dev/models/Ship.js
@@ -0,0 +1,84 @@
+define([
+ "Backbone",
+ "models/CubeSet"
+], function(Backbone, CubeSet) {
+
+ var Ship = Backbone.Model.extend({
+
+ defaults: {
+ "moving": false,
+ "rotateLeft": false,
+ "rotateRight": false,
+
+ "flip": 0,
+ "rotation": 0
+ },
+
+ initialize: function() {
+
+ var colors = {
+ 'X': 0x993333,
+ 'x': 0x999999,
+ 'o': 0x444444
+ };
+
+ var cubes = new CubeSet(10);
+ cubes.addAscii([
+ ' o o ',
+ ' o o ',
+ ' oxo ',
+ ' xxx ',
+ 'xxXxx',
+ 'xxxxx',
+ ' xox '
+ ], colors);
+
+ this.set("cubes", cubes);
+
+ this.set("mesh", cubes.toMesh());
+ },
+
+ thrust: function(onOff) {
+ this.set("moving", onOff);
+ },
+
+ rotateRight: function(onOff) {
+ this.set("rotateRight", onOff);
+ },
+
+ rotateLeft: function(onOff) {
+ this.set("rotateLeft", onOff);
+ },
+
+ tick: function() {
+ var state = this.attributes;
+
+ if (state['rotateLeft']) {
+ state['flip'] -= (state['flip'] + 0.8) * 0.1;
+ state['rotation'] -= 0.05;
+ } else if (state['rotateRight']) {
+ state['flip'] += (0.8 - state['flip']) * 0.1;
+ state['rotation'] += 0.05;
+ } else {
+ state['flip'] *= 0.9;
+ if (Math.abs(state['flip']) < 0.1) state['flip'] = 0;
+ }
+
+ var speed = 10;
+
+ if (state['moving']) {
+ state['mesh'].position.x -= speed * Math.sin(state['rotation']);
+ state['mesh'].position.y += speed * Math.cos(state['rotation']);
+ }
+
+ state['mesh'].quaternion.setFromAxisAngle(
+ new THREE.Vector3(0, 0, 1), state['rotation']);
+ var flip = new THREE.Quaternion();
+ flip.setFromAxisAngle(new THREE.Vector3(0, 1, 0), state['flip']);
+ state['mesh'].quaternion.multiplySelf(flip);
+ }
+ });
+
+ return Ship;
+
+});
View
34 client/js/dev/views/SectorRendererView.js
@@ -0,0 +1,34 @@
+define([
+ "jquery",
+ "Backbone",
+ "Three"
+], function($, Backbone, THREE) {
+
+ var SectorRendererView = Backbone.View.extend({
+
+ initialize: function() {
+ },
+
+ render: function() {
+ var renderer = this.model.get("renderer");
+
+ $(renderer.domElement)
+ .css("height", this.model.get("height") + "px")
+ .css("width", this.model.get("width") + "px")
+ .css("background-color", "black");
+
+ this.$el.empty().append(renderer.domElement);
+ },
+
+ renderFrame: function() {
+ this.model.get('renderer').render(
+ this.model.get('scene'),
+ this.model.get('camera'));
+ }
+
+ });
+
+ return SectorRendererView;
+
+});
+
View
10 client/sandbox/js/sandbox.js
@@ -1,16 +1,6 @@
var state;
function setup() {
- window.requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function( callback ){
- window.setTimeout(callback, 1000 / 60);
- };
- })();
var $container = $('#box');
Please sign in to comment.
Something went wrong with that request. Please try again.