#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
use gl::{self, Gl};
#[cfg(feature="gles")]
use gl::{self, Gles2 as Gl};
#[cfg(feature="webgl")]
use gl::{self, GlinContext as Gl};
use gl::types::*;
use std::cmp::{PartialEq, PartialOrd, Ordering, Ord};
use std::mem;
#[cfg(not(feature="webgl"))]
use std::ffi::CStr;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
use std::os::raw::c_void;
#[cfg(not(feature="webgl"))]
use std::os::raw::c_char;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
use std::sync::Arc;
use std::rc::Rc;
use std::fmt::{self, Debug, Formatter};
use std::ops::Deref;
use std::cell::{UnsafeCell, Cell};
#[cfg(feature = "webgl")]
use stdweb::unstable::TryInto;
use std::borrow::Cow;
use program;
use ::Rect;
use offscreen_buffer::UntypedOffscreenBuffer;
macro_rules! GLIN_ROUND_UP_8(
($num:expr) => ((($num)+7)&!7)
);
macro_rules! GLIN_ROUND_UP_4(
($num:expr) => ((($num)+3)&!3)
);
macro_rules! GLIN_ROUND_UP_2(
($num:expr) => ((($num)+1)&!1)
);
pub struct GlDebugWrapper(Gl);
impl Debug for GlDebugWrapper{
fn fmt(&self, _: &mut Formatter) -> fmt::Result{
Ok(())
}
}
impl Deref for GlDebugWrapper{
type Target = Gl;
#[inline]
fn deref(&self) -> &Gl{
&self.0
}
}
#[derive(Clone, Debug)]
pub struct StateRef{
state: Rc<UnsafeCell<State<'static>>>,
capabilities: Rc<UnsafeCell<Capabilities>>,
}
impl PartialEq for StateRef{
#[inline]
fn eq(&self, other: &StateRef) -> bool{
self.state.get() == other.state.get()
}
}
impl Eq for StateRef{}
impl Deref for StateRef{
type Target = Gl;
#[inline]
fn deref(&self) -> &Gl{
unsafe{ &(*self.state.get()).gl }
}
}
impl StateRef{
pub fn from_gl(gl: Gl) -> StateRef{
let capabilities = Capabilities::from_gl(&gl);
let state = State::from_gl(gl);
StateRef{
state: Rc::new(UnsafeCell::new(state)),
capabilities: Rc::new(UnsafeCell::new(capabilities)),
}
}
pub fn capabilities(&self) -> &Capabilities{
unsafe{ &*self.capabilities.get() }
}
pub fn capabilities_mut(&mut self) -> &mut Capabilities{
unsafe{ &mut *self.capabilities.get() }
}
#[inline]
pub(crate) fn state(&self) -> &State<'static>{
unsafe{ &*self.state.get() }
}
#[inline]
pub(crate) fn state_mut(&self) -> &mut State<'static>{
unsafe{ &mut *self.state.get() }
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Vendor{
Nvidia,
AMD,
Intel,
Other(String)
}
#[derive(Clone, Debug)]
pub struct ShadingLanguageVersion{
pub major: u32,
pub minor: u32,
pub vendor_specific: String,
}
impl ShadingLanguageVersion{
pub fn new(major: u32, minor: u32) -> ShadingLanguageVersion{
ShadingLanguageVersion{
major,
minor,
vendor_specific: String::new(),
}
}
}
impl PartialEq for ShadingLanguageVersion{
fn eq(&self, other: &ShadingLanguageVersion) -> bool {
self.major == other.major && self.minor == other.minor
}
}
impl PartialOrd for ShadingLanguageVersion{
fn partial_cmp(&self, other: &ShadingLanguageVersion) -> Option<Ordering>{
if self.major > other.major {
Some(Ordering::Greater)
}else if self.major < other.major {
Some(Ordering::Less)
}else {
if self.minor > other.minor {
Some(Ordering::Greater)
}else if self.minor < other.minor {
Some(Ordering::Less)
}else{
if self.vendor_specific == other.vendor_specific {
Some(Ordering::Equal)
}else if self.vendor_specific == "" || other.vendor_specific == ""{
Some(Ordering::Equal)
}else{
None
}
}
}
}
}
#[derive(Clone, Debug)]
pub struct Capabilities{
pub max_texture_size: u32,
pub max_texture_array_layers: u32,
pub max_3d_texture_size: u32,
pub max_color_attachments: u32,
pub max_renderbuffer_size: u32,
pub max_texture_image_units: u32,
pub max_texture_anistropy_level: f32,
pub supported_extensions: Vec<String>,
pub supports_dsa: bool,
pub supports_dsa_ext: bool,
pub supports_vertex_attrib_binding: bool,
pub dsa_enabled: bool,
pub vertex_attrib_binding_enabled: bool,
pub vendor: Vendor,
pub shading_language_version: ShadingLanguageVersion,
}
impl Capabilities{
pub fn from_gl(gl: &Gl) -> Capabilities{
unsafe{
let mut max_texture_size = 0;
gl.GetIntegerv(gl::MAX_TEXTURE_SIZE, &mut max_texture_size);
let mut max_3d_texture_size = 0;
gl.GetIntegerv(gl::MAX_3D_TEXTURE_SIZE, &mut max_3d_texture_size);
let mut max_texture_array_layers = 0;
gl.GetIntegerv(gl::MAX_ARRAY_TEXTURE_LAYERS, &mut max_texture_array_layers);
let mut max_color_attachments = 0;
gl.GetIntegerv(gl::MAX_COLOR_ATTACHMENTS, &mut max_color_attachments);
let mut max_renderbuffer_size = 0;
gl.GetIntegerv(gl::MAX_RENDERBUFFER_SIZE, &mut max_renderbuffer_size);
let mut max_texture_image_units = 0;
gl.GetIntegerv(gl::MAX_TEXTURE_IMAGE_UNITS, &mut max_texture_image_units);
let mut max_texture_anistropy_level = 0.;
#[cfg(not(feature="webgl"))]
gl.GetFloatv(gl::MAX_TEXTURE_MAX_ANISOTROPY_EXT, &mut max_texture_anistropy_level);
#[cfg(feature="webgl")]
gl.GetFloatv(
gl::EXT_texture_filter_anisotropic::MAX_TEXTURE_MAX_ANISOTROPY_EXT,
&mut max_texture_anistropy_level);
let supported_extensions: Vec<String>;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
{
let mut num_extensions = 0;
gl.GetIntegerv(gl::NUM_EXTENSIONS, &mut num_extensions);
supported_extensions = (0..num_extensions).filter_map(|i|{
let extension = gl.GetStringi(gl::EXTENSIONS, i as u32);
if !extension.is_null(){
let extension = CStr::from_ptr(extension as *const c_char)
.to_string_lossy()
.into_owned();
Some(extension)
}else{
None
}
}).collect();
}
#[cfg(feature = "gles")]
{
let extensions = gl.GetString(gl::EXTENSIONS);
supported_extensions = CStr::from_ptr(extensions as *const c_char)
.to_string_lossy()
.split(" ")
.map(|s| s.to_owned()).collect();
}
#[cfg(feature = "webgl")]
{
supported_extensions = gl.GetSupportedExtensions().unwrap_or_else(|| vec![])
}
let supports_dsa = supported_extensions
.contains(&"GL_ARB_direct_state_access".to_string());
let supports_dsa_ext = supported_extensions
.contains(&"GL_EXT_direct_state_access".to_string());
let supports_vertex_attrib_binding = supported_extensions
.contains(&"GL_ARB_vertex_attrib_binding".to_string());
#[cfg(not(feature="webgl"))]
let vendor = {
let vendor = gl.GetString(gl::VENDOR);
CStr::from_ptr(vendor as *const c_char)
.to_string_lossy()
.to_string()
};
#[cfg(feature="webgl")]
let vendor = gl.GetParameter(gl::VENDOR).into_string().unwrap();
let vendor = if vendor.contains("NVIDIA"){
Vendor::Nvidia
}else if vendor.contains("ATI") || vendor.contains("AMD"){
Vendor::AMD
}else if vendor.contains("Intel"){
Vendor::Intel
}else{
Vendor::Other(vendor)
};
#[cfg(not(feature="webgl"))]
let shading_language_version = {
let shading_language_version = gl.GetString(gl::SHADING_LANGUAGE_VERSION);
CStr::from_ptr(shading_language_version as *const c_char)
.to_string_lossy()
};
#[cfg(feature="webgl")]
let shading_language_version = gl.GetParameter(gl::SHADING_LANGUAGE_VERSION)
.into_string()
.unwrap();
#[cfg(not(feature="webgl"))]
let re_version = regex::Regex::new(r"([0-9]+)\.([0-9]+)(.*)").unwrap();
#[cfg(feature="webgl")]
let re_version = regex::Regex::new(r".*([0-9]+)\.([0-9]+)(.*)").unwrap();
let captures = re_version.captures(&shading_language_version).unwrap();
let vendor_specific = &captures[3];
let shading_language_version = ShadingLanguageVersion{
major: captures[1].parse().unwrap(),
minor: captures[2].parse().unwrap(),
vendor_specific: if vendor_specific == "" {
vendor_specific.to_owned()
}else{
vendor_specific[1..].to_owned()
},
};
Capabilities{
max_texture_size: max_texture_size as u32,
max_3d_texture_size: max_3d_texture_size as u32,
max_color_attachments: max_color_attachments as u32,
max_renderbuffer_size: max_renderbuffer_size as u32,
max_texture_image_units: max_texture_image_units as u32,
max_texture_array_layers: max_texture_array_layers as u32,
max_texture_anistropy_level,
supported_extensions,
supports_dsa,
supports_dsa_ext,
supports_vertex_attrib_binding,
dsa_enabled: supports_dsa,
vertex_attrib_binding_enabled: supports_vertex_attrib_binding,
vendor,
shading_language_version,
}
}
}
pub fn is_supported(&self, extension: &str) -> bool{
self.supported_extensions.contains(&extension.to_string())
}
pub(crate) fn supports_dsa(&self) -> bool{
self.supports_dsa && self.dsa_enabled
}
#[cfg(not(any(feature = "gles", feature="webgl")))]
pub(crate) fn supports_dsa_ext(&self) -> bool{
self.supports_dsa_ext && self.dsa_enabled
}
pub(crate) fn supports_vertex_attrib_binding(&self) -> bool{
self.supports_vertex_attrib_binding && self.vertex_attrib_binding_enabled
}
pub fn disable_dsa(&mut self){
self.dsa_enabled = false;
}
pub fn disable_vertex_attrib_binding(&mut self){
self.vertex_attrib_binding_enabled = false;
}
}
#[derive(Debug, PartialEq, Clone)]
struct StateInner<'a>{
enable: Enable,
depth: Depth,
program: Program,
vao: Vao,
fbo: Fbo,
#[cfg(not(any(feature = "gles", feature="webgl", target="macos")))]
clip_control: ClipControl,
mask: Cow<'a, Mask>,
viewport: Cow<'a, Viewport>,
scissor: Cow<'a, Scissor>,
blend: Cow<'a, Blend>,
stencil: Cow<'a, Stencil>,
#[cfg(not(any(feature = "gles", feature="webgl")))]
clip_distance: Cow<'a, ClipDistance>,
raster: Cow<'a, Box<Raster>>,
buffers: Cow<'a, Box<Buffers>>,
buffers_indexed: Cow<'a, Box<BuffersIndexed>>,
}
impl<'a> StateInner<'a>{
fn shallow_clone(&self) -> StateInner{
StateInner{
enable: self.enable,
depth: self.depth,
program: self.program.clone(),
vao: self.vao.clone(),
fbo: self.fbo,
#[cfg(all(not(feature = "gles"), not(feature="webgl"), not(target="macos")))]
clip_control: self.clip_control,
mask: Cow::Borrowed(self.mask.as_ref()),
viewport: Cow::Borrowed(self.viewport.as_ref()),
blend: Cow::Borrowed(self.blend.as_ref()),
stencil: Cow::Borrowed(self.stencil.as_ref()),
scissor: Cow::Borrowed(self.scissor.as_ref()),
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
clip_distance: Cow::Borrowed(self.clip_distance.as_ref()),
raster: Cow::Borrowed(self.raster.as_ref()),
buffers: Cow::Borrowed(self.buffers.as_ref()),
buffers_indexed: Cow::Borrowed(self.buffers_indexed.as_ref()),
}
}
}
#[derive(Clone, Debug)]
pub struct State<'a>{
inner: StateInner<'a>,
gl: Rc<GlDebugWrapper>,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum DebugSeverity{
High = 0,
Medium = 1,
Low = 2,
Notification = 3,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl DebugSeverity{
pub fn from_gl_enum(severity: GLenum) -> DebugSeverity{
match severity{
gl::DEBUG_SEVERITY_HIGH => DebugSeverity::High,
gl::DEBUG_SEVERITY_MEDIUM => DebugSeverity::Medium,
gl::DEBUG_SEVERITY_LOW => DebugSeverity::Low,
gl::DEBUG_SEVERITY_NOTIFICATION => DebugSeverity::Notification,
_ => panic!("Unkown debug severity {}", severity)
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DebugSource{
Api = gl::DEBUG_SOURCE_API,
WindowSystem = gl::DEBUG_SOURCE_WINDOW_SYSTEM,
ShaderCompiler = gl::DEBUG_SOURCE_SHADER_COMPILER,
ThirdParty = gl::DEBUG_SOURCE_THIRD_PARTY,
Application = gl::DEBUG_SOURCE_APPLICATION,
Other = gl::DEBUG_SOURCE_OTHER,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[repr(u32)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DebugType{
Error = gl::DEBUG_TYPE_ERROR,
DeprecatedBehaviour = gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR,
UndefinedBehaviour = gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR,
Portability = gl::DEBUG_TYPE_PORTABILITY,
Performance = gl::DEBUG_TYPE_PERFORMANCE,
Marker = gl::DEBUG_TYPE_MARKER,
PushGroup = gl::DEBUG_TYPE_PUSH_GROUP,
PopGroup = gl::DEBUG_TYPE_POP_GROUP,
Other = gl::DEBUG_TYPE_OTHER,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Clone, Debug)]
pub struct DebugInfo{
pub source: DebugSource,
pub ty: DebugType,
pub id: GLuint,
pub severity: DebugSeverity,
pub message: String,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
extern "system" fn gl_debug_async_callback(source: GLenum, ty: GLenum, id: GLuint, severity: GLenum, _length: GLsizei, message: *const GLchar, user: *mut c_void){
unsafe{
let message = CStr::from_ptr(message);
let callback: &DebugAsyncFn = &*(user as *const DebugAsyncFn);
let debug_info = DebugInfo{
source: mem::transmute(source),
ty: mem::transmute(ty),
id,
severity: DebugSeverity::from_gl_enum(severity),
message: message.to_str().unwrap().to_string(),
};
(*callback.func)(debug_info)
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
extern "system" fn gl_debug_sync_callback(source: GLenum, ty: GLenum, id: GLuint, severity: GLenum, _length: GLsizei, message: *const GLchar, user: *mut c_void){
unsafe{
let message = CStr::from_ptr(message);
let callback: &DebugSyncFn = &*(user as *const DebugSyncFn);
let debug_info = DebugInfo{
source: mem::transmute(source),
ty: mem::transmute(ty),
id,
severity: DebugSeverity::from_gl_enum(severity),
message: message.to_str().unwrap().to_string(),
};
(*callback.func)(debug_info)
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Clone)]
pub struct DebugAsyncFn{
func: Arc<dyn Fn(DebugInfo) + Send + Sync>,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl Debug for DebugAsyncFn{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str("debug function")
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl PartialEq for DebugAsyncFn{
fn eq(&self, other: &Self) -> bool{
&*self.func as *const _ == &*other.func as *const _
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl PartialOrd for DebugAsyncFn{
fn partial_cmp(&self, other: &Self) -> Option<Ordering>{
(&*self.func as *const _ as *const c_void)
.partial_cmp(&(&*other.func as *const _ as *const c_void))
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Clone)]
pub struct DebugSyncFn{
func: Rc<dyn Fn(DebugInfo)>,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl Debug for DebugSyncFn{
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
fmt.write_str("debug function")
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl PartialEq for DebugSyncFn{
fn eq(&self, other: &Self) -> bool{
&*self.func as *const _ == &*other.func as *const _
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl PartialOrd for DebugSyncFn{
fn partial_cmp(&self, other: &Self) -> Option<Ordering>{
(&*self.func as *const _ as *const c_void)
.partial_cmp(&(&*other.func as *const _ as *const c_void))
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub enum Property{
Blend(bool),
ClipDistance(Vec<u32>),
#[cfg(not(target="macos"))]
ClipControl(GLenum, GLenum),
ColorLogicOp(Option<GLenum>),
CullFace(Option<GLenum>),
FrontFace(GLenum),
_DebugOutput(Option<DebugAsyncFn>),
_DebugOutputSynchronous(Option<DebugSyncFn>),
DepthClamp(bool),
DepthTest(bool),
Dither(bool),
LineSmooth(bool),
Multisample(bool),
PolygonOffsetFill(Option<(f32, f32)>),
PolygonOffsetLine(Option<(f32, f32)>),
PolygonOffsetPoint(Option<(f32, f32)>),
PolygonSmooth(bool),
RasterizerDiscard(bool),
SampleAlphaToCoverage(bool),
SampleAlphaToOne(bool),
SampleCoverage(Option<(GLclampf, bool)>),
StencilMask(GLuint),
Scissor(Option<Rect>),
StencilTest(bool),
StencilFunc(GLenum, GLint, GLuint),
StencilOp(GLenum,GLenum,GLenum),
ProgramPointSize(bool),
ClearColor([GLclampf;4]),
ClearDepth(GLclampf),
ClearStencil(GLint),
ColorMask([bool;4]),
TextureCubemapSeamless(bool),
BlendEquation(GLenum),
BlendFunc(GLenum,GLenum),
BlendFuncSeparate(GLenum,GLenum,GLenum,GLenum),
BlendColor([GLclampf;4]),
DepthFunc(GLenum),
DepthMask(bool),
DepthRange(f32, f32),
LineWidth(GLfloat),
PointSize(GLfloat),
PolygonMode(GLenum),
Viewport(Rect),
_BufferBaseBinding{
target: GLenum,
index: GLuint,
binding: BufferRangeBind,
}
}
impl Eq for Property{}
impl Ord for Property{
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[allow(non_snake_case)]
impl Property {
pub fn DebugOutputSynchronous<F: Fn(DebugInfo) + 'static>(f: F) -> Property{
let debug_callback = DebugSyncFn{
func: Rc::new(f)
};
Property::_DebugOutputSynchronous(Some(debug_callback))
}
pub fn DebugOutputAsynchronous<F: Fn(DebugInfo) + Send + Sync + 'static>(f: F) -> Property{
let debug_callback = DebugAsyncFn{
func: Arc::new(f)
};
Property::_DebugOutput(Some(debug_callback))
}
pub fn DebugOutputStdoutSynchronous(minseverity: DebugSeverity) -> Property{
Property::DebugOutputSynchronous(move |debug_info|{
if debug_info.severity <= minseverity {
println!("[{:?} - {:?}] {:?}: {}", debug_info.severity, debug_info.ty, debug_info.source, debug_info.message)
}
})
}
pub fn DebugOutputStdoutAsynchronous(minseverity: DebugSeverity) -> Property{
Property::DebugOutputAsynchronous(move |debug_info|{
if debug_info.severity <= minseverity {
println!("[{:?} - {:?}] {:?}: {}", debug_info.severity, debug_info.ty, debug_info.source, debug_info.message)
}
})
}
pub fn DebugOutputStderrSynchronous(minseverity: DebugSeverity) -> Property{
Property::DebugOutputSynchronous(move |debug_info|{
if debug_info.severity <= minseverity {
eprintln!("[{:?} - {:?}] {:?}: {}", debug_info.severity, debug_info.ty, debug_info.source, debug_info.message)
}
})
}
pub fn DebugOutputStderrAsynchronous(minseverity: DebugSeverity) -> Property{
Property::DebugOutputAsynchronous(move |debug_info|{
if debug_info.severity <= minseverity {
eprintln!("[{:?} - {:?}] {:?}: {}", debug_info.severity, debug_info.ty, debug_info.source, debug_info.message)
}
})
}
pub fn DebugOutputDisabled() -> Property{
Property::_DebugOutput(None)
}
pub fn BufferBaseBinding<T, B: ::BufferRange<T>>(target: GLenum, index: GLuint, buffer: B) -> Property{
Property::_BufferBaseBinding{
target,
index,
binding: BufferRangeBind{
buffer: buffer.id(),
offset: (buffer.start() * mem::size_of::<T>()) as GLintptr,
size: (buffer.len() * mem::size_of::<T>()) as GLsizeiptr,
}
}
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[cfg(any(feature = "gles", feature="webgl"))]
pub enum Property{
Blend(bool),
CullFace(Option<GLenum>),
FrontFace(GLenum),
DepthTest(bool),
Dither(bool),
PolygonOffsetFill(Option<(f32, f32)>),
RasterizerDiscard(bool),
SampleAlphaToCoverage(bool),
SampleCoverage(Option<(GLclampf, bool)>),
StencilMask(GLuint),
Scissor(Option<Rect>),
StencilTest(bool),
StencilFunc(GLenum, GLint, GLuint),
StencilOp(GLenum,GLenum,GLenum),
ClearColor([GLclampf;4]),
ClearDepth(GLclampf),
ClearStencil(GLint),
ColorMask([bool;4]),
BlendEquation(GLenum),
BlendFunc(GLenum,GLenum),
BlendFuncSeparate(GLenum,GLenum,GLenum,GLenum),
BlendColor([GLclampf;4]),
DepthFunc(GLenum),
DepthMask(bool),
DepthRange(f32, f32),
LineWidth(GLfloat),
Viewport(Rect),
_BufferBaseBinding{
target: GLenum,
index: GLuint,
binding: BufferRangeBind,
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
#[allow(non_snake_case)]
impl Property {
pub fn BufferBaseBinding<T, B: ::BufferRange<T>>(target: GLenum, index: GLuint, buffer: B) -> Property{
Property::_BufferBaseBinding{
target,
index,
binding: BufferRangeBind{
buffer: buffer.id(),
offset: (buffer.start() * mem::size_of::<T>()) as GLintptr,
size: (buffer.len() * mem::size_of::<T>()) as GLsizeiptr,
}
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
mod bits{
use gl;
use gl::types::GLenum;
pub const COUNT: u32 = 22;
bitflags!{
pub struct EnableFlags: u32{
const BLEND = 1;
const COLOR_LOGIC_OP = 1 << 1;
const CULL_FACE = 1 << 2;
const DEBUG_OUTPUT = 1 << 3;
const DEBUG_OUTPUT_SYNCHRONOUS = 1 << 4;
const DEPTH_CLAMP = 1 << 5;
const DEPTH_TEST = 1 << 6;
const DITHER = 1 << 7;
const LINE_SMOOTH = 1 << 8;
const MULTISAMPLE = 1 << 9;
const POLYGON_OFFSET_FILL = 1 << 10;
const POLYGON_OFFSET_LINE = 1 << 11;
const POLYGON_OFFSET_POINT = 1 << 12;
const POLYGON_SMOOTH = 1 << 13;
const RASTERIZER_DISCARD = 1 << 14;
const SAMPLE_ALPHA_TO_COVERAGE = 1 << 15;
const SAMPLE_ALPHA_TO_ONE = 1 << 16;
const SAMPLE_COVERAGE = 1 << 17;
const STENCIL_TEST = 1 << 18;
const SCISSOR_TEST = 1 << 19;
const TEXTURE_CUBE_MAP_SEAMLESS = 1 << 20;
const PROGRAM_POINT_SIZE = 1 << 21;
}
}
impl EnableFlags{
pub fn to_gl(self) -> GLenum{
match self{
EnableFlags::BLEND => gl::BLEND,
EnableFlags::COLOR_LOGIC_OP => gl::COLOR_LOGIC_OP,
EnableFlags::CULL_FACE => gl::CULL_FACE,
EnableFlags::DEBUG_OUTPUT => gl::DEBUG_OUTPUT,
EnableFlags::DEBUG_OUTPUT_SYNCHRONOUS => gl::DEBUG_OUTPUT_SYNCHRONOUS,
EnableFlags::DEPTH_CLAMP => gl::DEPTH_CLAMP,
EnableFlags::DEPTH_TEST => gl::DEPTH_TEST,
EnableFlags::DITHER => gl::DITHER,
EnableFlags::LINE_SMOOTH => gl::LINE_SMOOTH,
EnableFlags::MULTISAMPLE => gl::MULTISAMPLE,
EnableFlags::POLYGON_OFFSET_FILL => gl::POLYGON_OFFSET_FILL,
EnableFlags::POLYGON_OFFSET_LINE => gl::POLYGON_OFFSET_LINE,
EnableFlags::POLYGON_OFFSET_POINT => gl::POLYGON_OFFSET_POINT,
EnableFlags::POLYGON_SMOOTH => gl::POLYGON_SMOOTH,
EnableFlags::RASTERIZER_DISCARD => gl::RASTERIZER_DISCARD,
EnableFlags::SAMPLE_ALPHA_TO_COVERAGE => gl::SAMPLE_ALPHA_TO_COVERAGE,
EnableFlags::SAMPLE_ALPHA_TO_ONE => gl::SAMPLE_ALPHA_TO_ONE,
EnableFlags::SAMPLE_COVERAGE => gl::SAMPLE_COVERAGE,
EnableFlags::STENCIL_TEST => gl::STENCIL_TEST,
EnableFlags::SCISSOR_TEST => gl::SCISSOR_TEST,
EnableFlags::TEXTURE_CUBE_MAP_SEAMLESS => gl::TEXTURE_CUBE_MAP_SEAMLESS,
EnableFlags::PROGRAM_POINT_SIZE => gl::PROGRAM_POINT_SIZE,
_ => unreachable!(),
}
}
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
mod bits{
use gl;
use gl::types::GLenum;
pub const COUNT: usize = 10;
bitflags!{
pub struct EnableFlags: u32{
const BLEND = 1;
const CULL_FACE = 1 << 1;
const DEPTH_TEST = 1 << 2;
const DITHER = 1 << 3;
const POLYGON_OFFSET_FILL = 1 << 4;
const RASTERIZER_DISCARD = 1 << 5;
const SAMPLE_ALPHA_TO_COVERAGE = 1 << 6;
const SAMPLE_COVERAGE = 1 << 7;
const STENCIL_TEST = 1 << 8;
const SCISSOR_TEST = 1 << 9;
}
}
impl EnableFlags{
pub fn to_gl(self) -> GLenum{
match self{
EnableFlags::BLEND => gl::BLEND,
EnableFlags::CULL_FACE => gl::CULL_FACE,
EnableFlags::DEPTH_TEST => gl::DEPTH_TEST,
EnableFlags::DITHER => gl::DITHER,
EnableFlags::POLYGON_OFFSET_FILL => gl::POLYGON_OFFSET_FILL,
EnableFlags::RASTERIZER_DISCARD => gl::RASTERIZER_DISCARD,
EnableFlags::SAMPLE_ALPHA_TO_COVERAGE => gl::SAMPLE_ALPHA_TO_COVERAGE,
EnableFlags::SAMPLE_COVERAGE => gl::SAMPLE_COVERAGE,
EnableFlags::STENCIL_TEST => gl::STENCIL_TEST,
EnableFlags::SCISSOR_TEST => gl::SCISSOR_TEST,
_ => unreachable!(),
}
}
}
}
impl<'a> State<'a>{
pub fn shallow_clone(&self) -> State{
State{
inner: self.inner.shallow_clone(),
gl: self.gl.clone(),
}
}
#[inline]
pub fn set_program(&self, program: &program::Program){
self.inner.program.set(program.id());
}
#[inline]
pub unsafe fn set_program_id(&self, program: u32){
self.inner.program.set(program);
}
#[inline]
pub unsafe fn set_vao(&self, vao: GLuint){
self.inner.vao.set(vao);
}
#[inline]
pub unsafe fn set_buffer_binding(&mut self, target: GLenum, buffer: GLuint){
let buffers = self.inner.buffers.to_mut();
match target{
gl::ARRAY_BUFFER => buffers.array = buffer,
#[cfg(not(feature = "webgl"))]
gl::ATOMIC_COUNTER_BUFFER => buffers.atomic_counter = buffer,
gl::COPY_READ_BUFFER => buffers.copy_read = buffer,
gl::COPY_WRITE_BUFFER => buffers.copy_write = buffer,
#[cfg(not(feature = "webgl"))]
gl::DISPATCH_INDIRECT_BUFFER => buffers.dispatch_indirect = buffer,
#[cfg(not(feature = "webgl"))]
gl::DRAW_INDIRECT_BUFFER => buffers.draw_indirect = buffer,
gl::ELEMENT_ARRAY_BUFFER => buffers.element_array = buffer,
gl::PIXEL_PACK_BUFFER => buffers.pixel_pack = buffer,
gl::PIXEL_UNPACK_BUFFER => buffers.pixel_unpack = buffer,
#[cfg(not(feature = "webgl"))]
gl::SHADER_STORAGE_BUFFER => buffers.shader_storage = buffer,
#[cfg(not(feature = "webgl"))]
gl::TEXTURE_BUFFER => buffers.texture = buffer,
gl::TRANSFORM_FEEDBACK_BUFFER => buffers.transform_feedback = buffer,
gl::UNIFORM_BUFFER => buffers.uniform = buffer,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
gl::QUERY_BUFFER => buffers.query = buffer,
_ => panic!("Trying to bind unkown buffer target {:x}", target),
}
}
pub unsafe fn set_buffer_base_binding(&mut self,
target: GLenum,
index: u32,
buffer: GLuint,
offset: GLintptr,
size: GLsizeiptr)
{
let binding = BufferRangeBind{
buffer,
offset,
size
};
self.inner.buffers_indexed.to_mut().set(target, index, binding)
}
pub fn bind_buffer(&mut self, target: GLenum, buffer: GLuint){
if (target == gl::ARRAY_BUFFER || target == gl::ELEMENT_ARRAY_BUFFER) &&
self.inner.vao.id() != 0
{
self.inner.vao.apply(&self.gl, Vao{id: Cell::new(0) });
}
self.inner.buffers.to_mut().bind(&self.gl, target, buffer);
}
pub fn bind_base_buffer(&mut self, target: GLenum, index: u32, buffer: GLuint, offset: GLintptr, size: GLsizeiptr){
let binding = BufferRangeBind{
buffer,
offset,
size,
};
self.inner.buffers_indexed.to_mut().bind(&self.gl, target, index, binding);
}
pub fn bind_vao(&mut self, vao: GLuint){
if self.inner.vao.id() != vao {
self.inner.vao.apply(&self.gl, Vao{ id: Cell::new(vao) });
}
}
pub fn bind_program(&mut self, program: GLuint){
if self.inner.program.id.get() != program {
self.inner.program.apply(&self.gl, Program{id: Cell::new(program)});
}
}
#[inline]
pub fn set_fbo(&mut self, draw: GLuint, read: GLuint){
if self.inner.fbo.draw() != draw || self.inner.fbo.read() != read {
self.inner.fbo.apply(&self.gl, Fbo{ draw, read })
}
}
#[inline]
pub fn from_buffer_binding(original: &'a State, target: GLenum, buffer: GLuint) -> State<'a> {
let mut state = original.shallow_clone();
unsafe{
state.set_buffer_binding(target, buffer)
};
state
}
#[inline]
pub fn from_buffer_base_binding(original: &'a State,
target: GLenum,
index: u32,
buffer: GLuint,
offset: GLintptr,
size: GLsizeiptr) -> State<'a>
{
let mut state = original.shallow_clone();
unsafe{
state.set_buffer_base_binding(target, index, buffer, offset, size)
};
state
}
#[inline]
pub fn from_properties_fbo_draw<'p, P, C>(original: &'a State, properties: P, fbo: &::Fbo<C>) -> State<'a>
where P: IntoIterator<Item = &'p Property>
{
let mut state = original.with_properties(properties);
state.inner.fbo.draw = fbo.id();
state
}
#[inline]
pub fn from_properties_fbo_read<'p, P, C>(original: &'a State, properties: P, fbo: &::Fbo<C>) -> State<'a>
where P: IntoIterator<Item = &'p Property>
{
let mut state = original.with_properties(properties);
state.inner.fbo.read = fbo.id();
state
}
#[inline]
pub fn from_properties_fbo_draw_id<'p, P, F>(original: &'a State, properties: P, fbo: &F) -> State<'a>
where P: IntoIterator<Item = &'p Property>,
F: UntypedOffscreenBuffer,
{
let mut state = original.with_properties(properties);
state.inner.fbo.draw = fbo.id();
state
}
#[inline]
pub fn set_properties_fbo_draw_id<'p, P, F>(original: &mut State<'a>, properties: P, fbo: &F)
where P: IntoIterator<Item = &'p Property>,
F: UntypedOffscreenBuffer,
{
original.set_properties(properties);
original.inner.fbo.draw = fbo.id();
}
#[inline]
pub fn from_properties_fbo_read_id<'p, P, F>(original: &'a State, properties: P, fbo: &F) -> State<'a>
where P: IntoIterator<Item = &'a Property>,
F: UntypedOffscreenBuffer,
{
let mut state = original.with_properties(properties);
state.inner.fbo.read = fbo.id();
state
}
#[inline]
pub fn from_properties_fbo<'p, P>(original: &'a State, properties: P, draw: GLuint, read: GLuint) -> State<'a>
where P: IntoIterator<Item = &'p Property>
{
let mut state = original.with_properties(properties);
state.inner.fbo.draw = draw;
state.inner.fbo.read = read;
state
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[allow(clippy::float_cmp)]
pub fn set_properties<'p, P>(&mut self, properties: P)
where P: IntoIterator<Item = &'p Property>
{
let depth_func = &mut self.inner.depth.func;
let mask = &mut self.inner.mask;
let raster = &mut self.inner.raster;
let blend = &mut self.inner.blend;
let viewport = &mut self.inner.viewport;
let stencil = &mut self.inner.stencil;
let scissor = &mut self.inner.scissor;
let clip_distance = &mut self.inner.clip_distance;
let buffers_indexed = &mut self.inner.buffers_indexed;
let bits = &mut self.inner.enable.state_bits;
#[cfg(not(target="macos"))]
let mut clip_control = self.inner.clip_control;
for p in properties.into_iter(){
use Property::*;
match *p {
Blend(enable) => bits.set(bits::EnableFlags::BLEND, enable),
ColorLogicOp(c) => match c{
Some(_op) => bits.insert(bits::EnableFlags::COLOR_LOGIC_OP),
None => bits.remove(bits::EnableFlags::COLOR_LOGIC_OP),
},
CullFace(f) => match f{
Some(f) => {
raster.to_mut().cull_face = f;
bits.insert(bits::EnableFlags::CULL_FACE)
}
None => bits.remove(bits::EnableFlags::CULL_FACE),
},
ColorMask(color_mask) => {
let mask = mask.to_mut();
mask.r = color_mask[0];
mask.g = color_mask[1];
mask.b = color_mask[2];
mask.a = color_mask[3];
}
DepthMask(depth_mask) => {
mask.to_mut().d = depth_mask;
}
StencilMask(stencil_mask) => {
mask.to_mut().s = stencil_mask;
}
_DebugOutput(None) => bits.remove(bits::EnableFlags::DEBUG_OUTPUT),
_DebugOutput(Some(ref func)) => {
unsafe{
self.gl.DebugMessageCallback(
Some(gl_debug_async_callback),
mem::transmute(Box::new(func.clone()))
);
self.gl.Disable(gl::DEBUG_OUTPUT_SYNCHRONOUS);
}
bits.insert(bits::EnableFlags::DEBUG_OUTPUT);
}
_DebugOutputSynchronous(Some(ref func)) => {
unsafe{
self.gl.DebugMessageCallback(
Some(gl_debug_sync_callback),
mem::transmute(Box::new(func.clone()))
);
self.gl.Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS);
}
bits.insert(bits::EnableFlags::DEBUG_OUTPUT);
}
DepthClamp(enable) => bits.set(bits::EnableFlags::DEPTH_CLAMP, enable),
DepthTest(enable) => bits.set(bits::EnableFlags::DEPTH_TEST, enable),
DepthFunc(func) => *depth_func = func,
Dither(enable) => bits.set(bits::EnableFlags::DITHER, enable),
LineSmooth(enable) => bits.set(bits::EnableFlags::LINE_SMOOTH, enable),
Multisample(enable) => bits.set(bits::EnableFlags::MULTISAMPLE, enable),
PolygonOffsetFill(polygon_offset) => match polygon_offset{
Some((factor, units)) => {
if raster.poly_offset_factor != factor || raster.poly_offset_units != units{
let raster = raster.to_mut();
raster.poly_offset_factor = factor;
raster.poly_offset_units = units;
}
bits.insert(bits::EnableFlags::POLYGON_OFFSET_FILL);
}
None => bits.remove(bits::EnableFlags::POLYGON_OFFSET_FILL),
},
PolygonOffsetLine(polygon_offset) => match polygon_offset{
Some((factor, units)) => {
if raster.poly_offset_factor != factor || raster.poly_offset_units != units{
let raster = raster.to_mut();
raster.poly_offset_factor = factor;
raster.poly_offset_units = units;
}
bits.insert(bits::EnableFlags::POLYGON_OFFSET_LINE);
}
None => bits.remove(bits::EnableFlags::POLYGON_OFFSET_LINE),
},
PolygonOffsetPoint(polygon_offset) => match polygon_offset{
Some((factor, units)) => {
if raster.poly_offset_factor != factor || raster.poly_offset_units != units{
let raster = raster.to_mut();
raster.poly_offset_factor = factor;
raster.poly_offset_units = units;
}
bits.insert(bits::EnableFlags::POLYGON_OFFSET_POINT)
}
None => bits.remove(bits::EnableFlags::POLYGON_OFFSET_POINT),
},
PolygonMode(mode) => {
if raster.poly_mode != mode {
raster.to_mut().poly_mode = mode;
}
},
BlendEquation(e) => {
if blend.equation != e {
blend.to_mut().equation = e;
}
}
BlendFunc(s,d) => {
if blend.func_src_rgb != s
|| blend.func_dst_rgb != d
|| blend.func_src_alpha != s
|| blend.func_dst_alpha != d
{
let blend = blend.to_mut();
blend.func_src_rgb = s;
blend.func_dst_rgb = d;
blend.func_src_alpha = s;
blend.func_dst_alpha = d;
}
}
BlendFuncSeparate(s_rgb,d_rgb,s_a,d_a) => {
if blend.func_src_rgb != s_rgb
|| blend.func_dst_rgb != d_rgb
|| blend.func_src_alpha != s_a
|| blend.func_dst_alpha != d_a
{
let blend = blend.to_mut();
blend.func_src_rgb = s_rgb;
blend.func_dst_rgb = d_rgb;
blend.func_src_alpha = s_a;
blend.func_dst_alpha = d_a;
}
}
BlendColor(c) => {
if blend.color != c {
blend.to_mut().color = c;
}
}
PolygonSmooth(enable) => bits.set(bits::EnableFlags::POLYGON_SMOOTH, enable),
RasterizerDiscard(enable) =>
bits.set(bits::EnableFlags::RASTERIZER_DISCARD, enable),
SampleAlphaToCoverage(enable) =>
bits.set(bits::EnableFlags::SAMPLE_ALPHA_TO_COVERAGE, enable),
SampleAlphaToOne(enable) =>
bits.set(bits::EnableFlags::SAMPLE_ALPHA_TO_ONE, enable),
SampleCoverage(Some((value, invert))) => {
if raster.sample_coverage != value || raster.sample_coverage_invert != invert {
let raster = raster.to_mut();
raster.sample_coverage = value;
raster.sample_coverage_invert = invert;
}
bits.insert(bits::EnableFlags::SAMPLE_COVERAGE)
},
SampleCoverage(None) => bits.remove(bits::EnableFlags::SAMPLE_COVERAGE),
StencilTest(enable) => bits.set(bits::EnableFlags::STENCIL_TEST, enable),
StencilFunc(func, reference, mask) => {
if stencil.func != func || stencil.reference != reference || stencil.mask != mask{
let stencil = stencil.to_mut();
stencil.func = func;
stencil.reference = reference;
stencil.mask = mask;
}
}
StencilOp(sfail,dpfail,dppass) => {
if stencil.sfail != sfail || stencil.dpfail != dpfail || stencil.dppass != dppass{
let stencil = stencil.to_mut();
stencil.sfail = sfail;
stencil.dpfail = dpfail;
stencil.dppass = dppass;
}
}
Scissor(Some(rect)) => {
*scissor.to_mut() = unsafe{ mem::transmute(rect) };
bits.insert(bits::EnableFlags::SCISSOR_TEST)
}
Scissor(None) => bits.remove(bits::EnableFlags::SCISSOR_TEST),
TextureCubemapSeamless(enable) =>
bits.set(bits::EnableFlags::TEXTURE_CUBE_MAP_SEAMLESS, enable),
ProgramPointSize(enable) => bits.set(bits::EnableFlags::PROGRAM_POINT_SIZE, enable),
Viewport(v) => {
*viewport.to_mut() = unsafe{ mem::transmute(v) };
}
ClipDistance(ref enable) => {
let mut enable = enable.clone();
enable.sort();
let mut enable = enable.into_iter().peekable();
let clip_distance = clip_distance.to_mut();
for (i, enabled) in clip_distance.enabled.iter_mut().enumerate() {
if let Some(&next) = enable.peek(){
if i == next as usize {
*enabled = true;
enable.next();
}else if i < next as usize {
*enabled = false;
}
}else{
*enabled = false;
}
};
}
#[cfg(not(target="macos"))]
ClipControl(origin, depth) => {
clip_control.origin = origin;
clip_control.depth = depth;
}
_BufferBaseBinding{target, index, binding} => {
if buffers_indexed.binding(target, index).map(|b| *b != binding).unwrap_or(true) {
buffers_indexed.to_mut().set(target, index, binding);
}
},
_ => ()
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[allow(clippy::float_cmp)]
pub fn with_properties<'p, P>(&self, properties: P) -> State
where P: IntoIterator<Item = &'p Property>
{
let depth_func = self.inner.depth.func;
let mask = Cow::Borrowed(self.inner.mask.as_ref());
let raster = Cow::Borrowed(self.inner.raster.as_ref());
let blend = Cow::Borrowed(self.inner.blend.as_ref());
let viewport = Cow::Borrowed(self.inner.viewport.as_ref());
let stencil = Cow::Borrowed(self.inner.stencil.as_ref());
let scissor = Cow::Borrowed(self.inner.scissor.as_ref());
let clip_distance = Cow::Borrowed(self.inner.clip_distance.as_ref());
let buffers_indexed = Cow::Borrowed(self.inner.buffers_indexed.as_ref());
let bits = self.inner.enable.state_bits;
#[cfg(not(target="macos"))]
let clip_control = self.inner.clip_control;
let mut state = State{
inner: StateInner{
enable: Enable{
state_bits: bits
},
program: self.inner.program.clone(),
vao: self.inner.vao.clone(),
depth: Depth{
func: depth_func,
},
raster,
blend,
viewport,
scissor,
stencil,
mask,
fbo: self.inner.fbo,
clip_distance,
#[cfg(not(target="macos"))]
clip_control,
buffers: Cow::Borrowed(self.inner.buffers.as_ref()),
buffers_indexed: buffers_indexed,
},
gl: self.gl.clone(),
};
state.set_properties(properties);
state
}
#[inline]
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn set_properties<'p, P>(&mut self, properties: P)
where P: IntoIterator<Item = &'p Property>
{
let bits = &mut self.inner.enable.state_bits;
let depth_func = &mut self.inner.depth.func;
let raster = &mut self.inner.raster;
let blend = &mut self.inner.blend;
let viewport = &mut self.inner.viewport;
let stencil = &mut self.inner.stencil;
let mask = &mut self.inner.mask;
let scissor = &mut self.inner.scissor;
let buffers_indexed = &mut self.inner.buffers_indexed;
for p in properties.into_iter(){
use Property::*;
match *p {
Blend(enable) => bits.set(bits::EnableFlags::BLEND, enable),
CullFace(f) => match f{
Some(f) => {
raster.to_mut().cull_face = f;
bits.insert(bits::EnableFlags::CULL_FACE)
}
None => bits.remove(bits::EnableFlags::CULL_FACE),
},
ColorMask(color_mask) => {
let mask = mask.to_mut();
mask.r = color_mask[0];
mask.g = color_mask[1];
mask.b = color_mask[2];
mask.a = color_mask[3];
}
DepthMask(depth_mask) => {
mask.to_mut().d = depth_mask;
}
StencilMask(stencil_mask) => {
mask.to_mut().s = stencil_mask;
}
DepthTest(enable) => bits.set(bits::EnableFlags::DEPTH_TEST, enable),
DepthFunc(func) => {
*depth_func = func;
}
Dither(enable) => bits.set(bits::EnableFlags::DITHER, enable),
PolygonOffsetFill(polygon_offset) => match polygon_offset{
Some((factor, units)) => {
let raster = raster.to_mut();
raster.poly_offset_factor = factor;
raster.poly_offset_units = units;
bits.insert(bits::EnableFlags::POLYGON_OFFSET_FILL)
}
None => bits.remove(bits::EnableFlags::POLYGON_OFFSET_FILL),
},
SampleAlphaToCoverage(enable) =>
bits.set(bits::EnableFlags::SAMPLE_ALPHA_TO_COVERAGE, enable),
SampleCoverage(Some((value, invert))) => {
let raster = raster.to_mut();
raster.sample_coverage = value;
raster.sample_coverage_invert = invert;
bits.insert(bits::EnableFlags::SAMPLE_COVERAGE)
},
SampleCoverage(None) => bits.remove(bits::EnableFlags::SAMPLE_COVERAGE),
BlendEquation(e) => {
blend.to_mut().equation = e;
}
BlendFunc(s,d) => {
if blend.func_src_rgb != s
|| blend.func_dst_rgb != d
|| blend.func_src_alpha != s
|| blend.func_dst_alpha != d
{
let blend = blend.to_mut();
blend.func_src_rgb = s;
blend.func_dst_rgb = d;
blend.func_src_alpha = s;
blend.func_dst_alpha = d;
}
}
BlendFuncSeparate(s_rgb,d_rgb,s_a,d_a) => {
if blend.func_src_rgb != s_rgb
|| blend.func_dst_rgb != d_rgb
|| blend.func_src_alpha != s_a
|| blend.func_dst_alpha != d_a
{
let blend = blend.to_mut();
blend.func_src_rgb = s_rgb;
blend.func_dst_rgb = d_rgb;
blend.func_src_alpha = s_a;
blend.func_dst_alpha = d_a;
}
}
BlendColor(c) => {
blend.to_mut().color = c;
}
StencilTest(enable) => bits.set(bits::EnableFlags::STENCIL_TEST, enable),
StencilFunc(func, reference, mask) => {
let stencil = stencil.to_mut();
stencil.func = func;
stencil.reference = reference;
stencil.mask = mask;
}
StencilOp(sfail,dpfail,dppass) => {
let stencil = stencil.to_mut();
stencil.sfail = sfail;
stencil.dpfail = dpfail;
stencil.dppass = dppass;
}
Scissor(Some(rect)) => {
*scissor.to_mut() = unsafe{ mem::transmute(rect) };
bits.insert(bits::EnableFlags::SCISSOR_TEST)
}
Scissor(None) => bits.remove(bits::EnableFlags::SCISSOR_TEST),
Viewport(v) => {
*viewport.to_mut() = unsafe{ mem::transmute(v) };
}
_BufferBaseBinding{target, index, binding} => {
buffers_indexed.to_mut().set(target, index, binding);
}
_ => ()
}
}
}
#[inline]
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn with_properties<'p, P>(&self, properties: P) -> State
where P: IntoIterator<Item = &'p Property>
{
let bits = self.inner.enable.state_bits;
let depth_func = self.inner.depth.func;
let raster = Cow::Borrowed(self.inner.raster.as_ref());
let blend = Cow::Borrowed(self.inner.blend.as_ref());
let viewport = Cow::Borrowed(self.inner.viewport.as_ref());
let stencil = Cow::Borrowed(self.inner.stencil.as_ref());
let mask = Cow::Borrowed(self.inner.mask.as_ref());
let scissor = Cow::Borrowed(self.inner.scissor.as_ref());
let buffers_indexed = Cow::Borrowed(self.inner.buffers_indexed.as_ref());
let mut state = State{
inner: StateInner{
enable: Enable{
state_bits: bits
},
program: self.inner.program.clone(),
vao: self.inner.vao.clone(),
depth: Depth{
func: depth_func,
},
raster: raster,
blend: blend,
viewport: viewport,
scissor,
stencil: stencil,
mask: mask,
fbo: self.inner.fbo,
buffers: Cow::Borrowed(self.inner.buffers.as_ref()),
buffers_indexed: buffers_indexed,
},
gl: self.gl.clone(),
};
state.set_properties(properties);
state
}
pub fn from_gl(gl: Gl) -> State<'static>{
State{
inner: StateInner{
enable: Enable::from_gl(&gl),
program: Program::from_gl(&gl),
depth: Depth::from_gl(&gl),
blend: Cow::Owned(Blend::from_gl(&gl)),
viewport: Cow::Owned(Viewport::from_gl(&gl)),
scissor: Cow::Owned(Scissor::from_gl(&gl)),
vao: Vao::from_gl(&gl),
stencil: Cow::Owned(Stencil::from_gl(&gl)),
mask: Cow::Owned(Mask::from_gl(&gl)),
fbo: Fbo::from_gl(&gl),
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
clip_distance: Cow::Owned(ClipDistance::from_gl(&gl)),
#[cfg(all(not(feature = "gles"), not(feature="webgl"), not(target="macos")))]
clip_control: ClipControl::from_gl(&gl),
raster: Cow::Owned(Box::new(Raster::from_gl(&gl))),
buffers: Cow::Owned(Box::new(Buffers::from_gl(&gl))),
buffers_indexed: Cow::Owned(Box::new(BuffersIndexed::from_gl(&gl))),
},
gl: Rc::new(GlDebugWrapper(gl)),
}
}
#[inline]
pub fn apply(&mut self, new_state: &State){
if self.inner == new_state.inner{
return;
}
if new_state.inner.enable != self.inner.enable{
self.inner.enable.apply(&self.gl, new_state.inner.enable);
}
if new_state.inner.program != self.inner.program{
self.inner.program.apply(&self.gl, new_state.inner.program.clone());
}
if new_state.inner.depth != self.inner.depth{
self.inner.depth.apply(&self.gl, new_state.inner.depth);
}
if new_state.inner.raster != self.inner.raster{
self.inner.raster.to_mut().apply(&self.gl, &new_state.inner.raster);
}
if new_state.inner.blend != self.inner.blend{
self.inner.blend.to_mut().apply(&self.gl, &new_state.inner.blend);
}
if new_state.inner.viewport != self.inner.viewport{
self.inner.viewport.to_mut().apply(&self.gl, &new_state.inner.viewport);
}
if new_state.inner.scissor != self.inner.scissor{
self.inner.scissor.to_mut().apply(&self.gl, &new_state.inner.scissor);
}
if new_state.inner.vao != self.inner.vao{
self.inner.vao.apply(&self.gl, new_state.inner.vao.clone());
}
if new_state.inner.stencil != self.inner.stencil{
self.inner.stencil.to_mut().apply(&self.gl, &new_state.inner.stencil);
}
if new_state.inner.mask != self.inner.mask{
self.inner.mask.to_mut().apply(&self.gl, &new_state.inner.mask);
}
if new_state.inner.fbo != self.inner.fbo{
self.inner.fbo.apply(&self.gl, new_state.inner.fbo);
}
if new_state.inner.buffers != self.inner.buffers{
self.inner.buffers.to_mut().apply(&self.gl, &new_state.inner.buffers);
}
if new_state.inner.buffers_indexed != self.inner.buffers_indexed{
self.inner.buffers_indexed.to_mut().apply(&self.gl, &new_state.inner.buffers_indexed);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
{
if new_state.inner.clip_distance != self.inner.clip_distance{
self.inner.clip_distance.to_mut().apply(&self.gl, &new_state.inner.clip_distance);
}
if new_state.inner.clip_control != self.inner.clip_control{
#[cfg(not(target="macos"))]
self.inner.clip_control.apply(&self.gl, &new_state.inner.clip_control);
}
}
}
#[inline]
pub fn apply_fbo(&mut self, new_state: &State){
if new_state.inner.fbo != self.inner.fbo{
self.inner.fbo.apply(&self.gl, new_state.inner.fbo);
}
}
#[inline]
pub fn apply_mask(&mut self, new_state: &State){
if new_state.inner.mask != self.inner.mask{
self.inner.mask.to_mut().apply(&self.gl, &new_state.inner.mask);
}
}
pub fn apply_depth(&mut self, new_state: &State){
if new_state.inner.depth != self.inner.depth{
self.inner.depth.apply(&self.gl, new_state.inner.depth);
}
}
pub fn apply_stencil(&mut self, new_state: &State){
if new_state.inner.stencil != self.inner.stencil{
self.inner.stencil.to_mut().apply(&self.gl, &new_state.inner.stencil);
}
}
pub fn apply_enable(&mut self, new_state: &State){
if new_state.inner.enable != self.inner.enable{
self.inner.enable.apply(&self.gl, new_state.inner.enable);
}
}
pub fn apply_scissor(&mut self, new_state: &State){
if new_state.inner.scissor != self.inner.scissor{
self.inner.scissor.to_mut().apply(&self.gl, &new_state.inner.scissor);
let old_scissors = self.inner.enable.state_bits.contains(bits::EnableFlags::SCISSOR_TEST);
let new_scissors = new_state.inner.enable.state_bits.contains(bits::EnableFlags::SCISSOR_TEST);
if old_scissors != new_scissors {
if new_scissors {
self.inner.enable.enable_flag(&self.gl, bits::EnableFlags::SCISSOR_TEST)
}else{
self.inner.enable.disable_flag(&self.gl, bits::EnableFlags::SCISSOR_TEST)
}
}
}
}
pub fn disable_scissors(&mut self) {
self.inner.enable.disable_flag(&self.gl, bits::EnableFlags::SCISSOR_TEST)
}
pub fn program(&self) -> &Program{
&self.inner.program
}
pub fn depth(&self) -> &Depth{
&self.inner.depth
}
pub fn raster(&self) -> &Raster{
&self.inner.raster
}
pub fn blend(&self) -> &Blend{
&self.inner.blend
}
pub fn viewport(&self) -> &Viewport{
&self.inner.viewport
}
pub fn vao(&self) -> &Vao{
&self.inner.vao
}
pub fn fbo(&self) -> &Fbo{
&self.inner.fbo
}
pub fn scissor(&self) -> &Scissor {
&self.inner.scissor
}
pub fn program_mut(&mut self) -> &mut Program{
&mut self.inner.program
}
pub fn depth_mut(&mut self) -> &mut Depth{
&mut self.inner.depth
}
pub fn raster_mut(&mut self) -> &mut Raster{
self.inner.raster.to_mut()
}
pub fn blend_mut(&mut self) -> &mut Blend{
self.inner.blend.to_mut()
}
pub fn viewport_mut(&mut self) -> &mut Viewport{
self.inner.viewport.to_mut()
}
pub fn vao_mut(&mut self) -> &mut Vao{
&mut self.inner.vao
}
pub fn fbo_mut(&mut self) -> &mut Fbo{
&mut self.inner.fbo
}
pub fn scissor_mut(&mut self) -> &mut Scissor {
self.inner.scissor.to_mut()
}
#[inline]
pub unsafe fn set_pixel_store(&self, width: i32){
if GLIN_ROUND_UP_8!(width) == width {
self.gl.PixelStorei (gl::UNPACK_ALIGNMENT, 8);
} else if GLIN_ROUND_UP_4!(width) == width {
self.gl.PixelStorei (gl::UNPACK_ALIGNMENT, 4);
} else if GLIN_ROUND_UP_2!(width) == width {
self.gl.PixelStorei (gl::UNPACK_ALIGNMENT, 2);
} else {
self.gl.PixelStorei (gl::UNPACK_ALIGNMENT, 1);
}
}
pub unsafe fn get_boolean(&self, param: GLenum) -> bool{
let mut value = mem::MaybeUninit::uninit();
self.gl.GetBooleanv(param, value.as_mut_ptr());
value.assume_init() != 0
}
pub unsafe fn get_booleanv(&self, param: GLenum, len: usize) -> Vec<bool>{
let mut value = vec![0; len];
self.gl.GetBooleanv(param, value.as_mut_ptr());
value.into_iter().map(|v| v!=0).collect()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn get_double(&self, param: GLenum) -> f64{
let mut value = mem::MaybeUninit::uninit();
self.gl.GetDoublev(param, value.as_mut_ptr());
value.assume_init()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn get_doublev(&self, param: GLenum, len: usize) -> Vec<f64>{
let mut value = vec![0.;len];
self.gl.GetDoublev(param, value.as_mut_ptr());
value
}
pub unsafe fn get_float(&self, param: GLenum) -> f32{
let mut value = mem::MaybeUninit::uninit();
self.gl.GetFloatv(param, value.as_mut_ptr());
value.assume_init()
}
pub unsafe fn get_floatv(&self, param: GLenum, len: usize) -> Vec<f32>{
let mut value = vec![0.;len];
self.gl.GetFloatv(param, value.as_mut_ptr());
value
}
pub unsafe fn get_int(&self, param: GLenum) -> i32{
let mut value = mem::MaybeUninit::uninit();
self.gl.GetIntegerv(param, value.as_mut_ptr());
value.assume_init()
}
pub unsafe fn get_intv(&self, param: GLenum, len: usize) -> Vec<i32>{
let mut value = vec![0;len];
self.gl.GetIntegerv(param, value.as_mut_ptr());
value
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn get_int64(&self, param: GLenum) -> i64{
let mut value = mem::MaybeUninit::uninit();
self.gl.GetInteger64v(param, value.as_mut_ptr());
value.assume_init()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn get_int64v(&self, param: GLenum, len: usize) -> Vec<i64>{
let mut value = vec![0;len];
self.gl.GetInteger64v(param, value.as_mut_ptr());
value
}
pub fn to_owned(&self) -> State<'static> {
let bits = self.inner.enable.state_bits;
let depth_func = self.inner.depth.func;
let raster = Cow::Owned(self.inner.raster.as_ref().clone());
let blend = Cow::Owned(self.inner.blend.as_ref().clone());
let viewport = Cow::Owned(self.inner.viewport.as_ref().clone());
let stencil = Cow::Owned(self.inner.stencil.as_ref().clone());
let mask = Cow::Owned(self.inner.mask.as_ref().clone());
let scissor = Cow::Owned(self.inner.scissor.as_ref().clone());
let buffers_indexed = Cow::Owned(self.inner.buffers_indexed.as_ref().clone());
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
let clip_distance = Cow::Owned(self.inner.clip_distance.as_ref().clone());
#[cfg(all(not(feature = "gles"), not(feature="webgl"), not(target="macos")))]
let clip_control = self.inner.clip_control;
State{
inner: StateInner{
enable: Enable{
state_bits: bits
},
program: self.inner.program.clone(),
vao: self.inner.vao.clone(),
depth: Depth{
func: depth_func,
},
raster,
blend,
viewport,
scissor,
stencil,
mask,
fbo: self.inner.fbo,
buffers: Cow::Owned(self.inner.buffers.as_ref().clone()),
buffers_indexed: buffers_indexed,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
clip_distance,
#[cfg(all(not(feature = "gles"), not(feature="webgl"), not(target="macos")))]
clip_control,
},
gl: self.gl.clone(),
}
}
}
impl<'a> Deref for State<'a>{
type Target = Gl;
fn deref(&self) -> &Gl{
&self.gl
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
struct Enable{
state_bits: bits::EnableFlags,
}
impl Enable{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: Enable){
let changed_bits = Enable::make_diff(*self, new_state).state_bits;
unsafe{
for i in 0 .. bits::COUNT{
let flag = bits::EnableFlags::from_bits(1 << i).unwrap();
if changed_bits.contains(flag){
let gl_flag = flag.to_gl();
if new_state.state_bits.contains(flag) {
gl.Enable(gl_flag)
}else{
gl.Disable(gl_flag)
}
}
}
}
self.state_bits = new_state.state_bits
}
pub fn enable_flag(&mut self, gl: &Gl, flag: bits::EnableFlags){
let gl_flag = flag.to_gl();
self.state_bits.insert(flag);
unsafe{
gl.Enable(gl_flag)
}
}
pub fn disable_flag(&mut self, gl: &Gl, flag: bits::EnableFlags){
let gl_flag = flag.to_gl();
self.state_bits.remove(flag);
unsafe{
gl.Disable(gl_flag)
}
}
pub fn from_gl(gl: &Gl) -> Enable{
let mut bits = bits::EnableFlags::empty();
unsafe{
for i in 0..bits::COUNT{
let flag = bits::EnableFlags::from_bits(1 << i).unwrap();
if gl.IsEnabled(flag.to_gl()) != 0{
bits.insert(flag);
}
}
}
Enable{
state_bits: bits
}
}
#[inline]
fn make_diff(from: Enable, to: Enable) -> Enable{
Enable{
state_bits: from.state_bits ^ to.state_bits
}
}
}
#[derive(Debug,PartialEq,Clone)]
pub struct Program{
pub id: Cell<u32>,
}
impl Program{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: Program){
unsafe{
gl.UseProgram(new_state.id.get());
self.id = new_state.id;
}
}
pub fn from_gl(gl: &Gl) -> Program{
let mut program = 0;
unsafe{
gl.GetIntegerv(gl::CURRENT_PROGRAM, &mut program);
}
Program{
id: Cell::new(program as u32)
}
}
pub fn id(&self) -> GLuint{
self.id.get()
}
pub fn set(&self, id: u32){
self.id.set(id)
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Depth{
func: GLenum,
}
impl Depth{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: Depth){
unsafe{
gl.DepthFunc(new_state.func)
}
self.func = new_state.func;
}
pub fn from_gl(gl: &Gl) -> Depth{
let mut func = 0;
unsafe{
gl.GetIntegerv(gl::DEPTH_FUNC, &mut func);
}
Depth{
func: func as GLenum
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Raster{
front_face: GLenum,
cull_face: GLenum,
poly_offset_factor: f32,
poly_offset_units: f32,
poly_mode: GLenum,
point_size: f32,
point_fade: f32,
point_sprite_origin: GLenum,
sample_coverage: f32,
sample_coverage_invert: bool,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[allow(clippy::float_cmp)]
impl Raster{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Raster){
unsafe{
if new_state.front_face != self.front_face {
gl.FrontFace(new_state.front_face);
}
if new_state.cull_face != self.cull_face {
gl.CullFace(new_state.cull_face);
}
if new_state.poly_mode != self.poly_mode {
gl.PolygonMode(gl::FRONT_AND_BACK, new_state.poly_mode);
}
if new_state.poly_offset_factor != self.poly_offset_factor {
gl.PolygonOffset(new_state.poly_offset_factor, new_state.poly_offset_units);
}
if new_state.point_size != self.point_size {
gl.PointSize(new_state.point_size);
}
if new_state.point_fade != self.point_fade {
gl.PointParameterf(gl::POINT_FADE_THRESHOLD_SIZE, new_state.point_fade);
}
if new_state.point_sprite_origin != self.point_sprite_origin {
gl.PointParameteri(gl::POINT_SPRITE_COORD_ORIGIN, new_state.point_sprite_origin as i32);
}
if new_state.sample_coverage_invert != self.sample_coverage_invert{
gl.SampleCoverage(self.sample_coverage, self.sample_coverage_invert as GLboolean);
}
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> Raster{
unsafe{
let mut raster = mem::MaybeUninit::<Raster>::uninit();
{
let raster = &mut *raster.as_mut_ptr();
gl.GetIntegerv(gl::FRONT_FACE, &mut raster.front_face as *mut u32 as *mut i32);
gl.GetIntegerv(gl::CULL_FACE_MODE, &mut raster.cull_face as *mut u32 as *mut i32);
gl.GetFloatv(gl::POLYGON_OFFSET_FACTOR, &mut raster.poly_offset_factor);
gl.GetFloatv(gl::POLYGON_OFFSET_UNITS, &mut raster.poly_offset_units);
gl.GetFloatv(gl::POINT_SIZE, &mut raster.point_size);
gl.GetFloatv(gl::POINT_FADE_THRESHOLD_SIZE, &mut raster.point_fade);
gl.GetIntegerv(gl::POINT_SPRITE_COORD_ORIGIN, &mut raster.point_sprite_origin as *mut u32 as *mut i32);
gl.GetIntegerv(gl::POLYGON_MODE, &mut raster.poly_mode as *mut u32 as *mut i32);
gl.GetFloatv(gl::SAMPLE_COVERAGE_VALUE, &mut raster.sample_coverage);
gl.GetBooleanv(gl::SAMPLE_COVERAGE_INVERT, &mut raster.sample_coverage_invert as *mut bool as *mut u8);
}
raster.assume_init()
}
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Raster{
front_face: GLenum,
cull_face: GLenum,
poly_offset_factor: f32,
poly_offset_units: f32,
sample_coverage: f32,
sample_coverage_invert: bool,
}
#[cfg(any(feature = "gles", feature="webgl"))]
impl Raster{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Raster){
unsafe{
gl.FrontFace(new_state.front_face);
gl.CullFace(new_state.cull_face);
gl.PolygonOffset(new_state.poly_offset_factor, new_state.poly_offset_units);
gl.SampleCoverage(self.sample_coverage, self.sample_coverage_invert as GLboolean);
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> Raster{
unsafe{
let mut raster = mem::MaybeUninit::<Raster>::uninit();
{
let raster = &mut *raster.as_mut_ptr();
gl.GetIntegerv(gl::FRONT_FACE, &mut raster.front_face as *mut u32 as *mut i32);
gl.GetIntegerv(gl::CULL_FACE_MODE, &mut raster.cull_face as *mut u32 as *mut i32);
gl.GetFloatv(gl::POLYGON_OFFSET_FACTOR, &mut raster.poly_offset_factor);
gl.GetFloatv(gl::POLYGON_OFFSET_UNITS, &mut raster.poly_offset_units);
gl.GetFloatv(gl::SAMPLE_COVERAGE_VALUE, &mut raster.sample_coverage);
gl.GetBooleanv(gl::SAMPLE_COVERAGE_INVERT, &mut raster.sample_coverage_invert as *mut bool as *mut u8);
}
raster.assume_init()
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Blend{
equation: GLenum,
func_src_rgb: GLenum,
func_dst_rgb: GLenum,
func_src_alpha: GLenum,
func_dst_alpha: GLenum,
color: [f32;4],
}
const BLEND_COLOR: GLenum = 0x8005;
impl Blend{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Blend){
unsafe{
gl.BlendEquation(new_state.equation);
gl.BlendFuncSeparate(
new_state.func_src_rgb,
new_state.func_dst_rgb,
new_state.func_src_alpha,
new_state.func_dst_alpha);
gl.BlendColor(new_state.color[0], new_state.color[1], new_state.color[2], new_state.color[3]);
}
*self = *new_state;
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn from_gl(gl: &Gl) -> Blend{
unsafe{
let mut blend = mem::MaybeUninit::<Blend>::uninit().assume_init();
gl.GetIntegerv(gl::BLEND_EQUATION_RGB, &mut blend.equation as *mut u32 as *mut i32);
gl.GetIntegerv(gl::BLEND_SRC_RGB, &mut blend.func_src_rgb as *mut u32 as *mut i32);
gl.GetIntegerv(gl::BLEND_DST_RGB, &mut blend.func_dst_rgb as *mut u32 as *mut i32);
gl.GetIntegerv(gl::BLEND_SRC_ALPHA, &mut blend.func_src_alpha as *mut u32 as *mut i32);
gl.GetIntegerv(gl::BLEND_DST_ALPHA, &mut blend.func_dst_alpha as *mut u32 as *mut i32);
gl.GetFloatv(BLEND_COLOR, blend.color.as_mut_ptr());
blend
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn from_gl(gl: &Gl) -> Blend{
unsafe{
let mut blend = mem::MaybeUninit::<Blend>::uninit().assume_init();
gl.GetIntegerv(gl::BLEND_EQUATION_RGB, &mut blend.equation as *mut u32 as *mut i32);
blend.func_src_rgb = gl::ONE;
blend.func_dst_rgb = gl::ZERO;
blend.func_src_alpha = gl::ONE;
blend.func_dst_alpha = gl::ZERO;
gl.GetFloatv(BLEND_COLOR, blend.color.as_mut_ptr());
blend
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl"), not(target="macos")))]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ClipControl{
origin: GLenum,
depth: GLenum,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl"), not(target="macos")))]
impl ClipControl{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &ClipControl){
unsafe{
gl.ClipControl(new_state.origin, new_state.depth);
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> ClipControl{
unsafe{
let mut clip_control = mem::MaybeUninit::<ClipControl>::uninit().assume_init();
gl.GetIntegerv(gl::CLIP_ORIGIN, &mut clip_control.origin as *mut u32 as *mut i32);
gl.GetIntegerv(gl::CLIP_DEPTH_MODE, &mut clip_control.depth as *mut u32 as *mut i32);
clip_control
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Viewport{
pub x: GLint,
pub y: GLint,
pub width: GLsizei,
pub height: GLsizei,
}
impl Viewport{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Viewport){
unsafe{
gl.Viewport(new_state.x,new_state.y,new_state.width,new_state.height);
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> Viewport{
unsafe{
let mut viewport = mem::MaybeUninit::<Viewport>::uninit();
gl.GetIntegerv(gl::VIEWPORT, viewport.as_mut_ptr() as *mut _);
viewport.assume_init()
}
}
pub fn x(&self) -> GLint { self.x }
pub fn y(&self) -> GLint { self.y }
pub fn width(&self) -> GLsizei { self.width }
pub fn height(&self) -> GLsizei { self.height }
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Scissor{
pub x: GLint,
pub y: GLint,
pub width: GLsizei,
pub height: GLsizei,
}
impl Scissor{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Scissor){
unsafe{
gl.Scissor(new_state.x,new_state.y,new_state.width,new_state.height);
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> Scissor{
unsafe{
let mut scissors = mem::MaybeUninit::<Scissor>::uninit();
gl.GetIntegerv(gl::SCISSOR_BOX, scissors.as_mut_ptr() as *mut _);
scissors.assume_init()
}
}
}
#[derive(Clone, PartialEq, Debug)]
pub struct Vao{
pub id: Cell<GLuint>,
}
impl Vao{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: Vao){
unsafe{
gl.BindVertexArray(new_state.id.get());
}
self.id = new_state.id;
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn from_gl(gl: &Gl) -> Vao{
unsafe{
let mut id = 0;
gl.GetIntegerv(gl::VERTEX_ARRAY, &mut id as *mut u32 as *mut i32);
Vao{ id: Cell::new(id) }
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn from_gl(_gl: &Gl) -> Vao{
Vao{ id: Cell::new(0) }
}
#[inline]
pub fn id(&self) -> GLuint{
self.id.get()
}
#[inline]
pub fn set(&self, id: GLuint){
self.id.set(id)
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Stencil{
func: GLenum,
reference: GLint,
mask: GLuint,
sfail: GLenum,
dpfail: GLenum,
dppass: GLenum,
}
impl Stencil{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Stencil){
unsafe{
gl.StencilFunc(new_state.func, new_state.reference, new_state.mask);
gl.StencilOp(new_state.sfail, new_state.dpfail, new_state.dppass);
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> Stencil{
unsafe{
let mut stencil: Stencil = mem::MaybeUninit::uninit().assume_init();
gl.GetIntegerv(gl::STENCIL_FUNC, &mut stencil.func as *mut u32 as *mut i32);
gl.GetIntegerv(gl::STENCIL_REF, &mut stencil.reference);
gl.GetIntegerv(gl::STENCIL_VALUE_MASK, &mut stencil.mask as *mut u32 as *mut i32);
gl.GetIntegerv(gl::STENCIL_FAIL, &mut stencil.sfail as *mut u32 as *mut i32);
gl.GetIntegerv(gl::STENCIL_PASS_DEPTH_FAIL, &mut stencil.dpfail as *mut u32 as *mut i32);
gl.GetIntegerv(gl::STENCIL_PASS_DEPTH_PASS, &mut stencil.dppass as *mut u32 as *mut i32);
stencil
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Mask{
r: bool,
g: bool,
b: bool,
a: bool,
d: bool,
s: GLuint,
}
impl Mask{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Mask){
unsafe{
gl.ColorMask(new_state.r as GLboolean,
new_state.g as GLboolean,
new_state.b as GLboolean,
new_state.a as GLboolean);
gl.DepthMask(new_state.d as GLboolean);
gl.StencilMask(new_state.s)
}
*self = *new_state;
}
pub fn from_gl(gl: &Gl) -> Mask{
unsafe{
let mut mask = mem::MaybeUninit::<Mask>::uninit();
let mut color_mask = mem::MaybeUninit::<[GLboolean;4]>::uninit();
let mut depth_mask = mem::MaybeUninit::uninit();
gl.GetBooleanv(gl::COLOR_WRITEMASK, color_mask.as_mut_ptr() as *mut u8);
gl.GetBooleanv(gl::DEPTH_WRITEMASK, depth_mask.as_mut_ptr());
{
let mask = &mut *mask.as_mut_ptr();
gl.GetIntegerv(gl::STENCIL_WRITEMASK, &mut mask.s as *mut GLuint as *mut GLint);
let color_mask = color_mask.assume_init();
let depth_mask = depth_mask.assume_init();
mask.r = color_mask[0] != 0;
mask.g = color_mask[1] != 0;
mask.b = color_mask[2] != 0;
mask.a = color_mask[3] != 0;
mask.d = depth_mask != 0;
}
mask.assume_init()
}
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Fbo{
draw: GLuint,
read: GLuint,
}
impl Fbo{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: Fbo){
unsafe{
gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, new_state.draw);
gl.BindFramebuffer(gl::READ_FRAMEBUFFER, new_state.read);
}
*self = new_state;
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn from_gl(gl: &Gl) -> Fbo{
unsafe{
let mut fbo: Fbo = mem::MaybeUninit::uninit().assume_init();
gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fbo.draw as *mut u32 as *mut i32);
gl.GetIntegerv(gl::READ_FRAMEBUFFER_BINDING, &mut fbo.read as *mut u32 as *mut i32);
fbo
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn from_gl(gl: &Gl) -> Fbo{
unsafe{
let mut fbo: Fbo = mem::MaybeUninit::uninit().assume_init();
gl.GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut fbo.draw as *mut u32 as *mut i32);
fbo.read = gl::FRONT;
fbo
}
}
#[inline]
pub fn draw(self) -> GLuint{
self.draw
}
#[inline]
pub fn read(self) -> GLuint{
self.read
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Clone,Debug,PartialEq,Copy)]
pub struct ClipDistance{
enabled: [bool;16],
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl ClipDistance{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &ClipDistance){
unsafe{
for (i, (enabled, enable)) in self.enabled.iter_mut().zip(new_state.enabled.iter()).enumerate(){
if enabled != enable {
if *enable {
gl.Enable(gl::CLIP_DISTANCE0 + i as u32)
}else{
gl.Disable(gl::CLIP_DISTANCE0 + i as u32)
}
*enabled = *enable
}
}
}
}
pub fn from_gl(gl: &Gl) -> ClipDistance{
unsafe{
let mut max = 0;
gl.GetIntegerv(gl::MAX_CLIP_DISTANCES, &mut max);
let mut enabled = [false;16];
for i in 0..max {
enabled[i as usize] = gl.IsEnabledi(gl::CLIP_DISTANCE0, i as u32) != gl::FALSE
}
ClipDistance{
enabled,
}
}
}
}
#[derive(Clone, PartialEq, Debug, Copy)]
pub struct Buffers{
array: GLuint,
#[cfg(not(feature = "webgl"))]
atomic_counter: GLuint,
copy_read: GLuint,
copy_write: GLuint,
#[cfg(not(feature = "webgl"))]
dispatch_indirect: GLuint,
#[cfg(not(feature = "webgl"))]
draw_indirect: GLuint,
element_array: GLuint,
pixel_pack: GLuint,
pixel_unpack: GLuint,
#[cfg(not(feature = "webgl"))]
shader_storage: GLuint,
#[cfg(not(feature = "webgl"))]
texture: GLuint,
transform_feedback: GLuint,
uniform: GLuint,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
query: GLuint,
}
impl Buffers{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &Buffers){
unsafe{
if self.array != new_state.array {
gl.BindBuffer(gl::ARRAY_BUFFER, new_state.array);
self.array = new_state.array;
}
if self.copy_read != new_state.copy_read {
gl.BindBuffer(gl::COPY_READ_BUFFER, new_state.copy_read);
self.copy_read = new_state.copy_read;
}
if self.copy_write != new_state.copy_write {
gl.BindBuffer(gl::COPY_WRITE_BUFFER, new_state.copy_write);
self.copy_write = new_state.copy_write;
}
if self.element_array != new_state.element_array {
gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, new_state.element_array);
self.element_array = new_state.element_array;
}
if self.pixel_pack != new_state.pixel_pack {
gl.BindBuffer(gl::PIXEL_PACK_BUFFER, new_state.pixel_pack);
self.pixel_pack = new_state.pixel_pack;
}
if self.pixel_unpack != new_state.pixel_unpack {
gl.BindBuffer(gl::PIXEL_UNPACK_BUFFER, new_state.pixel_unpack);
self.pixel_unpack = new_state.pixel_unpack;
}
if self.transform_feedback != new_state.transform_feedback {
gl.BindBuffer(gl::TRANSFORM_FEEDBACK_BUFFER, new_state.transform_feedback);
self.transform_feedback = new_state.transform_feedback;
}
if self.uniform != new_state.uniform {
gl.BindBuffer(gl::UNIFORM_BUFFER, new_state.uniform);
self.uniform = new_state.uniform;
}
#[cfg(not(feature = "webgl"))]
{
if self.atomic_counter != new_state.atomic_counter {
gl.BindBuffer(gl::ATOMIC_COUNTER_BUFFER, new_state.atomic_counter);
self.atomic_counter = new_state.atomic_counter;
}
if self.dispatch_indirect != new_state.dispatch_indirect {
gl.BindBuffer(gl::DISPATCH_INDIRECT_BUFFER, new_state.dispatch_indirect);
self.dispatch_indirect = new_state.dispatch_indirect;
}
if self.draw_indirect != new_state.draw_indirect {
gl.BindBuffer(gl::DRAW_INDIRECT_BUFFER, new_state.draw_indirect);
self.draw_indirect = new_state.draw_indirect;
}
if self.shader_storage != new_state.shader_storage {
gl.BindBuffer(gl::SHADER_STORAGE_BUFFER, new_state.shader_storage);
self.shader_storage = new_state.shader_storage;
}
if self.texture != new_state.texture {
gl.BindBuffer(gl::TEXTURE_BUFFER, new_state.texture);
self.texture = new_state.texture;
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
{
if self.query != new_state.query {
gl.BindBuffer(gl::QUERY_BUFFER, new_state.query);
self.query = new_state.query;
}
}
}
}
pub fn from_gl(gl: &Gl) -> Buffers{
unsafe{
let mut array = 0;
gl.GetIntegerv(gl::ARRAY_BUFFER_BINDING, &mut array);
let mut copy_read = 0;
gl.GetIntegerv(gl::COPY_READ_BUFFER_BINDING, &mut copy_read);
let mut copy_write = 0;
gl.GetIntegerv(gl::COPY_WRITE_BUFFER_BINDING, &mut copy_write);
let mut element_array = 0;
gl.GetIntegerv(gl::ELEMENT_ARRAY_BUFFER_BINDING, &mut element_array);
let mut pixel_pack = 0;
gl.GetIntegerv(gl::PIXEL_PACK_BUFFER_BINDING, &mut pixel_pack);
let mut pixel_unpack = 0;
gl.GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut pixel_unpack);
let mut transform_feedback = 0;
gl.GetIntegerv(gl::TRANSFORM_FEEDBACK_BUFFER_BINDING, &mut transform_feedback);
let mut uniform = 0;
gl.GetIntegerv(gl::UNIFORM_BUFFER_BINDING, &mut uniform);
#[cfg(not(feature = "webgl"))]
let mut atomic_counter = 0;
#[cfg(not(feature = "webgl"))]
let mut dispatch_indirect = 0;
#[cfg(not(feature = "webgl"))]
let mut draw_indirect = 0;
#[cfg(not(feature = "webgl"))]
let mut shader_storage = 0;
#[cfg(not(feature = "webgl"))]
let mut texture = 0;
#[cfg(not(feature = "webgl"))]
{
gl.GetIntegerv(gl::ATOMIC_COUNTER_BUFFER_BINDING, &mut atomic_counter);
gl.GetIntegerv(gl::DISPATCH_INDIRECT_BUFFER_BINDING, &mut dispatch_indirect);
gl.GetIntegerv(gl::DRAW_INDIRECT_BUFFER_BINDING, &mut draw_indirect);
gl.GetIntegerv(gl::SHADER_STORAGE_BUFFER_BINDING, &mut shader_storage);
gl.GetIntegerv(gl::TEXTURE_BUFFER_BINDING, &mut texture);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
let mut query = 0;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
gl.GetIntegerv(gl::QUERY_BUFFER_BINDING, &mut query);
Buffers{
array: array as GLuint,
#[cfg(not(feature = "webgl"))]
atomic_counter: atomic_counter as GLuint,
copy_read: copy_read as GLuint,
copy_write: copy_write as GLuint,
#[cfg(not(feature = "webgl"))]
dispatch_indirect: dispatch_indirect as GLuint,
#[cfg(not(feature = "webgl"))]
draw_indirect: draw_indirect as GLuint,
element_array: element_array as GLuint,
pixel_pack: pixel_pack as GLuint,
pixel_unpack: pixel_unpack as GLuint,
#[cfg(not(feature = "webgl"))]
shader_storage: shader_storage as GLuint,
#[cfg(not(feature = "webgl"))]
texture: texture as GLuint,
transform_feedback: transform_feedback as GLuint,
uniform: uniform as GLuint,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
query: query as GLuint,
}
}
}
fn bind(&mut self, gl: &Gl, target: GLenum, buffer: GLuint){
unsafe{
match target{
gl::ARRAY_BUFFER => if self.array != buffer {
gl.BindBuffer(target, buffer);
self.array = buffer;
}
gl::ELEMENT_ARRAY_BUFFER => if self.element_array != buffer {
gl.BindBuffer(target, buffer);
self.element_array = buffer;
}
#[cfg(not(feature = "webgl"))]
gl::ATOMIC_COUNTER_BUFFER => if self.atomic_counter != buffer {
gl.BindBuffer(target, buffer);
self.atomic_counter = buffer;
}
gl::COPY_READ_BUFFER => if self.copy_read != buffer {
gl.BindBuffer(target, buffer);
self.copy_read = buffer;
}
gl::COPY_WRITE_BUFFER => if self.copy_write != buffer {
gl.BindBuffer(target, buffer);
self.copy_write = buffer;
}
#[cfg(not(feature = "webgl"))]
gl::DISPATCH_INDIRECT_BUFFER => if self.dispatch_indirect != buffer {
gl.BindBuffer(target, buffer);
self.dispatch_indirect = buffer;
}
#[cfg(not(feature = "webgl"))]
gl::DRAW_INDIRECT_BUFFER => if self.draw_indirect != buffer {
gl.BindBuffer(target, buffer);
self.draw_indirect = buffer;
}
gl::PIXEL_PACK_BUFFER => if self.pixel_pack != buffer {
gl.BindBuffer(target, buffer);
self.pixel_pack = buffer;
}
gl::PIXEL_UNPACK_BUFFER => if self.pixel_unpack != buffer {
gl.BindBuffer(target, buffer);
self.pixel_unpack = buffer;
}
#[cfg(not(feature = "webgl"))]
gl::SHADER_STORAGE_BUFFER => if self.shader_storage != buffer {
gl.BindBuffer(target, buffer);
self.shader_storage = buffer;
}
#[cfg(not(feature = "webgl"))]
gl::TEXTURE_BUFFER => if self.texture != buffer {
gl.BindBuffer(target, buffer);
self.texture = buffer;
}
gl::TRANSFORM_FEEDBACK_BUFFER => if self.transform_feedback != buffer {
gl.BindBuffer(target, buffer);
self.transform_feedback = buffer;
}
gl::UNIFORM_BUFFER => if self.uniform != buffer {
gl.BindBuffer(target, buffer);
self.uniform = buffer;
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
gl::QUERY_BUFFER => if self.query != buffer {
gl.BindBuffer(target, buffer);
self.query = buffer;
}
_ => panic!("Trying to bind unkown buffer target {:x}", target),
}
}
}
}
#[derive(Clone, PartialEq, Debug, Copy, Default, Eq, PartialOrd, Ord)]
pub struct BufferRangeBind{
buffer: GLuint,
offset: GLintptr,
size: GLsizeiptr,
}
#[derive(Clone, Copy)]
struct BindingPoints{
bindings: [BufferRangeBind; 128],
max_set: u32,
}
impl PartialEq for BindingPoints{
#[inline]
fn eq(&self, other: &BindingPoints) -> bool{
self.bindings[..self.max_set as usize] == other.bindings[..other.max_set as usize]
}
}
impl Debug for BindingPoints{
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result{
fmt.debug_set().entries(self.bindings.iter().take(self.max_set as usize)).finish()
}
}
impl BindingPoints{
fn new() -> BindingPoints{
BindingPoints{
bindings: [BufferRangeBind::default(); 128],
max_set: 0,
}
}
fn apply(&mut self, gl: &Gl, target: GLenum, new_bindings: &BindingPoints){
self.max_set = self.max_set.max(new_bindings.max_set);
for (index, (self_binding, new_binding)) in self.bindings.iter_mut()
.zip(new_bindings.bindings.iter())
.take(self.max_set as usize)
.enumerate()
{
if new_binding.size > 0 && self_binding != new_binding {
unsafe{
gl.BindBufferRange(target,
index as u32,
new_binding.buffer,
new_binding.offset,
new_binding.size);
}
}
*self_binding = *new_binding;
}
}
pub fn from_gl(gl: &Gl,
max_enum: GLenum,
buffer_enum: GLenum,
offset_enum: GLenum,
size_enum: GLenum) -> BindingPoints
{
unsafe{
let mut max_bindings = 0;
gl.GetIntegerv(max_enum, &mut max_bindings);
let max_bindings = max_bindings as usize;
let mut binding_points = BindingPoints::new();
let mut max_set = 0;
for (index, binding) in binding_points.bindings.iter_mut()
.take(max_bindings)
.enumerate()
{
let index = index as u32;
#[cfg(not(feature = "webgl"))]
let buffer = {
let mut buffer = 0;
gl.GetIntegeri_v(buffer_enum, index, &mut buffer);
buffer
};
#[cfg(feature = "webgl")]
let buffer: u32 = gl.GetIndexedParameter(buffer_enum, index).try_into().unwrap_or(0);
binding.buffer = buffer as u32;
if buffer != 0 {
max_set = index + 1;
}
#[cfg(not(feature = "webgl"))]
let offset = {
let mut offset = 0;
gl.GetIntegeri_v(offset_enum, index, &mut offset);
offset
};
#[cfg(feature = "webgl")]
let offset: u32 = gl.GetIndexedParameter(offset_enum, index).try_into().unwrap_or(0);
binding.offset = offset as GLintptr;
#[cfg(not(feature = "webgl"))]
let size = {
let mut size = 0;
gl.GetIntegeri_v(size_enum, index, &mut size);
size
};
#[cfg(feature = "webgl")]
let size: u32 = gl.GetIndexedParameter(size_enum, index).try_into().unwrap_or(0);
binding.size = size as GLsizeiptr;
}
binding_points.max_set = max_set;
binding_points
}
}
pub fn bind(&mut self, gl: &Gl, target: GLenum, index: GLuint, binding: BufferRangeBind){
unsafe{
if self.bindings[index as usize] != binding {
gl.BindBufferRange(
target,
index,
binding.buffer,
binding.offset,
binding.size,
);
self.bindings[index as usize] = binding;
self.max_set = self.max_set.max(index + 1);
}
}
}
pub fn binding(&self, index: GLuint) -> Option<&BufferRangeBind>{
if index < self.max_set {
Some(&self.bindings[index as usize])
}else{
None
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct BuffersIndexed{
#[cfg(not(feature = "webgl"))]
atomic_counter: BindingPoints,
#[cfg(not(feature = "webgl"))]
shader_storage: BindingPoints,
#[cfg(not(any(feature = "webgl", feature="gles")))]
transform_feedback: BindingPoints,
uniform: BindingPoints,
}
impl BuffersIndexed{
#[inline]
fn apply(&mut self, gl: &Gl, new_state: &BuffersIndexed){
#[cfg(not(feature = "webgl"))]
{
if self.atomic_counter != new_state.atomic_counter{
self.atomic_counter.apply(gl, gl::ATOMIC_COUNTER_BUFFER, &new_state.atomic_counter)
}
if self.shader_storage != new_state.shader_storage{
self.shader_storage.apply(gl, gl::SHADER_STORAGE_BUFFER, &new_state.shader_storage)
}
}
#[cfg(not(any(feature = "webgl", feature="gles")))]
{
if self.transform_feedback != new_state.transform_feedback{
self.transform_feedback.apply(gl, gl::TRANSFORM_FEEDBACK_BUFFER, &new_state.transform_feedback)
}
}
if self.uniform != new_state.uniform{
self.uniform.apply(gl, gl::UNIFORM_BUFFER, &new_state.uniform)
}
}
pub fn from_gl(gl: &Gl) -> BuffersIndexed{
#[cfg(not(feature = "webgl"))]
let atomic_counter = BindingPoints::from_gl(gl,
gl::MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
gl::ATOMIC_COUNTER_BUFFER_BINDING,
gl::ATOMIC_COUNTER_BUFFER_START,
gl::ATOMIC_COUNTER_BUFFER_SIZE);
#[cfg(not(feature = "webgl"))]
let shader_storage = BindingPoints::from_gl(gl,
gl::MAX_SHADER_STORAGE_BUFFER_BINDINGS,
gl::SHADER_STORAGE_BUFFER_BINDING,
gl::SHADER_STORAGE_BUFFER_START,
gl::SHADER_STORAGE_BUFFER_SIZE);
#[cfg(not(any(feature = "webgl", feature="gles")))]
let transform_feedback = BindingPoints::from_gl(gl,
gl::MAX_TRANSFORM_FEEDBACK_BUFFERS,
gl::TRANSFORM_FEEDBACK_BUFFER_BINDING,
gl::TRANSFORM_FEEDBACK_BUFFER_START,
gl::TRANSFORM_FEEDBACK_BUFFER_SIZE);
let uniform = BindingPoints::from_gl(gl,
gl::MAX_UNIFORM_BUFFER_BINDINGS,
gl::UNIFORM_BUFFER_BINDING,
gl::UNIFORM_BUFFER_START,
gl::UNIFORM_BUFFER_SIZE);
BuffersIndexed{
#[cfg(not(feature = "webgl"))]
atomic_counter,
#[cfg(not(feature = "webgl"))]
shader_storage,
#[cfg(not(any(feature = "webgl", feature="gles")))]
transform_feedback,
uniform,
}
}
fn set(&mut self, target: GLenum, index: GLuint, binding: BufferRangeBind){
let binding_point = match target{
#[cfg(not(feature = "webgl"))]
gl::ATOMIC_COUNTER_BUFFER => &mut self.atomic_counter,
#[cfg(not(feature = "webgl"))]
gl::SHADER_STORAGE_BUFFER => &mut self.shader_storage,
#[cfg(not(any(feature = "webgl", feature="gles")))]
gl::TRANSFORM_FEEDBACK_BUFFER => &mut self.transform_feedback,
gl::UNIFORM_BUFFER => &mut self.uniform,
_ => panic!("Trying to bind unkown buffer target {:x}", target),
};
binding_point.bindings[index as usize] = binding;
binding_point.max_set = binding_point.max_set.max(index + 1);
}
fn bind(&mut self, gl: &Gl, target: GLenum, index: GLuint, binding: BufferRangeBind){
match target{
#[cfg(not(feature = "webgl"))]
gl::ATOMIC_COUNTER_BUFFER => self.atomic_counter.bind(gl, target, index, binding),
#[cfg(not(feature = "webgl"))]
gl::SHADER_STORAGE_BUFFER => self.shader_storage.bind(gl, target, index, binding),
#[cfg(not(any(feature = "webgl", feature="gles")))]
gl::TRANSFORM_FEEDBACK_BUFFER => self.transform_feedback.bind(gl, target, index, binding),
gl::UNIFORM_BUFFER => self.uniform.bind(gl, target, index, binding),
_ => panic!("Trying to bind unkown buffer target {:x}", target),
}
}
pub fn binding(&self, target: GLenum, index: GLuint) -> Option<&BufferRangeBind>{
match target{
#[cfg(not(feature = "webgl"))]
gl::ATOMIC_COUNTER_BUFFER => self.atomic_counter.binding(index),
#[cfg(not(feature = "webgl"))]
gl::SHADER_STORAGE_BUFFER => self.shader_storage.binding(index),
#[cfg(not(any(feature = "webgl", feature="gles")))]
gl::TRANSFORM_FEEDBACK_BUFFER => self.transform_feedback.binding(index),
gl::UNIFORM_BUFFER => self.uniform.binding(index),
_ => panic!("Trying to bind unkown buffer target {:x}", target),
}
}
}