#![allow(missing_docs)]
use std::{fmt, cmp, hash};
use std::error::Error;
use {Resources};
use {AttributeSlot, ColorSlot, ConstantBufferSlot, ResourceViewSlot, SamplerSlot, UnorderedViewSlot};
#[cfg(feature = "mint")]
use mint;
pub type Dimension = u8;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum IsArray { Array, NoArray }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum IsComparison { Compare, NoCompare }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum IsMultiSample { MultiSample, NoMultiSample }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum IsRect { Rect, NoRect }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum MatrixFormat { ColumnMajor, RowMajor }
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum TextureType {
Buffer,
D1(IsArray),
D2(IsArray, IsMultiSample),
D3,
Cube(IsArray),
}
impl TextureType {
pub fn can_sample(&self) -> bool {
match self {
&TextureType::Buffer => false,
&TextureType::D1(_) => true,
&TextureType::D2(_, IsMultiSample::MultiSample) => false,
&TextureType::D2(_, IsMultiSample::NoMultiSample) => true,
&TextureType::D3 => true,
&TextureType::Cube(_) => true,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct SamplerType(pub IsComparison, pub IsRect);
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum BaseType {
I32,
U32,
F32,
F64,
Bool,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum ContainerType {
Single,
Vector(Dimension),
Matrix(MatrixFormat, Dimension, Dimension),
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[repr(u8)]
pub enum Stage {
Vertex,
Hull,
Domain,
Geometry,
Pixel,
}
pub const STAGES: [Stage; 5] = [Stage::Vertex, Stage::Hull, Stage::Domain, Stage::Geometry, Stage::Pixel];
pub type Location = usize;
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum UniformValue {
I32(i32),
U32(u32),
F32(f32),
I32Vector2([i32; 2]),
I32Vector3([i32; 3]),
I32Vector4([i32; 4]),
U32Vector2([u32; 2]),
U32Vector3([u32; 3]),
U32Vector4([u32; 4]),
F32Vector2([f32; 2]),
F32Vector3([f32; 3]),
F32Vector4([f32; 4]),
F32Matrix2([[f32; 2]; 2]),
F32Matrix3([[f32; 3]; 3]),
F32Matrix4([[f32; 4]; 4]),
}
impl fmt::Debug for UniformValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
UniformValue::I32(x) => write!(f, "ValueI32({:?})", x),
UniformValue::U32(x) => write!(f, "ValueU32({:?})", x),
UniformValue::F32(x) => write!(f, "ValueF32({:?})", x),
UniformValue::I32Vector2(ref v) => write!(f, "ValueI32Vector2({:?})", &v[..]),
UniformValue::I32Vector3(ref v) => write!(f, "ValueI32Vector3({:?})", &v[..]),
UniformValue::I32Vector4(ref v) => write!(f, "ValueI32Vector4({:?})", &v[..]),
UniformValue::U32Vector2(ref v) => write!(f, "ValueU32Vector2({:?})", &v[..]),
UniformValue::U32Vector3(ref v) => write!(f, "ValueU32Vector3({:?})", &v[..]),
UniformValue::U32Vector4(ref v) => write!(f, "ValueU32Vector4({:?})", &v[..]),
UniformValue::F32Vector2(ref v) => write!(f, "ValueF32Vector2({:?})", &v[..]),
UniformValue::F32Vector3(ref v) => write!(f, "ValueF32Vector3({:?})", &v[..]),
UniformValue::F32Vector4(ref v) => write!(f, "ValueF32Vector4({:?})", &v[..]),
UniformValue::F32Matrix2(ref m) => {
try!(write!(f, "ValueF32Matrix2("));
for v in m.iter() {
try!(write!(f, "{:?}", &v[..]));
}
write!(f, ")")
},
UniformValue::F32Matrix3(ref m) => {
try!(write!(f, "ValueF32Matrix3("));
for v in m.iter() {
try!(write!(f, "{:?}", &v[..]));
}
write!(f, ")")
},
UniformValue::F32Matrix4(ref m) => {
try!(write!(f, "ValueF32Matrix4("));
for v in m.iter() {
try!(write!(f, "{:?}", &v[..]));
}
write!(f, ")")
},
}
}
}
pub type ConstFormat = (BaseType, ContainerType);
pub trait BaseTyped {
fn get_base_type() -> BaseType;
}
pub trait Formatted {
fn get_format() -> ConstFormat;
}
macro_rules! impl_base_type {
( $($name:ty = $value:ident ,)* ) => {
$(
impl BaseTyped for $name {
fn get_base_type() -> BaseType {
BaseType::$value
}
}
)*
}
}
macro_rules! impl_const_vector {
( $( $num:expr ),* ) => {
$(
impl<T: BaseTyped> Formatted for [T; $num] {
fn get_format() -> ConstFormat {
(T::get_base_type(), ContainerType::Vector($num))
}
}
)*
}
}
macro_rules! impl_const_matrix {
( $( [$n:expr, $m:expr] ),* ) => {
$(
impl<T: BaseTyped> Formatted for [[T; $n]; $m] {
fn get_format() -> ConstFormat {
let mf = MatrixFormat::ColumnMajor;
(T::get_base_type(), ContainerType::Matrix(mf, $n, $m))
}
}
)*
}
}
#[cfg(feature = "mint")]
macro_rules! impl_const_vector_mint {
( $( $name:ident = $num:expr, )* ) => {
$(
impl<T: BaseTyped> Formatted for mint::$name<T> {
fn get_format() -> ConstFormat {
(T::get_base_type(), ContainerType::Vector($num))
}
}
)*
}
}
#[cfg(feature = "mint")]
macro_rules! impl_const_matrix_mint {
( $( $name:ident = $format:ident $size:expr, )* ) => {
$(
impl<T: BaseTyped> Formatted for mint::$name<T> {
fn get_format() -> ConstFormat {
let mf = MatrixFormat::$format;
(T::get_base_type(), ContainerType::Matrix(mf, $size, $size))
}
}
)*
}
}
impl_base_type! {
i32 = I32,
u32 = U32,
f32 = F32,
f64 = F64,
bool = Bool,
}
impl<T: BaseTyped> Formatted for T {
fn get_format() -> ConstFormat {
(T::get_base_type(), ContainerType::Single)
}
}
impl_const_vector!(2, 3, 4);
impl_const_matrix!([2,2], [3,3], [4,4], [4,3]);
#[cfg(feature = "mint")]
impl_const_vector_mint! {
Point2 = 2,
Point3 = 3,
Vector2 = 2,
Vector3 = 3,
Vector4 = 4,
}
#[cfg(feature = "mint")]
impl_const_matrix_mint! {
ColumnMatrix2 = ColumnMajor 2,
ColumnMatrix3 = ColumnMajor 3,
ColumnMatrix4 = ColumnMajor 4,
RowMatrix2 = RowMajor 2,
RowMatrix3 = RowMajor 3,
RowMatrix4 = RowMajor 4,
}
bitflags!(
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Usage: u8 {
const VERTEX = 0x1;
const GEOMETRY = 0x2;
const PIXEL = 0x4;
const HULL = 0x8;
const DOMAIN = 0x16;
}
);
impl From<Stage> for Usage {
fn from(stage: Stage) -> Self {
match stage {
Stage::Vertex => Self::VERTEX,
Stage::Geometry => Self::GEOMETRY,
Stage::Pixel => Self::PIXEL,
Stage::Hull => Self::HULL,
Stage::Domain => Self::DOMAIN,
}
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct AttributeVar {
pub name: String,
pub slot: AttributeSlot,
pub base_type: BaseType,
pub container: ContainerType,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ConstVar {
pub name: String,
pub location: Location,
pub count: usize,
pub base_type: BaseType,
pub container: ContainerType,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ConstantBufferVar {
pub name: String,
pub slot: ConstantBufferSlot,
pub size: usize,
pub usage: Usage,
pub elements: Vec<ConstVar>,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct TextureVar {
pub name: String,
pub slot: ResourceViewSlot,
pub base_type: BaseType,
pub ty: TextureType,
pub usage: Usage,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct UnorderedVar {
pub name: String,
pub slot: UnorderedViewSlot,
pub usage: Usage,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct SamplerVar {
pub name: String,
pub slot: SamplerSlot,
pub ty: SamplerType,
pub usage: Usage,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct OutputVar {
pub name: String,
pub slot: ColorSlot,
pub base_type: BaseType,
pub container: ContainerType,
}
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct ProgramInfo {
pub vertex_attributes: Vec<AttributeVar>,
pub globals: Vec<ConstVar>,
pub constant_buffers: Vec<ConstantBufferVar>,
pub textures: Vec<TextureVar>,
pub unordereds: Vec<UnorderedVar>,
pub samplers: Vec<SamplerVar>,
pub outputs: Vec<OutputVar>,
pub output_depth: bool,
pub knows_outputs: bool,
}
#[derive(Debug)]
pub struct Program<R: Resources> {
resource: R::Program,
info: ProgramInfo,
}
impl<R: Resources> Program<R> {
#[doc(hidden)]
pub fn new(resource: R::Program, info: ProgramInfo) -> Self {
Program {
resource: resource,
info: info,
}
}
#[doc(hidden)]
pub fn resource(&self) -> &R::Program { &self.resource }
pub fn get_info(&self) -> &ProgramInfo { &self.info }
}
impl<R: Resources + cmp::PartialEq> cmp::PartialEq for Program<R> {
fn eq(&self, other: &Program<R>) -> bool {
self.resource().eq(other.resource())
}
}
impl<R: Resources + cmp::Eq> cmp::Eq for Program<R> {}
impl<R: Resources + hash::Hash> hash::Hash for Program<R> {
fn hash<H>(&self, state: &mut H) where H: hash::Hasher {
self.resource().hash(state);
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CompatibilityError {
ErrorArraySize,
ErrorBaseType,
ErrorContainer,
}
impl fmt::Display for CompatibilityError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.description())
}
}
impl Error for CompatibilityError {
fn description(&self) -> &str {
match *self {
CompatibilityError::ErrorArraySize =>
"Array sizes differ between the value and the var \
(trying to upload a vec2 as a vec4, etc)",
CompatibilityError::ErrorBaseType =>
"Base types differ between the value and the var \
(trying to upload a f32 as a u16, etc)",
CompatibilityError::ErrorContainer =>
"Container-ness differs between the value and the var \
(trying to upload a scalar as a vec4, etc)",
}
}
}
impl ConstVar {
pub fn is_compatible(&self, value: &UniformValue) -> Result<(), CompatibilityError> {
if self.count != 1 {
return Err(CompatibilityError::ErrorArraySize)
}
match (self.base_type, self.container, *value) {
(BaseType::I32, ContainerType::Single, UniformValue::I32(_)) => Ok(()),
(BaseType::U32, ContainerType::Single, UniformValue::U32(_)) => Ok(()),
(BaseType::F32, ContainerType::Single, UniformValue::F32(_)) => Ok(()),
(BaseType::I32, ContainerType::Vector(2), UniformValue::I32Vector2(_)) => Ok(()),
(BaseType::I32, ContainerType::Vector(3), UniformValue::I32Vector3(_)) => Ok(()),
(BaseType::I32, ContainerType::Vector(4), UniformValue::I32Vector4(_)) => Ok(()),
(BaseType::U32, ContainerType::Vector(2), UniformValue::U32Vector2(_)) => Ok(()),
(BaseType::U32, ContainerType::Vector(3), UniformValue::U32Vector3(_)) => Ok(()),
(BaseType::U32, ContainerType::Vector(4), UniformValue::U32Vector4(_)) => Ok(()),
(BaseType::F32, ContainerType::Vector(2), UniformValue::F32Vector2(_)) => Ok(()),
(BaseType::F32, ContainerType::Vector(3), UniformValue::F32Vector3(_)) => Ok(()),
(BaseType::F32, ContainerType::Vector(4), UniformValue::F32Vector4(_)) => Ok(()),
(BaseType::F32, ContainerType::Matrix(_, 2,2), UniformValue::F32Matrix2(_)) => Ok(()),
(BaseType::F32, ContainerType::Matrix(_, 3,3), UniformValue::F32Matrix3(_)) => Ok(()),
(BaseType::F32, ContainerType::Matrix(_, 4,4), UniformValue::F32Matrix4(_)) => Ok(()),
_ => Err(CompatibilityError::ErrorBaseType)
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum CreateShaderError {
ModelNotSupported,
StageNotSupported(Stage),
CompilationFailed(String),
}
impl fmt::Display for CreateShaderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let desc = self.description();
match *self {
CreateShaderError::StageNotSupported(ref stage) => write!(f, "{}: {:?}", desc, stage),
CreateShaderError::CompilationFailed(ref string) => write!(f, "{}: {}", desc, string),
_ => write!(f, "{}", desc),
}
}
}
impl Error for CreateShaderError {
fn description(&self) -> &str {
match *self {
CreateShaderError::ModelNotSupported => "The device does not support the requested shader model",
CreateShaderError::StageNotSupported(_) => "The device does not support the shader stage",
CreateShaderError::CompilationFailed(_) => "The shader failed to compile",
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CreateProgramError(String);
impl fmt::Display for CreateProgramError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.pad(&self.0)
}
}
impl Error for CreateProgramError {
fn description(&self) -> &str {
&self.0
}
}
impl<S: Into<String>> From<S> for CreateProgramError {
fn from(s: S) -> CreateProgramError {
CreateProgramError(s.into())
}
}