use gl::types::*;
#[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 texture::{self, Texture};
#[cfg(not(feature="webgl"))]
use cubemap::{self, CubeMap};
use utils::Rect;
use state::StateRef;
use std::mem;
use std::borrow::{Borrow, BorrowMut};
pub struct Fbo<C = ColorAttachment, D = DepthAttachment>{
id: GLuint,
color: Vec<C>,
depth: Option<D>,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
is_dsa: bool,
gl: StateRef,
}
impl<C,D> Drop for Fbo<C,D>{
fn drop(&mut self){
unsafe{
self.gl.DeleteFramebuffers(1, &self.id);
}
}
}
impl PartialEq for Fbo {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for Fbo {}
pub struct Builder<'a>(pub(crate) &'a StateRef);
impl<'a> Builder<'a>{
pub fn create(&self, w: u32, h: u32) -> ::Result<Fbo>{
let color = ColorAttachmentBuilder(self.0).texture(w, h, ColorFormat::default())?;
let depth = DepthAttachmentBuilder(self.0).render_buffer(w, h, DepthFormat::default())?;
self.from_color_depth(color, depth)
}
pub fn from_color<C: ColorAttach>(&self, color: C) -> ::Result<Fbo<C>>{
let depth = if color.samples() > 0{
DepthAttachmentBuilder(self.0)
.render_buffer_multisampled(color.width(), color.height(), color.samples(), DepthFormat::default())?
}else{
DepthAttachmentBuilder(self.0)
.render_buffer(color.width(), color.height(), DepthFormat::default())?
};
self.from_color_depth(color, depth)
}
pub fn from_color_no_depth<C: ColorAttach>(&self, color: C) -> ::Result<Fbo<C>>{
Builder::new_(self.0, vec![color], None)
}
pub fn from_colors<C: ColorAttach>(&self, color: Vec<C>) -> ::Result<Fbo<C>>{
if color.is_empty(){
return Err(::Error::new(::ErrorKind::NoColorAttachments, None));
}
let depth_w = color.iter().map(|color| color.width()).max().unwrap();
let depth_h = color.iter().map(|color| color.height()).max().unwrap();
let depth = DepthAttachmentBuilder(self.0)
.render_buffer(depth_w, depth_h, DepthFormat::default())?;
self.from_colors_depth(color, depth)
}
pub fn from_colors_no_depth<C: ColorAttach>(&self, color: Vec<C>) -> ::Result<Fbo<C>>{
if color.is_empty(){
return Err(::Error::new(::ErrorKind::NoColorAttachments, None));
}
Builder::new_(self.0, color, None)
}
pub fn from_depth<D: DepthAttach>(&self, depth: D) -> ::Result<Fbo<ColorAttachment,D>>{
Builder::new_(self.0, vec![], Some(depth))
}
pub fn from_color_depth<C: ColorAttach, D: DepthAttach>(&self, color: C, depth: D) -> ::Result<Fbo<C,D>>{
if color.width() != depth.width() || color.height() != depth.height() || color.samples() != depth.samples(){
Err(::Error::new(::ErrorKind::FormatNotSupported,
"color and depth attachment dimensions and number of samples have to be the same"))
}else{
Builder::new_(self.0, vec![color], Some(depth))
}
}
pub fn from_colors_depth<C: ColorAttach, D: DepthAttach>(&self, color: Vec<C>, depth: D) -> ::Result<Fbo<C,D>>{
if !color.is_empty(){
let w = color[0].width();
let h = color[0].height();
let s = color[0].samples();
let diff = color.iter().find(|c| c.width() != w || c.height() != h || c.samples() != s);
if diff.is_some(){
return Err(::Error::new(::ErrorKind::FormatNotSupported,
"color attachments dimensions and number of samples have to be the same"));
}
if w != depth.width() || h != depth.height() || s != depth.samples(){
return Err(::Error::new(::ErrorKind::FormatNotSupported,
"color and depth attachment dimensions and number of samples have to be the same"));
}
}
Builder::new_(self.0, color, Some(depth))
}
pub fn from_cubemap_face<'c>(&self, cubemap: &'c ::CubeMap, face: GLenum) -> ::Result<Fbo<ColorAttachmentCubemapFace<'c>>>{
self.from_cubemap_face_level(cubemap, face, 0)
}
pub fn from_cubemap_face_level<'c>(&self, cubemap: &'c ::CubeMap, face: GLenum, level: u32) -> ::Result<Fbo<ColorAttachmentCubemapFace<'c>>>{
let w = cubemap.width() >> level;
let h = cubemap.height() >> level;
let depth = DepthAttachmentBuilder(self.0)
.render_buffer(w, h, DepthFormat::default())?;
Builder::new_(self.0, vec![ColorAttachmentCubemapFace{cubemap, face, level: level as i32}], Some(depth))
}
pub fn from_cubemap_face_no_depth<'c>(&self, cubemap: &'c ::CubeMap, face: GLenum) -> ::Result<Fbo<ColorAttachmentCubemapFace<'c>>>{
self.from_cubemap_face_level_no_depth(cubemap, face, 0)
}
pub fn from_cubemap_face_level_no_depth<'c>(&self, cubemap: &'c ::CubeMap, face: GLenum, level: u32) -> ::Result<Fbo<ColorAttachmentCubemapFace<'c>>>{
Builder::new_(self.0, vec![ColorAttachmentCubemapFace{cubemap, face, level: level as i32}], None)
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn new_dsa<C: ColorAttach, D: DepthAttach>(gl: &StateRef, color: Vec<C>, depth: Option<D>) -> ::Result<Fbo<C,D>>{
let mut max_attach = 0;
let mut id: GLuint = 0;
unsafe{
gl.GetIntegerv(gl::MAX_COLOR_ATTACHMENTS, &mut max_attach);
if color.len() > max_attach as usize{
return Err(::Error::new(::ErrorKind::MaxColorAttachments, None));
}
gl.CreateFramebuffers(1, &mut id);
if !color.is_empty(){
let attachments: Vec<u32> = (0..color.len()).map(|i| gl::COLOR_ATTACHMENT0 + i as u32).collect();
for (i, color) in color.iter().enumerate(){
color.dsa_color_attach(gl, id, gl::COLOR_ATTACHMENT0 + i as u32);
}
gl.NamedFramebufferDrawBuffers(id, color.len() as i32, attachments.as_ptr());
}else{
gl.NamedFramebufferDrawBuffer(id, gl::NONE);
}
if let Some(depth) = depth.as_ref(){
depth.dsa_depth_attach(gl, id, gl::DEPTH_ATTACHMENT);
}
let status = gl.CheckNamedFramebufferStatus(id, gl::FRAMEBUFFER);
match status {
gl::FRAMEBUFFER_COMPLETE =>
Ok( Fbo{
id,
color,
depth,
is_dsa: true,
gl: gl.clone(),
}),
_ => Err(::Error::with_gl_code(::ErrorKind::FramebufferCreationError,None,status))
}
}
}
fn new_bind<C: ColorAttach, D: DepthAttach>(gl: &StateRef, color: Vec<C>, depth: Option<D>) -> ::Result<Fbo<C,D>> {
let max_attach = gl.capabilities().max_color_attachments;
let mut id: GLuint = 0;
unsafe{
if color.len() > max_attach as usize{
return Err(::Error::new(::ErrorKind::MaxColorAttachments, None));
}
gl.GenFramebuffers(1, &mut id);
gl.BindFramebuffer(gl::FRAMEBUFFER, id);
if !color.is_empty(){
let attachments: Vec<u32> = (0..color.len()).map(|i| gl::COLOR_ATTACHMENT0 + i as u32).collect();
for (i, color) in color.iter().enumerate(){
color.color_attach(gl, gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0 + i as u32);
}
#[cfg(not(feature="webgl"))]
gl.DrawBuffers(color.len() as i32, attachments.as_ptr());
#[cfg(feature="webgl")]
gl.DrawBuffers(&attachments);
}else{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
gl.DrawBuffer(gl::NONE);
}
if let Some(depth) = depth.as_ref(){
depth.depth_attach(gl, gl::FRAMEBUFFER, gl::DEPTH_ATTACHMENT);
}
let status = gl.CheckFramebufferStatus(gl::FRAMEBUFFER);
gl.BindFramebuffer(gl::FRAMEBUFFER, 0);
match status {
gl::FRAMEBUFFER_COMPLETE =>
Ok( Fbo{
id: id,
color: color,
depth: depth,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
is_dsa: false,
gl: gl.clone(),
}),
_ => Err(::Error::with_gl_code(::ErrorKind::FramebufferCreationError,None,status))
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn new_<C: ColorAttach, D: DepthAttach>(gl: &StateRef, color: Vec<C>, depth: Option<D>) -> ::Result<Fbo<C, D>>{
if gl.capabilities().supports_dsa(){
Builder::new_dsa(gl, color, depth)
}else{
Builder::new_bind(gl, color, depth)
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
fn new_<C: ColorAttach, D: DepthAttach>(gl: &StateRef, color: Vec<C>, depth: Option<D>) -> ::Result<Fbo<C, D>>{
Builder::new_bind(gl, color, depth)
}
}
impl<C,D> Fbo<C,D>{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn blit(&self, fbo2: &mut Fbo, src_rect: &Rect, dst_rect: &Rect){
unsafe{
if self.is_dsa{
self.gl.BlitNamedFramebuffer(
self.id(),
fbo2.id(),
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::COLOR_BUFFER_BIT,
gl::LINEAR,
);
}else{
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, self.id());
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo2.id());
self.gl.BlitFramebuffer(
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::COLOR_BUFFER_BIT,
gl::LINEAR
);
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, 0);
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn blit_depth(&self, fbo2: &mut Fbo, src_rect: &Rect, dst_rect: &Rect){
unsafe{
if self.is_dsa{
self.gl.BlitNamedFramebuffer(
self.id(),
fbo2.id(),
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::DEPTH_BUFFER_BIT,
gl::NEAREST,
);
}else{
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, self.id());
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo2.id());
self.gl.BlitFramebuffer(
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::DEPTH_BUFFER_BIT,
gl::NEAREST
);
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, 0);
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
}
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn blit(&self, fbo2: &mut Fbo, src_rect: &Rect, dst_rect: &Rect){
unsafe{
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, self.id());
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo2.id());
#[cfg(target_os="emscripten")]
{
extern "C"{
fn emscripten_glBlitFramebuffer( srcX0: GLint,
srcY0: GLint,
srcX1: GLint,
srcY1: GLint,
dstX0: GLint,
dstY0: GLint,
dstX1: GLint,
dstY1: GLint,
mask: GLbitfield,
filter: GLenum);
}
emscripten_glBlitFramebuffer(
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::COLOR_BUFFER_BIT,
gl::LINEAR
);
}
#[cfg(not(target_os="emscripten"))]
self.gl.BlitFramebuffer(
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::COLOR_BUFFER_BIT,
gl::LINEAR
);
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, 0);
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn blit_depth(&self, fbo2: &mut Fbo, src_rect: &Rect, dst_rect: &Rect){
unsafe{
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, self.id());
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, fbo2.id());
#[cfg(target_os="emscripten")]
{
extern "C"{
fn emscripten_glBlitFramebuffer( srcX0: GLint,
srcY0: GLint,
srcX1: GLint,
srcY1: GLint,
dstX0: GLint,
dstY0: GLint,
dstX1: GLint,
dstY1: GLint,
mask: GLbitfield,
filter: GLenum);
}
emscripten_glBlitFramebuffer(
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::DEPTH_BUFFER_BIT,
gl::NEAREST
);
}
#[cfg(not(target_os="emscripten"))]
self.gl.BlitFramebuffer(
src_rect.left as i32,
src_rect.bottom as i32,
src_rect.width as i32,
src_rect.height as i32,
dst_rect.left as i32,
dst_rect.bottom as i32,
dst_rect.width as i32,
dst_rect.height as i32,
gl::DEPTH_BUFFER_BIT,
gl::NEAREST
);
self.gl.BindFramebuffer(gl::READ_FRAMEBUFFER, 0);
self.gl.BindFramebuffer(gl::DRAW_FRAMEBUFFER, 0);
}
}
pub fn id(&self) -> GLuint{
self.id
}
pub fn color(&self, idx: usize) -> Option<&C>{
self.color.get(idx)
}
pub fn depth(&self) -> Option<&D>{
self.depth.as_ref()
}
pub fn into_attachments(mut self) -> (Vec<C>, Option<D>){
(mem::replace(&mut self.color, vec![]), mem::replace(&mut self.depth, None))
}
#[cfg(feature="webgl")]
pub fn read_to<T>(&self, x: i32, y: i32, width: i32, height: i32, format: GLenum, ty: GLenum, pixels: &mut [T])
where for <'s> &'s mut [T]: gl::AsArrayBufferView<'s>
{
unsafe{
self.gl.BindFramebuffer(gl::FRAMEBUFFER, self.id);
self.gl.ReadBuffer(gl::COLOR_ATTACHMENT0);
self.gl.ReadPixels(x, y, width, height, format, ty, Some(pixels));
}
}
#[cfg(feature="gles")]
pub unsafe fn read_to<T>(&self, x: i32, y: i32, width: i32, height: i32, format: GLenum, ty: GLenum, pixels: &mut [T]){
self.gl.BindFramebuffer(gl::FRAMEBUFFER, self.id);
self.gl.ReadBuffer(gl::COLOR_ATTACHMENT0);
self.gl.ReadPixels(x, y, width, height, format, ty, pixels.as_mut_ptr() as *mut GLvoid);
}
}
impl<C: ColorAttach, D: DepthAttach> Fbo<C, D>{
pub fn viewport(&self) -> Rect{
Rect{ bottom: 0, left: 0, width: self.width(), height: self.height() }
}
pub fn width(&self) -> u32{
self.color.get(0).map(|c| c.width())
.unwrap_or_else(|| self.depth.as_ref().map(|d| d.width()).unwrap())
}
pub fn height(&self) -> u32{
self.color.get(0).map(|c| c.height())
.unwrap_or_else(|| self.depth.as_ref().map(|d| d.height()).unwrap())
}
pub fn aspect_ratio(&self) -> f32{
self.width() as f32 / self.height() as f32
}
pub fn size(&self) -> (u32, u32){
(self.width(), self.height())
}
}
impl<C: Borrow<ColorAttachment>, D: Borrow<DepthAttachment>> Fbo<C,D>{
pub fn color_tex(&self, idx: usize) -> Option<&Texture>{
self.color(idx).and_then(|color| match color.borrow(){
ColorAttachment::Texture(tex) => Some(tex),
_ => None
})
}
#[cfg(not(feature="webgl"))]
pub fn color_cubemap(&self, idx: usize) -> Option<&CubeMap>{
self.color(idx).and_then(|color| match color.borrow(){
ColorAttachment::CubeMap(cm) => Some(cm),
_ => None
})
}
pub fn depth_tex(&self) -> Option<&Texture>{
self.depth.as_ref().and_then(|tex| match tex.borrow() {
DepthAttachment::Texture(tex) => Some(tex),
_ => None
})
}
#[cfg(not(feature="webgl"))]
pub fn depth_cubemap(&self) -> Option<&CubeMap>{
self.depth.as_ref().and_then(|tex| match tex.borrow() {
DepthAttachment::CubeMap(cm) => Some(cm),
_ => None
})
}
}
impl<C: BorrowMut<ColorAttachment>, D: BorrowMut<DepthAttachment>> Fbo<C,D>{
pub fn color_tex_mut(&mut self, idx: usize) -> Option<&mut Texture>{
self.color.get_mut(idx).and_then(|color| match color.borrow_mut(){
ColorAttachment::Texture(ref mut tex) => Some(tex),
_ => None
})
}
pub fn depth_tex_mut(&mut self) -> Option<&mut Texture>{
self.depth.as_mut().and_then(|tex| match tex.borrow_mut() {
DepthAttachment::Texture(tex) => Some(tex),
_ => None
})
}
}
pub struct RenderBuffer{
id: GLuint,
w: u32,
h: u32,
samples: u32,
gl: StateRef,
}
pub struct RenderBufferBuilder<'a>(pub(crate) &'a StateRef);
impl Drop for RenderBuffer{
fn drop(&mut self){
unsafe{
self.gl.DeleteRenderbuffers(1, &self.id);
}
}
}
impl<'a> RenderBufferBuilder<'a> {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn create(&self, w: u32, h: u32, internal: GLenum) -> ::Result<RenderBuffer>{
let mut id = 0;
let mut maxsize = 0;
unsafe {
self.0.GetIntegerv(gl::MAX_RENDERBUFFER_SIZE, &mut maxsize);
if w > maxsize as u32 || h > maxsize as u32 {
return Err(::Error::new(::ErrorKind::SizeGreaterThanMaxSize, None));
}
}
if self.0.capabilities().is_supported("GL_ARB_internalformat_query"){
let mut supported = 0;
unsafe{
self.0.GetInternalformativ(gl::RENDERBUFFER, internal, gl::INTERNALFORMAT_SUPPORTED, 1, &mut supported);
if supported == gl::FALSE as i32 {
return Err(::Error::new(::ErrorKind::FormatNotSupported, None));
}
}
}
if self.0.capabilities().supports_dsa(){
unsafe{
self.0.CreateRenderbuffers(1, &mut id);
self.0.NamedRenderbufferStorage(id, internal, w as i32, h as i32);
}
}else{
unsafe{
self.0.GenRenderbuffers(1, &mut id);
self.0.BindRenderbuffer(gl::RENDERBUFFER, id);
self.0.RenderbufferStorage(gl::RENDERBUFFER, internal, w as i32, h as i32);
}
}
Ok(RenderBuffer{
id: id,
w: w,
h: h,
samples: 0,
gl: self.0.clone()
})
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn create(&self, w: u32, h: u32, internal: GLenum) -> ::Result<RenderBuffer>{
let mut id = 0;
let maxsize = self.0.capabilities().max_renderbuffer_size;
if w > maxsize as u32 || h > maxsize as u32 {
return Err(::Error::new(::ErrorKind::SizeGreaterThanMaxSize, None));
}
unsafe{
self.0.GenRenderbuffers(1, &mut id);
self.0.BindRenderbuffer(gl::RENDERBUFFER, id);
self.0.RenderbufferStorage(gl::RENDERBUFFER, internal, w as i32, h as i32);
}
Ok(RenderBuffer{
id: id,
w: w,
h: h,
samples: 0,
gl: self.0.clone()
})
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn create_multisampled(&self, w: u32, h: u32, samples: u32, internal: GLenum) -> ::Result<RenderBuffer>{
let mut id = 0;
let mut maxsize = 0;
unsafe {
self.0.GetIntegerv(gl::MAX_RENDERBUFFER_SIZE, &mut maxsize);
if w > maxsize as u32 || h > maxsize as u32 {
return Err(::Error::new(::ErrorKind::SizeGreaterThanMaxSize, None));
}
}
if self.0.capabilities().is_supported("GL_ARB_internalformat_query"){
let mut supported = 0;
unsafe{
self.0.GetInternalformativ(gl::RENDERBUFFER, internal, gl::INTERNALFORMAT_SUPPORTED, 1, &mut supported);
if supported == gl::FALSE as i32 {
return Err(::Error::new(::ErrorKind::FormatNotSupported, None));
}
}
}
if self.0.capabilities().supports_dsa(){
unsafe{
self.0.CreateRenderbuffers(1, &mut id);
self.0.NamedRenderbufferStorageMultisample(id, samples as GLsizei, internal, w as i32, h as i32);
}
}else{
unsafe{
self.0.GenRenderbuffers(1, &mut id);
self.0.BindRenderbuffer(gl::RENDERBUFFER, id);
self.0.RenderbufferStorageMultisample(gl::RENDERBUFFER, samples as GLsizei, internal, w as i32, h as i32);
}
}
Ok(RenderBuffer{
id: id,
w: w,
h: h,
samples: samples,
gl: self.0.clone(),
})
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn create_multisampled(&self, w: u32, h: u32, samples: u32, internal: GLenum) -> ::Result<RenderBuffer>{
let mut id = 0;
let mut maxsize = 0;
unsafe {
self.0.GetIntegerv(gl::MAX_RENDERBUFFER_SIZE, &mut maxsize);
if w > maxsize as u32 || h > maxsize as u32 {
return Err(::Error::new(::ErrorKind::SizeGreaterThanMaxSize, None));
}
}
unsafe{
self.0.GenRenderbuffers(1, &mut id);
self.0.BindRenderbuffer(gl::RENDERBUFFER, id);
#[cfg(target_os="emscripten")]
{
extern "C"{
fn emscripten_glRenderbufferStorageMultisample(target: GLenum,
samples: GLsizei,
internalformat: GLenum,
width: GLsizei,
height: GLsizei);
}
emscripten_glRenderbufferStorageMultisample(gl::RENDERBUFFER, samples as GLsizei, internal, w as i32, h as i32);
}
#[cfg(not(target_os="emscripten"))]
self.0.RenderbufferStorageMultisample(gl::RENDERBUFFER, samples as GLsizei, internal, w as i32, h as i32);
}
Ok(RenderBuffer{
id: id,
w: w,
h: h,
samples: samples,
gl: self.0.clone(),
})
}
}
impl RenderBuffer{
pub fn width(&self) -> u32{
self.w
}
pub fn height(&self) -> u32{
self.h
}
pub fn samples(&self) -> u32{
self.samples
}
pub fn id(&self) -> GLuint{
self.id
}
}
pub enum ColorAttachment{
Texture(::Texture),
Buffer(RenderBuffer),
#[cfg(not(feature="webgl"))]
CubeMap(::CubeMap),
}
pub struct ColorAttachmentCubemapFace<'a>{
pub cubemap: &'a ::CubeMap,
pub face: GLenum,
pub level: i32,
}
pub trait ColorAttach{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn dsa_color_attach(&self, gl: &Gl, framebuffer_id: GLuint, attachment: GLuint);
unsafe fn color_attach(&self, gl: &Gl, target: GLenum, attachment: GLuint);
fn width(&self) -> u32;
fn height(&self) -> u32;
fn samples(&self) -> u32;
}
impl<'a> ColorAttach for ColorAttachmentCubemapFace<'a>{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn dsa_color_attach(&self, gl: &Gl, framebuffer_id: GLuint, attachment: GLuint){
gl.NamedFramebufferTextureLayer(framebuffer_id, attachment, self.cubemap.id(), self.level, (self.face - gl::TEXTURE_CUBE_MAP_POSITIVE_X) as i32);
}
unsafe fn color_attach(&self, gl: &Gl, target: GLenum, attachment: GLuint) {
gl.FramebufferTexture2D(target, attachment, self.face, self.cubemap.id(), self.level);
}
fn width(&self) -> u32{
self.cubemap.width() >> self.level
}
fn height(&self) -> u32{
self.cubemap.height() >> self.level
}
fn samples(&self) -> u32{
0
}
}
impl<C: Borrow<ColorAttachment>> ColorAttach for C{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn dsa_color_attach(&self, gl: &Gl, framebuffer_id: GLuint, attachment: GLuint){
match self.borrow(){
ColorAttachment::Texture(tex) => gl.NamedFramebufferTexture(framebuffer_id, attachment, tex.id(), 0),
ColorAttachment::Buffer(buff) => gl.NamedFramebufferRenderbuffer(framebuffer_id, attachment, gl::RENDERBUFFER, buff.id()),
ColorAttachment::CubeMap(cubemap) => gl.NamedFramebufferTexture(framebuffer_id, attachment, cubemap.id(), 0),
}
}
unsafe fn color_attach(&self, gl: &Gl, target: GLenum, attachment: GLuint) {
match self.borrow(){
ColorAttachment::Texture(tex) => gl.FramebufferTexture2D(target, attachment, tex.target(), tex.id(), 0),
ColorAttachment::Buffer(buff) => gl.FramebufferRenderbuffer(target, attachment, gl::RENDERBUFFER, buff.id()),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(cubemap) => gl.FramebufferTexture(target, attachment, cubemap.id(), 0),
}
}
fn width(&self) -> u32{
match self.borrow(){
ColorAttachment::Texture(tex) => tex.width(),
ColorAttachment::Buffer(buff) => buff.width(),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(cubemap) => cubemap.width(),
}
}
fn height(&self) -> u32{
match self.borrow(){
ColorAttachment::Texture(tex) => tex.height(),
ColorAttachment::Buffer(buff) => buff.height(),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(cubemap) => cubemap.height(),
}
}
fn samples(&self) -> u32{
match self.borrow(){
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
ColorAttachment::Texture(tex) => tex.samples(),
#[cfg(any(feature = "gles", feature="webgl"))]
ColorAttachment::Texture(_tex) => 0,
ColorAttachment::Buffer(buff) => buff.samples(),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(cubemap) => 0,
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Copy,Clone,Debug)]
#[repr(u32)]
pub enum ColorFormat{
R8 = gl::R8,
R16 = gl::R16,
R32F = gl::R32F,
RG8 = gl::RG8,
RG16 = gl::RG16,
RG32F = gl::RG32F,
RGB8 = gl::RGB8,
RGB16 = gl::RGB16,
RGB16F = gl::RGB16F,
RGB32F = gl::RGB32F,
RGBA8 = gl::RGBA8,
RGBA16 = gl::RGBA16,
RGBA16F = gl::RGBA16F,
RGBA32F = gl::RGBA32F,
}
#[cfg(any(feature = "gles", feature="webgl"))]
#[derive(Copy,Clone,Debug)]
#[repr(u32)]
pub enum ColorFormat{
R8 = gl::R8,
R32F = gl::R32F,
RG8 = gl::RG8,
RG32F = gl::RG32F,
RGB8 = gl::RGB8,
RGB16F = gl::RGB16F,
RGB32F = gl::RGB32F,
RGBA8 = gl::RGBA8,
RGBA16F = gl::RGBA16F,
RGBA32F = gl::RGBA32F,
}
impl Default for ColorFormat{
fn default() -> ColorFormat{
ColorFormat::RGBA8
}
}
impl ColorFormat{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn from(internal_format: GLenum) -> Option<ColorFormat>{
let format = match internal_format{
gl::R8 => ColorFormat::R8,
gl::R16 => ColorFormat::R16,
gl::R32F => ColorFormat::R32F,
gl::RG8 => ColorFormat::RG8,
gl::RG16 => ColorFormat::RG16,
gl::RG32F => ColorFormat::RG32F,
gl::RGB8 => ColorFormat::RGB8,
gl::RGB16 => ColorFormat::RGB16,
gl::RGB16F => ColorFormat::RGB16F,
gl::RGB32F => ColorFormat::RGB32F,
gl::RGBA8 => ColorFormat::RGBA8,
gl::RGBA16 => ColorFormat::RGBA16,
gl::RGBA16F => ColorFormat::RGBA16F,
gl::RGBA32F => ColorFormat::RGBA32F,
_ => return None,
};
Some(format)
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn from(internal_format: GLenum) -> Option<ColorFormat>{
let format = match internal_format{
gl::R8 => ColorFormat::R8,
gl::R32F => ColorFormat::R32F,
gl::RG8 => ColorFormat::RG8,
gl::RG32F => ColorFormat::RG32F,
gl::RGB8 => ColorFormat::RGB8,
gl::RGB16F => ColorFormat::RGB16F,
gl::RGB32F => ColorFormat::RGB32F,
gl::RGBA8 => ColorFormat::RGBA8,
gl::RGBA16F => ColorFormat::RGBA16F,
gl::RGBA32F => ColorFormat::RGBA32F,
_ => return None,
};
Some(format)
}
}
pub struct ColorAttachmentBuilder<'a>(pub(crate) &'a StateRef);
impl<'a> ColorAttachmentBuilder<'a>{
pub fn texture(&self, w: u32, h: u32, format: ColorFormat) -> ::Result<ColorAttachment>{
let tex = texture::Builder(self.0).from_format(texture::Format{
target: gl::TEXTURE_2D,
internal_format: format as GLenum,
width: w,
height: h,
levels: 1,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: 0,
})?;
Ok(ColorAttachment::Texture(tex))
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn texture_multisampled(&self, w: u32, h: u32, samples: u32, format: ColorFormat) -> ::Result<ColorAttachment>{
let tex = texture::Builder(self.0).from_format(texture::Format{
target: gl::TEXTURE_2D_MULTISAMPLE,
internal_format: format as GLenum,
width: w,
height: h,
levels: 1,
samples: samples,
})?;
Ok(ColorAttachment::Texture(tex))
}
pub fn render_buffer(&self, w: u32, h: u32, format: ColorFormat) -> ::Result<ColorAttachment>{
let buffer = RenderBufferBuilder(self.0).create(w, h, format as GLenum)?;
Ok(ColorAttachment::Buffer(buffer))
}
pub fn render_buffer_multisampled(&self, w: u32, h: u32, samples: u32, format: ColorFormat) -> ::Result<ColorAttachment>{
let buffer = RenderBufferBuilder(self.0).create_multisampled(w, h, samples, format as GLenum)?;
Ok(ColorAttachment::Buffer(buffer))
}
#[cfg(not(feature="webgl"))]
pub fn cubemap(&self, w: u32, h: u32, format: ColorFormat) -> ::Result<ColorAttachment>{
let cubemap = cubemap::Builder(self.0).from_format(cubemap::Format{
internal_format: format as GLenum,
width: w,
height: h,
levels: 1})?;
Ok(ColorAttachment::CubeMap(cubemap))
}
}
impl ColorAttachment{
pub fn width(&self) -> u32{
match self{
ColorAttachment::Texture(tex) => tex.width(),
ColorAttachment::Buffer(buff) => buff.width(),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(cm) => cm.width(),
}
}
pub fn height(&self) -> u32{
match self{
ColorAttachment::Texture(tex) => tex.height(),
ColorAttachment::Buffer(buff) => buff.height(),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(cm) => cm.height(),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn samples(&self) -> u32{
match self{
ColorAttachment::Texture(tex) => tex.samples(),
ColorAttachment::Buffer(buff) => buff.samples(),
ColorAttachment::CubeMap(_) => 0,
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn samples(&self) -> u32{
match self{
ColorAttachment::Texture(_) => 0,
ColorAttachment::Buffer(buff) => buff.samples(),
#[cfg(not(feature="webgl"))]
ColorAttachment::CubeMap(_) => 0,
}
}
}
pub enum DepthAttachment{
Texture(Texture),
Buffer(RenderBuffer),
#[cfg(not(feature="webgl"))]
CubeMap(CubeMap),
}
#[derive(Copy,Clone,Debug)]
#[repr(u32)]
pub enum DepthFormat{
_16 = gl::DEPTH_COMPONENT16,
_24 = gl::DEPTH_COMPONENT24,
_32 = gl::DEPTH_COMPONENT32F,
}
impl Default for DepthFormat{
fn default() -> DepthFormat{
DepthFormat::_24
}
}
impl DepthFormat{
pub fn from(internal_format: GLenum) -> Option<DepthFormat>{
let format = match internal_format{
gl::DEPTH_COMPONENT16 => DepthFormat::_16,
gl::DEPTH_COMPONENT24 => DepthFormat::_24,
gl::DEPTH_COMPONENT32F => DepthFormat::_32,
_ => return None,
};
Some(format)
}
}
pub struct DepthAttachmentBuilder<'a>(pub(crate) &'a StateRef);
impl<'a> DepthAttachmentBuilder<'a>{
pub fn texture(&self, w: u32, h: u32, format: DepthFormat) -> ::Result<DepthAttachment>{
let tex = texture::Builder(self.0).from_format(texture::Format{
target: gl::TEXTURE_2D,
internal_format: format as GLenum,
width: w,
height: h,
levels: 1,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: 0,
})?;
Ok(DepthAttachment::Texture(tex))
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn texture_multisampled(&self, w: u32, h: u32, samples: u32, format: DepthFormat) -> ::Result<DepthAttachment>{
let tex = texture::Builder(self.0).from_format(texture::Format{
target: gl::TEXTURE_2D_MULTISAMPLE,
internal_format: format as GLenum,
width: w,
height: h,
levels: 1,
samples: samples,
})?;
Ok(DepthAttachment::Texture(tex))
}
pub fn render_buffer(&self, w: u32, h: u32, format: DepthFormat) -> ::Result<DepthAttachment>{
let buffer = RenderBufferBuilder(self.0).create(w, h, format as GLenum)?;
Ok(DepthAttachment::Buffer(buffer))
}
pub fn render_buffer_multisampled(&self, w: u32, h: u32, samples: u32, format: DepthFormat) -> ::Result<DepthAttachment>{
let buffer = RenderBufferBuilder(self.0).create_multisampled(w, h, samples, format as GLenum)?;
Ok(DepthAttachment::Buffer(buffer))
}
#[cfg(not(feature="webgl"))]
pub fn cubemap(&self, w: u32, h: u32, format: DepthFormat) -> ::Result<DepthAttachment>{
let cubemap = cubemap::Builder(self.0).from_format(cubemap::Format{
internal_format: format as GLenum,
width: w,
height: h,
levels: 1})?;
Ok(DepthAttachment::CubeMap(cubemap))
}
}
impl DepthAttachment{
pub fn width(&self) -> u32{
match self{
DepthAttachment::Texture(tex) => tex.width(),
DepthAttachment::Buffer(buff) => buff.width(),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(cm) => cm.width(),
}
}
pub fn height(&self) -> u32{
match self{
DepthAttachment::Texture(tex) => tex.height(),
DepthAttachment::Buffer(buff) => buff.height(),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(cm) => cm.height(),
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn samples(&self) -> u32{
match self{
DepthAttachment::Texture(tex) => tex.samples(),
DepthAttachment::Buffer(buff) => buff.samples(),
DepthAttachment::CubeMap(_) => 0,
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn samples(&self) -> u32{
match self{
DepthAttachment::Texture(_) => 0,
DepthAttachment::Buffer(buff) => buff.samples(),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(_) => 0,
}
}
}
pub trait DepthAttach{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn dsa_depth_attach(&self, gl: &Gl, framebuffer_id: GLuint, attachment: GLuint);
unsafe fn depth_attach(&self, gl: &Gl, target: GLenum, attachment: GLuint);
fn width(&self) -> u32;
fn height(&self) -> u32;
fn samples(&self) -> u32;
}
pub struct DepthAttachmentCubemapFace<'a>{
pub cubemap: &'a ::CubeMap,
pub face: GLenum,
pub level: i32,
}
impl<'a> DepthAttach for DepthAttachmentCubemapFace<'a>{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn dsa_depth_attach(&self, gl: &Gl, framebuffer_id: GLuint, attachment: GLuint){
gl.NamedFramebufferTextureLayer(framebuffer_id, attachment, self.cubemap.id(), self.level, (self.face - gl::TEXTURE_CUBE_MAP_POSITIVE_X) as i32);
}
unsafe fn depth_attach(&self, gl: &Gl, target: GLenum, attachment: GLuint) {
gl.FramebufferTexture2D(target, attachment, self.face, self.cubemap.id(), self.level);
}
fn width(&self) -> u32{
self.cubemap.width() >> self.level
}
fn height(&self) -> u32{
self.cubemap.height() >> self.level
}
fn samples(&self) -> u32{
0
}
}
impl<D: Borrow<DepthAttachment>> DepthAttach for D{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn dsa_depth_attach(&self, gl: &Gl, framebuffer_id: GLuint, attachment: GLuint){
match self.borrow(){
DepthAttachment::Texture(tex) => gl.NamedFramebufferTexture(framebuffer_id, attachment, tex.id(), 0),
DepthAttachment::Buffer(buff) => gl.NamedFramebufferRenderbuffer(framebuffer_id, attachment, gl::RENDERBUFFER, buff.id()),
DepthAttachment::CubeMap(cubemap) => gl.NamedFramebufferTexture(framebuffer_id, attachment, cubemap.id(), 0),
}
}
unsafe fn depth_attach(&self, gl: &Gl, target: GLenum, attachment: GLuint) {
match self.borrow(){
DepthAttachment::Texture(tex) => gl.FramebufferTexture2D(target, attachment, tex.target(), tex.id(), 0),
DepthAttachment::Buffer(buff) => gl.FramebufferRenderbuffer(target, attachment, gl::RENDERBUFFER, buff.id()),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(cubemap) => gl.FramebufferTexture(target, attachment, cubemap.id(), 0),
}
}
fn width(&self) -> u32{
match self.borrow(){
DepthAttachment::Texture(tex) => tex.width(),
DepthAttachment::Buffer(buff) => buff.width(),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(cubemap) => cubemap.width(),
}
}
fn height(&self) -> u32{
match self.borrow(){
DepthAttachment::Texture(tex) => tex.height(),
DepthAttachment::Buffer(buff) => buff.height(),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(cubemap) => cubemap.height(),
}
}
fn samples(&self) -> u32{
match self.borrow(){
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
DepthAttachment::Texture(tex) => tex.samples(),
#[cfg(any(feature = "gles", feature="webgl"))]
DepthAttachment::Texture(_tex) => 0,
DepthAttachment::Buffer(buff) => buff.samples(),
#[cfg(not(feature="webgl"))]
DepthAttachment::CubeMap(cubemap) => 0,
}
}
}