use gfx_core::{format, handle, tex};
use gfx_core::{Primitive, Resources, ShaderSet, VertexCount};
use gfx_core::factory::{BufferRole, Factory};
use gfx_core::pso::{CreationError, Descriptor};
use gfx_core::state::{CullFace, Rasterizer};
use encoder::Encoder;
use mesh::{Slice, SliceKind, ToIndexSlice};
use pso;
use shade::{ProgramError, ShaderSource};
#[derive(Clone, PartialEq, Debug)]
pub enum PipelineStateError {
Program(ProgramError),
DescriptorInit(pso::InitError),
DeviceCreate(CreationError),
}
pub trait FactoryExt<R: Resources>: Factory<R> + Sized {
fn create_encoder(&mut self) -> Encoder<R, Self::CommandBuffer> {
Encoder::create(self)
}
fn create_vertex_buffer<T>(&mut self, data: &[T])
-> (handle::Buffer<R, T>, Slice<R>) where
T: Copy + pso::buffer::Structure<format::Format>
{
let nv = data.len();
let buf = self.create_buffer_static(data, BufferRole::Vertex);
(buf, Slice {
start: 0,
end: nv as VertexCount,
instances: None,
kind: SliceKind::Vertex,
})
}
fn create_vertex_buffer_indexed<V, I>(&mut self, vd: &[V], id: I)
-> (handle::Buffer<R, V>, Slice<R>) where
V: Copy + pso::buffer::Structure<format::Format>,
I: ToIndexSlice<R>,
{
let buf = self.create_buffer_static(vd, BufferRole::Vertex);
(buf, id.to_slice(self))
}
fn create_constant_buffer<T>(&mut self, num: usize) -> handle::Buffer<R, T> {
self.create_buffer_dynamic(num, BufferRole::Uniform)
}
fn create_shader_set(&mut self, vs_code: &[u8], ps_code: &[u8])
-> Result<ShaderSet<R>, ProgramError> {
let vs = match self.create_shader_vertex(vs_code) {
Ok(s) => s,
Err(e) => return Err(ProgramError::Vertex(e)),
};
let ps = match self.create_shader_pixel(ps_code) {
Ok(s) => s,
Err(e) => return Err(ProgramError::Pixel(e)),
};
Ok(ShaderSet::Simple(vs, ps))
}
fn link_program(&mut self, vs_code: &[u8], ps_code: &[u8])
-> Result<handle::Program<R>, ProgramError> {
let set = try!(self.create_shader_set(vs_code, ps_code));
self.create_program(&set)
.map_err(|e| ProgramError::Link(e))
}
fn link_program_source(&mut self, vs_src: ShaderSource, ps_src: ShaderSource)
-> Result<handle::Program<R>, ProgramError> {
use gfx_core::shade::CreateShaderError;
let model = self.get_capabilities().shader_model;
match (vs_src.choose(model), ps_src.choose(model)) {
(Ok(vs_code), Ok(ps_code)) => self.link_program(vs_code, ps_code),
(Err(_), Ok(_)) => Err(ProgramError::Vertex(CreateShaderError::ModelNotSupported)),
(_, Err(_)) => Err(ProgramError::Pixel(CreateShaderError::ModelNotSupported)),
}
}
fn create_pipeline_state<I: pso::PipelineInit>(&mut self, shaders: &ShaderSet<R>,
primitive: Primitive, rasterizer: Rasterizer, init: I)
-> Result<pso::PipelineState<R, I::Meta>, PipelineStateError>
{
let program = match self.create_program(shaders) {
Ok(p) => p,
Err(e) => return Err(PipelineStateError::Program(ProgramError::Link(e))),
};
let mut descriptor = Descriptor::new(primitive, rasterizer);
let meta = match init.link_to(&mut descriptor, program.get_info()) {
Ok(m) => m,
Err(e) => return Err(PipelineStateError::DescriptorInit(e)),
};
let raw = match self.create_pipeline_state_raw(&program, &descriptor) {
Ok(raw) => raw,
Err(e) => return Err(PipelineStateError::DeviceCreate(e)),
};
Ok(pso::PipelineState::new(raw, primitive, meta))
}
fn create_pipeline_simple<I: pso::PipelineInit>(&mut self, vs: &[u8], ps: &[u8], cull: CullFace, init: I)
-> Result<pso::PipelineState<R, I::Meta>, PipelineStateError>
{
match self.create_shader_set(vs, ps) {
Ok(ref s) => self.create_pipeline_state(s,
Primitive::TriangleList, Rasterizer::new_fill(cull), init),
Err(e) => Err(PipelineStateError::Program(e)),
}
}
fn create_sampler_linear(&mut self) -> handle::Sampler<R> {
self.create_sampler(tex::SamplerInfo::new(
tex::FilterMethod::Trilinear,
tex::WrapMode::Clamp,
))
}
}
impl<R: Resources, F: Factory<R>> FactoryExt<R> for F {}