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 = $(""); $("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 = $("
" + msg + "
"); $("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 = $("
" + msg + "
"); $("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; };