server/ui/js/gorobots_render_webgl.js

609 lines
21 KiB
JavaScript

var gorobots_render_webgl = function(){
var my = {};
var grey = "rgba(0, 0, 0, 0.5)";
var red = "rgba(200, 0, 0, 0.5)";
// Tracking last 50 frame lengths
var d = new Date();
my.delta_history = [];
my.last_frame_time = d.getTime();
my.delta = 0;
my.width = null;
my.height = null;
my.y_base = 16; // The top status bar
my.scene = null;
// Tracking the objects in the scene
my.robots = {};
my.objects = {};
my.dom_id = null;
my.target = null;
my.init = function(dom_id) {
my.dom_id = dom_id;
my.canvas = document.getElementById(dom_id);
$('body').keypress(function(e){
if (my.canvas.clientWidth === 0){
// dont respond to key events when canvas is not in view
return;
}
if(e.which == 118){
// v
my.currentcamera += 1;
if (my.currentcamera >= my.cameras.length) {
my.currentcamera = 0;
}
my.use_camera = my.cameras[my.currentcamera];
}
if (e.which == 45){
// -
if (my.use_camera == my.followcamera){
my.followcamera.fov = my.followcamera.fov - 5;
if (my.followcamera.fov < 5){
my.followcamera.fov = 5;
}
my.followcamera.updateProjectionMatrix();
}
if (my.use_camera == my.trackcamera){
my.track_area -= 10;
if (my.track_area < 50){
my.track_area = 50;
}
my.resize_view();
}
}
if (e.which == 61){
// =
if (my.use_camera == my.followcamera){
my.followcamera.fov = my.followcamera.fov + 5;
if (my.followcamera.fov > 120){
my.followcamera.fov = 120;
}
my.followcamera.updateProjectionMatrix();
}
if (my.use_camera == my.trackcamera){
my.track_area += 10;
if (my.track_area > 1000){
my.track_area = 1000;
}
my.resize_view();
}
}
if (e.which == 100){
// d
$(my.stats.domElement).toggle();
}
});
my.stats = new Stats();
my.stats.setMode(0); // 0: fps, 1: ms
// Align top-left
my.stats.domElement.style.position = 'absolute';
my.stats.domElement.style.left = '5px';
my.stats.domElement.style.top = '200px';
document.body.appendChild( my.stats.domElement );
$(my.stats.domElement).hide();
};
var random_color = function () {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
};
my.setup_cameras = function(){
console.log("Setting up cameras");
my.canvas = document.getElementById(my.dom_id);
my.cameras = [];
var pos = new THREE.Vector3(my.width / 2, my.height / 2, 0);
var game_aspect = my.height / my.width;
var aspect = my.canvas.clientHeight / my.canvas.clientWidth;
var scale = game_aspect/aspect;
if (scale < 1){
var new_scale = (1/game_aspect) / (1/aspect);
var s = (my.height * new_scale) / 2;
my.camera = new THREE.OrthographicCamera( 0, my.width , s + (my.height/2), -(s - (my.height/2)), 0.1, 200 );
} else {
var s = (my.width * scale) / 2;
my.camera = new THREE.OrthographicCamera( -(s - (my.width/2)), s + (my.width/2), my.height, 0, 0.1, 200 );
}
my.camera.position.z = 99;
my.camera.updateProjectionMatrix();
my.cameras.push(my.camera);
var view_aspect = my.canvas.clientHeight / my.canvas.clientWidth;
my.track_area = 300;
my.trackcamera = new THREE.OrthographicCamera( -my.track_area, my.track_area, my.track_area * view_aspect, -my.track_area * view_aspect, -100, 200 );
my.trackcamera.position.z = 100;
my.trackcamera.updateProjectionMatrix();
my.cameras.push(my.trackcamera);
my.followcamera = new THREE.PerspectiveCamera( 35, my.canvas.clientWidth / my.canvas.clientHeight, 1, 10000 );
my.followcamera.position = new THREE.Vector3(my.width / 2, -my.height + (my.height/2), (my.height / 2) + 200);
my.followcamera.up = new THREE.Vector3(0,0,1);
my.followcamera.lookAt(pos);
my.followcamera.updateProjectionMatrix();
my.controls = new THREE.TrackballControls( my.followcamera );
my.cameras.push(my.followcamera);
};
my.setup_render_target = function(map_width, map_height, screen_width, screen_height){
if (my.renderer){
console.log("Renderer already initialized");
my.reset();
return;
}
my.turn = 0;
my.robots = {};
my.objects = {};
my.labels = [];
my.scene = new THREE.Scene();
my.quit = false;
my.width = screen_width;
my.height = screen_height;
my.renderer = new THREE.WebGLRenderer({"canvas": my.canvas, antialias: true });
my.setup_cameras();
my.floorobj = new THREE.CubeGeometry(my.width, my.height, 0.1);
var material = new THREE.MeshLambertMaterial( { color: random_color() } );
my.floor = new THREE.Mesh(my.floorobj, material);
my.floor.position.x = my.width / 2;
my.floor.position.y = my.height / 2 ;
my.floor.position.z = -2;
my.scene.add(my.floor);
// Basic primitives
my.grey_material = new THREE.MeshLambertMaterial( { color: "#999999", transparent: false } );
my.red_material = new THREE.MeshLambertMaterial( { color: "#ff0000", transparent: true } );
my.black_material = new THREE.MeshLambertMaterial( { color: "#000000", transparent: false } );
my.robot_geom = new THREE.CubeGeometry(5,5,5);
var loader = new THREE.OBJLoader();
loader.load( '/ui/obj/robot.obj', function ( object ) {
object.position.x = 100;
object.position.y = 100;
object.position.z = 1;
object.up = new THREE.Vector3(0,0,1);
object.scale.set(5,5,5);
my.robot_geom = object;
} );
my.bullet_geom = new THREE.CubeGeometry(3,3,3);
my.splosion_geom = new THREE.SphereGeometry(1,50,50);
var axis = new THREE.AxisHelper(100);
my.scene.add(axis);
my.wallobjx = new THREE.CubeGeometry(my.width, 3, 3);
my.wallobjy = new THREE.CubeGeometry(3, my.height, 3);
var material = new THREE.MeshLambertMaterial( { color: "#cccccc" } );
my.wall = new THREE.Mesh(my.wallobjx, material);
my.wall.position.x = my.width / 2;
my.scene.add(my.wall);
my.wall2 = new THREE.Mesh(my.wallobjx, material);
my.wall2.position.x = my.width / 2;
my.wall2.position.y = my.height ;
my.scene.add(my.wall2);
my.wall3 = new THREE.Mesh(my.wallobjy, material);
my.wall3.position.y = my.height / 2;
my.scene.add(my.wall3);
my.wall4 = new THREE.Mesh(my.wallobjy, material);
my.wall4.position.y = my.height / 2;
my.wall4.position.x = my.width ;
my.scene.add(my.wall4);
my.scene.add(my.camera);
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.9 );
directionalLight.position.set( 0, 0, -1 );
my.scene.add( directionalLight );
var directionalLight2 = new THREE.DirectionalLight( 0xffffff, 0.9 );
directionalLight2.position.set( 0, 0.707, 0.707 );
my.scene.add( directionalLight2 );
var ambientLight = new THREE.AmbientLight(0x222222, 0.7);
my.scene.add(ambientLight);
my.currentcamera = 2;
my.use_camera = my.cameras[my.currentcamera];
var render = function render() {
my.stats.begin();
my.renderer.render(my.scene, my.use_camera);
my.update_labels();
if (my.controls){
my.controls.update();
}
if (!my.quit)
requestAnimationFrame(render);
my.stats.end();
};
render();
$(window).resize(function(){
my.resize_view();
});
my.resize_view();
};
my.resize_view = function(){
my.canvas.height = ($(window).height() - $(my.canvas).offset().top);
my.canvas.width = $(window).width();
var game_aspect = my.height / my.width;
var aspect = my.canvas.clientHeight / my.canvas.clientWidth;
var scale = game_aspect/aspect;
if (scale < 1){
var new_scale = (1/game_aspect) / (1/aspect);
var s = (my.height * new_scale) / 2;
my.camera.left = 0;
my.camera.right = my.width;
my.camera.top = s + (my.height/2);
my.camera.bottom = -(s - (my.height/2));
} else {
var s = (my.width * scale) / 2;
my.camera.left = -(s - (my.width/2));
my.camera.right = s + (my.width/2);
my.camera.top = my.height;
my.camera.bottom = 0;
}
my.camera.updateProjectionMatrix();
var view_aspect = my.canvas.clientHeight / my.canvas.clientWidth;
my.trackcamera.left = -my.track_area;
my.trackcamera.right = my.track_area;
my.trackcamera.top = my.track_area * view_aspect;
my.trackcamera.bottom = -my.track_area * view_aspect;
my.trackcamera.updateProjectionMatrix();
my.followcamera.aspect = my.canvas.clientWidth / my.canvas.clientHeight;
my.followcamera.updateProjectionMatrix();
my.use_camera = my.cameras[my.currentcamera];
my.renderer.context.viewport(0, 0, my.canvas.width, my.canvas.height);
};
my.begin_frame = function(turn){
my.turn = turn;
var d = new Date();
var time = d.getTime();
my.delta = time - my.last_frame_time;
my.delta_history.unshift(my.delta);
if (my.delta_history.length > 50){
my.delta_history.pop();
}
my.last_frame_time = time;
// Status Bar Text
var slowest = Math.max.apply(null, my.delta_history);
var debug_string = slowest + "ms";
};
my.render = function(draw_list){
var obj_count = 0;
for (var i in draw_list) {
var robot_data = draw_list[i];
var key, geometry, material, cube = null;
if (robot_data['type'] == 'object'){
key = robot_data['type'] + robot_data.bounds[0] + robot_data.bounds[1];
if (!(key in my.objects)){
obj_count++;
console.log(robot_data);
x = robot_data.bounds[0];
y = robot_data.bounds[1];
w = robot_data.bounds[2] - robot_data.bounds[0];
h = robot_data.bounds[3] - robot_data.bounds[1];
geometry = new THREE.CubeGeometry(w,h,5 + Math.round(Math.random() * 25));
var material = new THREE.MeshLambertMaterial( { color: random_color(), transparent: false } );
cube = new THREE.Mesh( geometry, material );
my.scene.add( cube );
cube.position.x = x + (w / 2);
cube.position.y = y + (h / 2);
cube.position.z = 0;
cube.turn = my.turn;
my.objects[key] = cube;
continue;
} else {
my.objects[key].turn = my.turn;
}
}
else{
key = robot_data['type'] + robot_data['id'];
if (!(key in my.robots)){
if (robot_data['type'] == 'bullet'){
material = my.black_material;
geometry = my.bullet_geom;
cube = new THREE.Mesh( geometry, material );
}
else if (robot_data['type'] == 'explosion'){
size = robot_data.radius;
material = my.red_material;
geometry = my.splosion_geom;
material.opacity = 0.8;
cube = new THREE.Mesh( geometry, material );
cube.scale.set(size, size, size);
}
else {
material = new THREE.MeshLambertMaterial( { color: robot_data['color'], transparent: false } );
geometry = my.robot_geom;
cube = geometry.clone();
cube.traverse(function ( geo ) {
geo.material = new THREE.MeshLambertMaterial( { color: robot_data['color'] } );
} );
my.make_bot_label(robot_data.id, robot_data.name, cube);
}
my.robots[key] = cube;
my.scene.add(cube);
cube.position.x = robot_data['position']['x'];
cube.position.y = robot_data['position']['y'];
cube.position.z = -1;
cube.turn = my.turn;
}
else{
my.robots[key].position.x = robot_data['position']['x'];
my.robots[key].position.y = robot_data['position']['y'];
my.robots[key].turn = my.turn;
if ("heading" in robot_data){
if (robot_data['heading']['x'] == 0 && robot_data['heading']['y'] == 0) {
robot_data['heading']['y'] = 1;
}
var tmp = new THREE.Vector3(
robot_data['heading']['x'] + robot_data.position.x,
robot_data['heading']['y'] + robot_data.position.y,
-1);
my.robots[key].up = new THREE.Vector3(0,0,1);
my.robots[key].lookAt( tmp );
}
if (robot_data.health){
var h = Math.round((robot_data.health / 200) * 100) + "%";
var x = "#health_" + robot_data.id;
$(x).css({
"width": h
});
}
}
}
}
// Worth noting this list contains robots, bullets and explosions
// it's badly named, I am sorry!
for (var q in my.robots){
if (my.turn - my.robots[q].turn > 1){
// find and remove label?
for (var w in my.labels){
if (my.labels[w].target == my.robots[q]){
my.labels[w].label.remove();
my.labels.splice(w, 1);
}
}
// Can I do this? I dont think so, we dont know
// if these things will ever be back
// my.robots[q].traverse(function ( geo ) {
// geo.visible = false;
// });
my.scene.remove(my.robots[q]);
delete my.robots[q];
}
}
for (var q in my.objects){
if (my.turn - my.objects[q].turn > 1){
my.objects[q].visible = false;
} else {
my.objects[q].visible = true;
}
}
for (var p in draw_list){
if (draw_list[p]['type'] == "robot"){
if (draw_list[p]['id'] == my.target){
var pos = new THREE.Vector3(draw_list[p].position.x, draw_list[p].position.y, 0);
my.followcamera.lookAt(pos);
my.controls.target = pos;
my.trackcamera.position.x = pos.x;
my.trackcamera.position.y = pos.y;
my.trackcamera.updateProjectionMatrix();
break;
}
}
}
};
var projector = new THREE.Projector();
my.update_labels = function(){
for (var i in my.labels){
var label = my.labels[i];
var screen_pos = label.target.position.clone();
var x = $(my.canvas).position();
if (my.canvas.clientWidth === 0){
$(label.label).css({
display: "none"});
} else {
projector.projectVector( screen_pos, my.use_camera );
if (screen_pos.x > 1 || screen_pos.x < -1 || screen_pos.y > 1 || screen_pos.y < -1){
$(label.label).css({
display: "none"});
continue;
}
var sx = (screen_pos.x * ((my.canvas.clientWidth)/2)) + ((my.canvas.clientWidth)/2) + x.left;
var sy = -(screen_pos.y * ((my.canvas.clientHeight)/2)) + ((my.canvas.clientHeight)/2) + x.top - 30;
$(label.label).css({
position: "absolute",
display:"block",
marginLeft: 0,
marginTop: 0,
top: sy,
left: sx});
}
}
};
my.make_bot_label = function(id, text, track_object){
var obj = $("<div class='label' style='display:none;'>" + text + "<div class='health' id='health_" + id + "'></div></div>");
$("body").append(obj);
my.labels.push({
label: obj,
target: track_object
});
};
my.debug_labels = [];
my.debug_lines = [];
my.clear_debug = function(){
for (var i in my.debug_labels){
my.debug_labels[i].remove();
}
my.debug_labels = [];
for (var i in my.debug_lines){
my.scene.remove(my.debug_lines[i]);
}
delete my.debug_lines;
my.debug_lines = [];
};
my.debug_label = function(x, y, msg){
if (my.canvas.clientWidth > 0){
var screen_pos = new THREE.Vector3(x, y, 0);
var canvas_pos = $(my.canvas).position();
projector.projectVector( screen_pos, my.use_camera );
if (screen_pos.x > 1 || screen_pos.x < -1 || screen_pos.y > 1 || screen_pos.y < -1){
return;
}
var sx = (screen_pos.x * ((my.canvas.clientWidth)/2)) + ((my.canvas.clientWidth)/2) + canvas_pos.left;
var sy = -(screen_pos.y * ((my.canvas.clientHeight)/2)) + ((my.canvas.clientHeight)/2) + canvas_pos.top;
var obj = $("<div class='label'>" + msg + "</div>");
$("body").append(obj);
$(obj).css({
position: "absolute",
marginLeft: 0,
marginTop: 0,
top: sy,
left: sx});
my.debug_labels.push(obj);
}
};
my.debug_label_screen = function(x, y, msg){
if (my.canvas.clientWidth > 0){
var canvas_pos = $(my.canvas).position();
var obj = $("<div class='label'>" + msg + "</div>");
$("body").append(obj);
$(obj).css({
position: "absolute",
marginLeft: 0,
marginTop: 0,
top: y + canvas_pos.top,
left: x + canvas_pos.left});
my.debug_labels.push(obj);
}
};
my.debug_line = function(x1, y1, x2, y2){
var material = new THREE.LineBasicMaterial({
color: 0x0000ff
});
var geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(x1, y1, 0));
geometry.vertices.push(new THREE.Vector3(x2, y2, 0));
var line = new THREE.Line(geometry, material);
my.scene.add(line);
my.debug_lines.push(line);
};
my.set_focus_robot = function(id){
my.target = id;
};
my.reset = function(){
for (var i in my.objects){
my.scene.remove(my.objects[i]);
}
delete my.objects;
my.objects = {};
for (i in my.robots){
my.scene.remove(my.robots[i]);
}
delete my.robots;
my.robots = {};
my.clear_debug();
for (i in my.labels){
my.labels[i].label.remove();
}
my.labels = [];
};
my.end_frame = function(){
};
my.shutdown = function(){
my.reset();
my.quit = true;
};
return my;
};