plexus 0.0.10

3D mesh generation and manipulation.
Documentation
use gfx::format::{DepthStencil, Rgba8};
use gfx::handle::{DepthStencilView, RenderTargetView};
use gfx::state::Rasterizer;
use gfx::traits::FactoryExt;
use gfx::{CommandBuffer, Device, Encoder, Factory, PipelineState, Primitive, Resources};
use gfx_device_gl;
use gfx_window_glutin;
use glutin::{GlContext, GlWindow};
use plexus::buffer::MeshBuffer;

use pipeline::{self, Data, Meta, Transform, Vertex};

const CLEAR_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];

pub trait SwapBuffers {
    fn swap_buffers(&mut self) -> Result<(), ()>;
}

impl SwapBuffers for GlWindow {
    fn swap_buffers(&mut self) -> Result<(), ()> {
        match <GlWindow as GlContext>::swap_buffers(self) {
            Ok(_) => Ok(()),
            Err(_) => Err(()),
        }
    }
}

pub trait UpdateFrameBufferView<R>
where
    R: Resources,
{
    fn update_frame_buffer_view(
        &self,
        color: &mut RenderTargetView<R, Rgba8>,
        depth: &mut DepthStencilView<R, DepthStencil>,
    );
}

impl UpdateFrameBufferView<gfx_device_gl::Resources> for GlWindow {
    fn update_frame_buffer_view(
        &self,
        color: &mut RenderTargetView<gfx_device_gl::Resources, Rgba8>,
        depth: &mut DepthStencilView<gfx_device_gl::Resources, DepthStencil>,
    ) {
        gfx_window_glutin::update_views(self, color, depth);
    }
}

pub trait MetaRenderer {
    type Window: SwapBuffers + UpdateFrameBufferView<Self::Resources>;
    type Resources: Resources;
    type Factory: Factory<Self::Resources>;
    type CommandBuffer: CommandBuffer<Self::Resources>;
    type Device: Device<Resources = Self::Resources, CommandBuffer = Self::CommandBuffer>;
}

pub struct GlutinRenderer {}

impl MetaRenderer for GlutinRenderer {
    type Window = GlWindow;
    type Resources = gfx_device_gl::Resources;
    type Factory = gfx_device_gl::Factory;
    type CommandBuffer = gfx_device_gl::CommandBuffer;
    type Device = gfx_device_gl::Device;
}

pub struct Renderer<R>
where
    R: MetaRenderer,
{
    pub window: R::Window,
    pub factory: R::Factory,
    device: R::Device,
    encoder: Encoder<R::Resources, R::CommandBuffer>,
    state: PipelineState<R::Resources, Meta>,
    data: Data<R::Resources>,
}

impl Renderer<GlutinRenderer> {
    pub fn from_glutin_window(window: GlWindow) -> Self {
        let (device, mut factory, color, depth) = gfx_window_glutin::init_existing(&window);
        let encoder = factory.create_command_buffer().into();
        Renderer::new(window, factory, device, encoder, color, depth)
    }
}

impl<R> Renderer<R>
where
    R: MetaRenderer,
{
    fn new(
        window: R::Window,
        mut factory: R::Factory,
        device: R::Device,
        encoder: Encoder<R::Resources, R::CommandBuffer>,
        color: RenderTargetView<R::Resources, Rgba8>,
        depth: DepthStencilView<R::Resources, DepthStencil>,
    ) -> Self {
        let shaders = factory
            .create_shader_set(
                include_bytes!("shader.v.glsl"),
                include_bytes!("shader.f.glsl"),
            )
            .unwrap();
        let state = factory
            .create_pipeline_state(
                &shaders,
                Primitive::TriangleList,
                Rasterizer::new_fill().with_cull_back(),
                pipeline::new(),
            )
            .unwrap();
        let data = Data {
            // Using an empty slice here causes an error.
            buffer: factory.create_vertex_buffer(&[Vertex::default()]),
            transform: factory.create_constant_buffer(1),
            camera: [[0.0; 4]; 4],
            model: [[0.0; 4]; 4],
            color: color,
            depth: depth,
        };
        Renderer {
            window: window,
            factory: factory,
            device: device,
            encoder: encoder,
            state: state,
            data: data,
        }
    }

    pub fn set_transform(&mut self, transform: &Transform) -> Result<(), ()> {
        self.data.camera = transform.camera;
        self.data.model = transform.model;
        match self
            .encoder
            .update_buffer(&self.data.transform, &[*transform], 0)
        {
            Ok(_) => Ok(()),
            Err(_) => Err(()),
        }
    }

    pub fn draw_mesh_buffer(&mut self, buffer: &MeshBuffer<u32, Vertex>) {
        let (buffer, slice) = self
            .factory
            .create_vertex_buffer_with_slice(buffer.as_vertex_slice(), buffer.as_index_slice());
        self.data.buffer = buffer;
        self.encoder.draw(&slice, &self.state, &self.data);
    }

    pub fn clear(&mut self) {
        self.encoder.clear(&self.data.color, CLEAR_COLOR);
        self.encoder.clear_depth(&self.data.depth, 1.0);
    }

    pub fn flush(&mut self) -> Result<(), ()> {
        self.encoder.flush(&mut self.device);
        match self.window.swap_buffers().and_then(|_| {
            self.device.cleanup();
            Ok(())
        }) {
            Ok(_) => Ok(()),
            Err(_) => Err(()),
        }
    }

    pub fn update_frame_buffer_view(&mut self) {
        self.window
            .update_frame_buffer_view(&mut self.data.color, &mut self.data.depth);
    }
}