use std::sync::{Arc, Mutex};
use gfx;
use gfx::Primitive;
use gfx::state::Rasterizer;
use vecmath;
use camera_controllers;
use specs;
use specs::Entities;
use specs::{ReadStorage, Fetch};
use slog::Logger;
use super::default_pipeline::pipe;
use super::mesh::MeshGuts;
use super::EncoderChannel;
use super::Visual;
use super::MeshRepository;
use Spatial;
use camera::DefaultCamera;
pub struct System<R: gfx::Resources, C: gfx::CommandBuffer<R>> {
_log: Logger,
pso: gfx::PipelineState<R, pipe::Meta>,
mesh_repo: Arc<Mutex<MeshRepository<R>>>,
encoder_channel: EncoderChannel<R, C>,
output_color: gfx::handle::RenderTargetView<R, gfx::format::Srgba8>,
output_stencil: gfx::handle::DepthStencilView<R, gfx::format::DepthStencil>,
projection: Arc<Mutex<[[f32; 4]; 4]>>,
}
impl<R: gfx::Resources, C: gfx::CommandBuffer<R>> System<R, C> {
pub fn new<F: gfx::Factory<R>>(
world: &mut specs::World,
factory: &mut F,
encoder_channel: EncoderChannel<R, C>,
output_color: gfx::handle::RenderTargetView<R, gfx::format::Srgba8>,
output_stencil: gfx::handle::DepthStencilView<R, gfx::format::DepthStencil>,
projection: Arc<Mutex<[[f32; 4]; 4]>>,
parent_log: &Logger,
mesh_repo: Arc<Mutex<MeshRepository<R>>>,
) -> System<R, C> {
use auto_resource::AutoResource;
let log = parent_log.new(o!("system" => "render"));
debug!(log, "Initialising");
DefaultCamera::ensure(world);
use gfx::traits::FactoryExt;
let vs_bytes = include_bytes!("../shaders/copypasta_150.glslv");
let ps_bytes = include_bytes!("../shaders/copypasta_150.glslf");
let program = factory.link_program(vs_bytes, ps_bytes).unwrap();
let pso = factory
.create_pipeline_from_program(
&program,
Primitive::TriangleList,
Rasterizer::new_fill().with_cull_back(),
pipe::new(),
)
.unwrap();
System {
pso: pso,
encoder_channel: encoder_channel,
output_color: output_color,
output_stencil: output_stencil,
projection: projection,
_log: log,
mesh_repo: mesh_repo,
}
}
fn draw<'a>(
&mut self,
entities: &specs::Entities<'a>,
visuals: &specs::ReadStorage<'a, Visual>,
spatials: &specs::ReadStorage<'a, Spatial>,
camera: specs::Entity,
) {
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!("Device owner hung up. That wasn't supposed to happen!")
}
};
const CLEAR_COLOR: [f32; 4] = [0.3, 0.3, 0.3, 1.0];
encoder.clear(&self.output_color, CLEAR_COLOR);
encoder.clear_depth(&self.output_stencil, 1.0);
let projection = self.projection.lock().unwrap();
let mut mesh_repo = self.mesh_repo.lock().unwrap();
use specs::Join;
for (entity, visual) in (&**entities, visuals).join() {
use spatial::SpatialStorage;
if !spatials.have_common_ancestor(entity, camera) {
continue;
}
let mesh_pointer = match visual.mesh_pointer() {
Some(mesh_pointer) => mesh_pointer,
None => continue,
};
let camera_relative_transform = spatials.a_relative_to_b(entity, camera);
use na;
use na::{Isometry3, Point3, Vector3};
let model: Isometry3<f32> = na::convert(camera_relative_transform);
let view: Isometry3<f32> = Isometry3::look_at_rh(
&Point3::origin(),
&Point3::from_coordinates(Vector3::z()),
&Vector3::y(),
);
let model_view = view * model;
let model_view_matrix = model_view.to_homogeneous();
let mut model_for_camera_controllers: vecmath::Matrix4<f32> = vecmath::mat4_id();
model_for_camera_controllers[0].copy_from_slice(&model_view_matrix.as_slice()[0..4]);
model_for_camera_controllers[1].copy_from_slice(&model_view_matrix.as_slice()[4..8]);
model_for_camera_controllers[2].copy_from_slice(&model_view_matrix.as_slice()[8..12]);
model_for_camera_controllers[3].copy_from_slice(&model_view_matrix.as_slice()[12..16]);
let model_view_projection = camera_controllers::model_view_projection(
model_for_camera_controllers,
vecmath::mat4_id(),
*projection,
);
let mesh = mesh_repo.get_mut(mesh_pointer);
mesh.data_mut().u_model_view_proj = model_view_projection;
encoder.draw(mesh.slice(), &self.pso, mesh.data());
}
self.encoder_channel.sender.send(encoder).unwrap();
}
}
impl<'a, R, C> specs::System<'a> for System<R, C>
where
R: 'static + gfx::Resources,
C: 'static + gfx::CommandBuffer<R> + Send,
{
type SystemData = (Entities<'a>,
Fetch<'a, DefaultCamera>,
ReadStorage<'a, Visual>,
ReadStorage<'a, Spatial>);
fn run(&mut self, data: Self::SystemData) {
let (entities, default_camera, visuals, spatials) = data;
if let Some(camera_entity) = default_camera.camera_entity {
if spatials.get(camera_entity).is_some() {
self.draw(&entities, &visuals, &spatials, camera_entity);
}
}
}
}