use std::sync::{Arc, Mutex, mpsc};
use piston_window::PistonWindow;
use piston::input::{UpdateArgs, RenderArgs};
use slog::Logger;
use gfx;
use gfx_device_gl;
use camera_controllers;
use specs;
use render;
use render::{Visual, Mesh, MeshRepository};
use types::*;
use input_adapter::InputAdapter;
fn get_projection(w: &PistonWindow) -> [[f32; 4]; 4] {
use piston::window::Window;
use camera_controllers::CameraPerspective;
let draw_size = w.window.draw_size();
CameraPerspective {
fov: 90.0,
near_clip: 0.01,
far_clip: 100.0,
aspect_ratio: (draw_size.width as f32) / (draw_size.height as f32),
}.projection()
}
pub struct App {
t: TimeDelta,
log: Logger,
world: specs::World,
dispatcher: specs::Dispatcher<'static, 'static>,
encoder_channel: render::EncoderChannel<gfx_device_gl::Resources, gfx_device_gl::CommandBuffer>,
input_adapters: Vec<Box<InputAdapter>>,
projection: Arc<Mutex<[[f32; 4]; 4]>>,
first_person: Arc<Mutex<camera_controllers::FirstPerson>>,
factory: gfx_device_gl::Factory,
output_color: gfx::handle::RenderTargetView<
gfx_device_gl::Resources,
(gfx::format::R8_G8_B8_A8, gfx::format::Srgb),
>,
output_stencil: gfx::handle::DepthStencilView<
gfx_device_gl::Resources,
(gfx::format::D24_S8, gfx::format::Unorm),
>,
mesh_repo: Arc<Mutex<MeshRepository<gfx_device_gl::Resources>>>,
window: PistonWindow,
}
impl App {
pub fn new(
parent_log: &Logger,
mut window: PistonWindow,
mut world: specs::World,
dispatcher_builder: specs::DispatcherBuilder<'static, 'static>,
) -> App {
use camera_controllers::{FirstPersonSettings, FirstPerson};
let (render_sys_send, device_recv) = mpsc::channel();
let (device_send, render_sys_recv) = mpsc::channel();
let render_sys_encoder_channel = render::EncoderChannel {
sender: render_sys_send,
receiver: render_sys_recv,
};
let device_encoder_channel = render::EncoderChannel {
sender: device_send,
receiver: device_recv,
};
let enc1 = window.factory.create_command_buffer().into();
let enc2 = window.factory.create_command_buffer().into();
render_sys_encoder_channel.sender.send(enc1).unwrap();
device_encoder_channel.sender.send(enc2).unwrap();
let log = parent_log.new(o!());
let projection = Arc::new(Mutex::new(get_projection(&window)));
let first_person = FirstPerson::new([0.5, 0.5, 4.0], FirstPersonSettings::keyboard_wasd());
let first_person_mutex_arc = Arc::new(Mutex::new(first_person));
let mesh_repo = MeshRepository::new(
window.output_color.clone(),
window.output_stencil.clone(),
&log,
);
let factory = &mut window.factory.clone();
let mesh_repo_ptr = Arc::new(Mutex::new(mesh_repo));
let render_sys = render::System::new(
&mut world,
factory,
render_sys_encoder_channel,
window.output_color.clone(),
window.output_stencil.clone(),
projection.clone(),
&log,
mesh_repo_ptr.clone(),
);
let dispatcher_builder = dispatcher_builder
.add_barrier()
.add(render_sys, "render", &[]);
App {
t: 0.0,
log: log,
world: world,
dispatcher: dispatcher_builder.build(),
encoder_channel: device_encoder_channel,
input_adapters: Vec::new(),
projection: projection,
first_person: first_person_mutex_arc,
factory: factory.clone(),
output_color: window.output_color.clone(),
output_stencil: window.output_stencil.clone(),
mesh_repo: mesh_repo_ptr,
window: window,
}
}
pub fn run(&mut self) {
use piston::input::*;
info!(self.log, "Starting event loop");
let mut events = self.window.events;
while let Some(e) = events.next(&mut self.window) {
self.first_person.lock().unwrap().event(&e);
if let Some(r) = e.render_args() {
self.render(&r);
}
if e.resize_args().is_some() {
let mut projection = self.projection.lock().unwrap();
*projection = get_projection(&self.window);
}
if let Some(u) = e.update_args() {
self.update(&u);
}
if let Event::Input(input) = e {
for adapter in &self.input_adapters {
adapter.handle(&input);
}
}
}
info!(self.log, "Quitting");
}
fn render(&mut self, _args: &RenderArgs) {
use std::sync::mpsc::TryRecvError;
let mut encoder = match self.encoder_channel.receiver.try_recv() {
Ok(encoder) => encoder,
Err(TryRecvError::Empty) => return,
Err(TryRecvError::Disconnected) => {
panic!("Render system hung up. That wasn't supposed to happen!")
}
};
use piston::window::OpenGLWindow;
self.window.window.make_current();
encoder.flush(&mut self.window.device);
self.encoder_channel.sender.send(encoder).unwrap();
}
fn update(&mut self, args: &UpdateArgs) {
self.t += args.dt;
self.world.write_resource::<TimeDeltaResource>().0 = args.dt;
self.dispatcher.dispatch(&mut self.world.res);
self.world.maintain();
self.realize_proto_meshes();
}
fn realize_proto_meshes(&mut self) {
let mut mesh_repo = self.mesh_repo.lock().unwrap();
let mut visuals = self.world.write::<Visual>();
use specs::Join;
for visual in (&mut visuals).join() {
let needs_to_be_realized = visual.proto_mesh.is_some();
if !needs_to_be_realized {
continue;
}
let proto_mesh = visual.proto_mesh.clone().expect(
"Just ensured this above...",
);
let mesh = Mesh::new(
&mut self.factory,
proto_mesh.vertexes.clone(),
proto_mesh.indexes.clone(),
self.output_color.clone(),
self.output_stencil.clone(),
);
let mesh_pointer = mesh_repo.add_mesh(mesh);
visual.set_mesh_pointer(mesh_pointer);
visual.proto_mesh = None;
}
mesh_repo.collect_garbage();
}
pub fn add_input_adapter(&mut self, adapter: Box<InputAdapter>) {
self.input_adapters.push(adapter);
}
}
impl<'a> App {
pub fn world_mut(&'a mut self) -> &'a mut specs::World {
&mut self.world
}
pub fn world_and_window_mut(&'a mut self) -> (&'a mut specs::World, &'a mut PistonWindow) {
(&mut self.world, &mut self.window)
}
}