#![deny(missing_docs)]
#![feature(use_extern_macros)]
pub extern crate gfx;
pub extern crate glutin;
pub extern crate image;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
mod error;
mod game;
mod pipeline;
use gfx::{Device, Encoder, Factory, Slice};
use gfx::format::{Rgba8, DepthStencil};
use gfx::handle::Sampler;
use gfx::pso::{PipelineData, PipelineInit, PipelineState};
use gfx::texture::{AaMode, Kind, Mipmap};
use gfx::traits::FactoryExt;
use gfx_device_gl::{CommandBuffer, Device as GlDevice, Factory as GlFactory, Resources};
use glutin::{ContextBuilder, EventsLoop, GlContext, GlWindow, WindowBuilder};
use image::RgbaImage;
pub type R = Resources;
pub type RenderTargetView = gfx::handle::RenderTargetView<R, Rgba8>;
pub type DepthStencilView = gfx::handle::DepthStencilView<R, DepthStencil>;
pub type ShaderResourceView = gfx::handle::ShaderResourceView<R, [f32; 4]>;
pub type Shader<T> = PipelineState<R, T>;
pub type Texture = (ShaderResourceView, Sampler<R>);
pub use error::{Error, Result};
pub use game::Game;
pub use gfx::{Global, TextureSampler};
pub type RenderTarget = gfx::RenderTarget<Rgba8>;
pub type DepthTarget = gfx::DepthTarget<DepthStencil>;
const VERTEX_SHADER: &'static [u8] = b"
#version 130
void main() {
float x = -1.0 + float((gl_VertexID & 1) << 2);
float y = -1.0 + float((gl_VertexID & 2) << 1);
gl_Position = vec4(x, y, 0, 1);
}
";
pub struct Window {
window: GlWindow,
device: GlDevice,
factory: GlFactory,
rtv: RenderTargetView,
stv: DepthStencilView,
encoder: Encoder<R, CommandBuffer>,
}
impl Window {
pub fn new(events: &EventsLoop) -> Self {
let (window, device, mut factory, rtv, stv) = gfx_window_glutin::init(
WindowBuilder::new(),
ContextBuilder::new().with_vsync(true),
&events,
);
Window {
encoder: factory.create_command_buffer().into(),
window, device, factory, rtv, stv,
}
}
pub fn shader<I>(&mut self, init: I, shader: &[u8])
-> Result<Shader<I::Meta>>
where
I: PipelineInit,
{
Ok(self.factory.create_pipeline_simple(
VERTEX_SHADER,
shader,
init,
)?)
}
pub fn draw<'a, D, F>(&'a mut self, shader: &Shader<D::Meta>, data: F)
where
D: PipelineData<R>,
F: FnOnce(&'a RenderTargetView, &'a DepthStencilView) -> D
{
let slice = Slice {
start: 0,
end: 3,
base_vertex: 0,
instances: None,
buffer: Default::default(),
};
self.encoder.draw(&slice, shader, &data(&self.rtv, &self.stv));
}
pub fn flush(&mut self) {
self.encoder.flush(&mut self.device);
self.window.swap_buffers().unwrap();
self.device.cleanup();
}
pub fn resize(&mut self) {
gfx_window_glutin::update_views(&self.window, &mut self.rtv, &mut self.stv);
}
pub fn texture(&mut self, image: RgbaImage) -> Texture {
let (width, height) = image.dimensions();
let (_, view) = self.factory
.create_texture_immutable_u8::<Rgba8>(
Kind::D2(width as u16, height as u16, AaMode::Single),
Mipmap::Provided,
&[&image],
)
.unwrap();
(view, self.factory.create_sampler_linear())
}
pub fn size(&self) -> Option<(u32, u32)> {
self.window().get_inner_size()
}
pub fn window(&self) -> &glutin::Window { self.window.window() }
pub fn encoder(&mut self) -> &mut Encoder<R, CommandBuffer> { &mut self.encoder }
pub fn factory(&mut self) -> &mut GlFactory { &mut self.factory }
}