use gl;
use context::Context;
use version::Version;
use version::Api;
use DrawError;
use Rect;
use ToGlEnum;
use std::default::Default;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BlendingFunction {
AlwaysReplace,
Min,
Max,
Addition {
source: LinearBlendingFactor,
destination: LinearBlendingFactor,
},
Subtraction {
source: LinearBlendingFactor,
destination: LinearBlendingFactor,
},
ReverseSubtraction {
source: LinearBlendingFactor,
destination: LinearBlendingFactor,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LinearBlendingFactor {
Zero,
One,
SourceColor,
OneMinusSourceColor,
DestinationColor,
OneMinusDestinationColor,
SourceAlpha,
OneMinusSourceAlpha,
DestinationAlpha,
OneMinusDestinationAlpha,
}
impl ToGlEnum for LinearBlendingFactor {
fn to_glenum(&self) -> gl::types::GLenum {
match *self {
LinearBlendingFactor::Zero => gl::ZERO,
LinearBlendingFactor::One => gl::ONE,
LinearBlendingFactor::SourceColor => gl::SRC_COLOR,
LinearBlendingFactor::OneMinusSourceColor => gl::ONE_MINUS_SRC_COLOR,
LinearBlendingFactor::DestinationColor => gl::DST_COLOR,
LinearBlendingFactor::OneMinusDestinationColor => gl::ONE_MINUS_DST_COLOR,
LinearBlendingFactor::SourceAlpha => gl::SRC_ALPHA,
LinearBlendingFactor::OneMinusSourceAlpha => gl::ONE_MINUS_SRC_ALPHA,
LinearBlendingFactor::DestinationAlpha => gl::DST_ALPHA,
LinearBlendingFactor::OneMinusDestinationAlpha => gl::ONE_MINUS_DST_ALPHA,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BackfaceCullingMode {
CullingDisabled,
CullCounterClockWise,
CullClockWise
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DepthTest {
Ignore,
Overwrite,
IfEqual,
IfNotEqual,
IfMore,
IfMoreOrEqual,
IfLess,
IfLessOrEqual
}
impl DepthTest {
pub fn requires_depth_buffer(&self) -> bool {
match *self {
DepthTest::Ignore => true,
DepthTest::Overwrite => false,
DepthTest::IfEqual => true,
DepthTest::IfNotEqual => true,
DepthTest::IfMore => true,
DepthTest::IfMoreOrEqual => true,
DepthTest::IfLess => true,
DepthTest::IfLessOrEqual => true,
}
}
}
impl ToGlEnum for DepthTest {
fn to_glenum(&self) -> gl::types::GLenum {
match *self {
DepthTest::Ignore => gl::NEVER,
DepthTest::Overwrite => gl::ALWAYS,
DepthTest::IfEqual => gl::EQUAL,
DepthTest::IfNotEqual => gl::NOTEQUAL,
DepthTest::IfMore => gl::GREATER,
DepthTest::IfMoreOrEqual => gl::GEQUAL,
DepthTest::IfLess => gl::LESS,
DepthTest::IfLessOrEqual => gl::LEQUAL,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum StencilTest {
AlwaysPass,
AlwaysFail,
IfLess { mask: u32 },
IfLessOrEqual { mask: u32 },
IfMore { mask: u32 },
IfMoreOrEqual { mask: u32 },
IfEqual { mask: u32 },
IfNotEqual { mask: u32 },
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum StencilOperation {
Keep,
Zero,
Replace,
Increment,
IncrementWrap,
Decrement,
DecrementWrap,
Invert,
}
impl ToGlEnum for StencilOperation {
fn to_glenum(&self) -> gl::types::GLenum {
match *self {
StencilOperation::Keep => gl::KEEP,
StencilOperation::Zero => gl::ZERO,
StencilOperation::Replace => gl::REPLACE,
StencilOperation::Increment => gl::INCR,
StencilOperation::IncrementWrap => gl::INCR_WRAP,
StencilOperation::Decrement => gl::DECR,
StencilOperation::DecrementWrap => gl::DECR_WRAP,
StencilOperation::Invert => gl::INVERT,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PolygonMode {
Point,
Line,
Fill,
}
impl ToGlEnum for PolygonMode {
fn to_glenum(&self) -> gl::types::GLenum {
match *self {
PolygonMode::Point => gl::POINT,
PolygonMode::Line => gl::LINE,
PolygonMode::Fill => gl::FILL,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct DrawParameters {
pub depth_test: DepthTest,
pub depth_write: bool,
pub depth_range: (f32, f32),
pub stencil_test_clockwise: StencilTest,
pub stencil_reference_value_clockwise: i32,
pub stencil_write_mask_clockwise: u32,
pub stencil_fail_operation_clockwise: StencilOperation,
pub stencil_pass_depth_fail_operation_clockwise: StencilOperation,
pub stencil_depth_pass_operation_clockwise: StencilOperation,
pub stencil_test_counter_clockwise: StencilTest,
pub stencil_reference_value_counter_clockwise: i32,
pub stencil_write_mask_counter_clockwise: u32,
pub stencil_fail_operation_counter_clockwise: StencilOperation,
pub stencil_pass_depth_fail_operation_counter_clockwise: StencilOperation,
pub stencil_depth_pass_operation_counter_clockwise: StencilOperation,
pub blending_function: Option<BlendingFunction>,
pub line_width: Option<f32>,
pub point_size: Option<f32>,
pub backface_culling: BackfaceCullingMode,
pub polygon_mode: PolygonMode,
pub multisampling: bool,
pub dithering: bool,
pub viewport: Option<Rect>,
pub scissor: Option<Rect>,
pub draw_primitives: bool,
}
impl Default for DrawParameters {
fn default() -> DrawParameters {
DrawParameters {
depth_test: DepthTest::Overwrite,
depth_write: false,
depth_range: (0.0, 1.0),
stencil_test_clockwise: StencilTest::AlwaysPass,
stencil_reference_value_clockwise: 0,
stencil_write_mask_clockwise: 0xffffffff,
stencil_fail_operation_clockwise: StencilOperation::Keep,
stencil_pass_depth_fail_operation_clockwise: StencilOperation::Keep,
stencil_depth_pass_operation_clockwise: StencilOperation::Keep,
stencil_test_counter_clockwise: StencilTest::AlwaysPass,
stencil_reference_value_counter_clockwise: 0,
stencil_write_mask_counter_clockwise: 0xffffffff,
stencil_fail_operation_counter_clockwise: StencilOperation::Keep,
stencil_pass_depth_fail_operation_counter_clockwise: StencilOperation::Keep,
stencil_depth_pass_operation_counter_clockwise: StencilOperation::Keep,
blending_function: Some(BlendingFunction::AlwaysReplace),
line_width: None,
point_size: None,
backface_culling: BackfaceCullingMode::CullingDisabled,
polygon_mode: PolygonMode::Fill,
multisampling: true,
dithering: true,
viewport: None,
scissor: None,
draw_primitives: true,
}
}
}
pub fn validate(context: &Context, params: &DrawParameters) -> Result<(), DrawError> {
if params.depth_range.0 < 0.0 || params.depth_range.0 > 1.0 ||
params.depth_range.1 < 0.0 || params.depth_range.1 > 1.0
{
return Err(DrawError::InvalidDepthRange);
}
if !params.draw_primitives && context.get_version() < &Version(Api::Gl, 3, 0) &&
!context.get_extensions().gl_ext_transform_feedback
{
return Err(DrawError::TransformFeedbackNotSupported);
}
Ok(())
}