use device;
use device::shade::{Stage, CreateShaderError, ShaderModel};
use super::mesh::{Mesh, VertexFormat};
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum ProgramError {
Vertex(CreateShaderError),
Fragment(CreateShaderError),
Link(()),
}
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct ShaderSource<'a> {
pub glsl_120: Option<&'a [u8]>,
pub glsl_130: Option<&'a [u8]>,
pub glsl_140: Option<&'a [u8]>,
pub glsl_150: Option<&'a [u8]>,
pub glsl_430: Option<&'a [u8]>,
pub targets: &'a [&'a str],
}
impl<'a> ShaderSource<'a> {
pub fn empty() -> ShaderSource<'a> {
ShaderSource {
glsl_120: None,
glsl_130: None,
glsl_140: None,
glsl_150: None,
glsl_430: None,
targets: &[],
}
}
pub fn choose(&self, model: ShaderModel) -> Result<&'a [u8], ()> {
let version = model.to_number();
Ok(match *self {
ShaderSource { glsl_430: Some(s), .. } if version >= 50 => s,
ShaderSource { glsl_150: Some(s), .. } if version >= 40 => s,
ShaderSource { glsl_140: Some(s), .. } if version >= 40 => s,
ShaderSource { glsl_130: Some(s), .. } if version >= 30 => s,
ShaderSource { glsl_120: Some(s), .. } if version >= 20 => s,
_ => return Err(()),
})
}
}
pub trait DeviceExt: device::Device {
fn create_renderer(&mut self) -> ::Renderer<<Self as device::Device>::CommandBuffer>;
fn create_mesh<T: VertexFormat + Copy>(&mut self, data: &[T]) -> Mesh;
fn link_program(&mut self, vs_code: &[u8], fs_code: &[u8])
-> Result<device::ProgramHandle, ProgramError>;
fn link_program_source(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
-> Result<device::ProgramHandle, ProgramError>;
}
impl<D: device::Device> DeviceExt for D {
fn create_renderer(&mut self) -> ::Renderer<D::CommandBuffer> {
::Renderer {
command_buffer: device::draw::CommandBuffer::new(),
data_buffer: device::draw::DataBuffer::new(),
common_array_buffer: self.create_array_buffer(),
draw_frame_buffer: self.create_frame_buffer(),
read_frame_buffer: self.create_frame_buffer(),
default_frame_buffer: device::get_main_frame_buffer(),
render_state: super::RenderState::new(),
parameters: super::ParamStorage::new(),
}
}
fn create_mesh<T: VertexFormat + Copy>(&mut self, data: &[T]) -> Mesh {
let nv = data.len();
debug_assert!(nv < {
use std::num::Int;
let val: device::VertexCount = Int::max_value();
val as usize
});
let buf = self.create_buffer_static(data);
Mesh::from_format(buf, nv as device::VertexCount)
}
fn link_program(&mut self, vs_code: &[u8], fs_code: &[u8])
-> Result<device::ProgramHandle, ProgramError> {
let vs = match self.create_shader(Stage::Vertex, vs_code) {
Ok(s) => s,
Err(e) => return Err(ProgramError::Vertex(e)),
};
let fs = match self.create_shader(Stage::Fragment, fs_code) {
Ok(s) => s,
Err(e) => return Err(ProgramError::Fragment(e)),
};
self.create_program(&[vs, fs], None)
.map_err(|e| ProgramError::Link(e))
}
fn link_program_source(&mut self, vs_src: ShaderSource, fs_src: ShaderSource)
-> Result<device::ProgramHandle, ProgramError> {
let model = self.get_capabilities().shader_model;
let err_model = CreateShaderError::ModelNotSupported;
let vs = match vs_src.choose(model) {
Ok(code) => match self.create_shader(Stage::Vertex, code) {
Ok(s) => s,
Err(e) => return Err(ProgramError::Vertex(e)),
},
Err(_) => return Err(ProgramError::Vertex(err_model))
};
let fs = match fs_src.choose(model) {
Ok(code) => match self.create_shader(Stage::Fragment, code) {
Ok(s) => s,
Err(e) => return Err(ProgramError::Fragment(e)),
},
Err(_) => return Err(ProgramError::Fragment(err_model))
};
self.create_program(&[vs, fs], Some(fs_src.targets))
.map_err(|e| ProgramError::Link(e))
}
}