use gl::{self, types::*};
use state::StateRef;
#[cfg(feature = "gles")]
use std::ptr;
pub struct FrameBuffer{
id: GLuint,
gl: StateRef,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
is_dsa: bool,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
needs_intel_hack: bool,
}
impl Drop for FrameBuffer{
fn drop(&mut self){
unsafe{
self.gl.DeleteFramebuffers(1, &self.id);
}
}
}
impl PartialEq for FrameBuffer {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for FrameBuffer {}
impl FrameBuffer{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_dsa(gl: StateRef) -> FrameBuffer {
let mut id: GLuint = 0;
#[cfg(target_os="windows")]
let needs_intel_hack = gl.capabilities().vendor == Vendor::Intel;
#[cfg(not(target_os="windows"))]
let needs_intel_hack = false;
unsafe{
gl.CreateFramebuffers(1, &mut id);
FrameBuffer{
id,
gl,
is_dsa: true,
needs_intel_hack,
}
}
}
pub fn new_bind(gl: StateRef) -> FrameBuffer {
let mut id: GLuint = 0;
unsafe{
gl.GenFramebuffers(1, &mut id);
FrameBuffer{
id,
gl,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
is_dsa: false,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
needs_intel_hack: false,
}
}
}
pub fn new(gl: StateRef) -> FrameBuffer {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
{
if gl.capabilities().supports_dsa(){
return FrameBuffer::new_dsa(gl)
}
}
FrameBuffer::new_bind(gl)
}
pub fn id(&self) -> GLuint {
self.id
}
pub fn bind(&self){
unsafe{
self.gl.BindFramebuffer(gl::FRAMEBUFFER, self.id);
}
}
pub fn unbind(&self){
unsafe{
self.gl.BindFramebuffer(gl::FRAMEBUFFER, 0)
}
}
pub fn check_status(&self) -> u32{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe{
if self.is_dsa {
return self.gl.CheckNamedFramebufferStatus(self.id, gl::FRAMEBUFFER)
}
}
unsafe{
let status = self.gl.CheckFramebufferStatus(gl::FRAMEBUFFER);
status
}
}
pub fn set_drawbuffers(&self, attachments: &[GLenum]){
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe{
if self.is_dsa {
self.gl.NamedFramebufferDrawBuffers(
self.id,
attachments.len() as i32,
attachments.as_ptr());
return;
}
}
unsafe{
#[cfg(not(feature="webgl"))]
self.gl.DrawBuffers(attachments.len() as i32, attachments.as_ptr());
#[cfg(feature="webgl")]
self.gl.DrawBuffers(&attachments);
}
}
pub fn set_no_drawbuffers(&self){
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe{
if self.is_dsa{
self.gl.NamedFramebufferDrawBuffer(self.id, gl::NONE);
return;
}
}
unsafe{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
self.gl.DrawBuffer(gl::NONE);
#[cfg(feature = "gles")]
self.gl.DrawBuffers(0, ptr::null());
#[cfg(feature = "webgl")]
self.gl.DrawBuffers(&[]);
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn needs_intel_hack(&self) -> bool {
self.needs_intel_hack
}
pub fn gl(&self) -> &StateRef {
&self.gl
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn is_dsa(&self) -> bool {
self.is_dsa
}
#[cfg(any(feature = "gles", feature="webgl"))]
pub fn is_dsa(&self) -> bool{
false
}
pub fn attach_texture(&self, texture: GLuint, textarget: GLenum, level: GLint, target: GLenum, attachment: GLenum) {
unsafe {
if self.is_dsa() {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
self.gl.NamedFramebufferTexture(self.id, attachment, texture, level)
}else{
self.gl.FramebufferTexture2D(target, attachment, textarget, texture, level)
}
}
}
pub fn attach_render_buffer(&self, renderbuffer: GLuint, target: GLenum, attachment: GLenum) {
unsafe {
if self.is_dsa() {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
self.gl.NamedFramebufferRenderbuffer(self.id, attachment, gl::RENDERBUFFER, renderbuffer)
}else{
self.gl.FramebufferRenderbuffer(target, attachment, gl::RENDERBUFFER, renderbuffer)
}
}
}
#[cfg(not(feature="webgl"))]
pub fn attach_cubemap(&self, cubemap: GLuint, level: GLint, target: GLenum, attachment: GLenum) {
unsafe{
if self.is_dsa() {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
self.gl.NamedFramebufferTexture(self.id, attachment, cubemap, level)
}else{
self.gl.FramebufferTexture(target, attachment, cubemap, level)
}
}
}
pub fn attach_cubemap_face(&self, cubemap: GLuint, face: GLenum, level: GLint, target: GLenum, attachment: GLenum) {
unsafe{
if self.is_dsa() {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
if self.needs_intel_hack {
if self.gl.capabilities().supports_dsa_ext(){
self.gl.NamedFramebufferTextureFaceEXT(
self.id,
attachment,
cubemap,
level,
face
);
}else{
self.bind();
self.gl.FramebufferTexture2D(
gl::FRAMEBUFFER,
attachment,
face,
cubemap,
level
);
self.unbind();
}
}else{
self.gl.NamedFramebufferTextureLayer(
self.id(),
attachment,
cubemap,
level,
(face - gl::TEXTURE_CUBE_MAP_POSITIVE_X) as i32
);
}
}else{
self.gl.FramebufferTexture2D(target, attachment, face, cubemap, level)
}
}
}
pub fn attach_texture_layer(&self, texture: GLuint, textarget: GLenum, level: GLint, attachment: GLenum, layer: GLint) {
unsafe{
if self.is_dsa() {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
self.gl.NamedFramebufferTextureLayer(
self.id(),
attachment,
texture,
level,
layer,
)
}else{
self.gl.FramebufferTextureLayer(
textarget,
attachment,
texture,
level,
layer
)
}
}
}
}