2022-11-14 17:49:51 +11:00
|
|
|
use gl::types::{GLenum, GLsizei, GLuint};
|
2022-11-20 14:03:58 +11:00
|
|
|
use librashader::{FilterMode, ShaderFormat, WrapMode};
|
|
|
|
use librashader_presets::{Scale2D, ScaleType, Scaling};
|
2022-11-14 17:49:51 +11:00
|
|
|
use crate::util;
|
2022-11-20 14:03:58 +11:00
|
|
|
use crate::util::{GlImage, Size, Texture, Viewport};
|
2022-11-14 17:49:51 +11:00
|
|
|
|
2022-11-20 14:03:58 +11:00
|
|
|
#[derive(Debug)]
|
2022-11-14 17:49:51 +11:00
|
|
|
pub struct Framebuffer {
|
|
|
|
pub image: GLuint,
|
|
|
|
pub size: Size,
|
|
|
|
pub format: GLenum,
|
|
|
|
pub max_levels: u32,
|
|
|
|
pub levels: u32,
|
2022-11-20 15:16:19 +11:00
|
|
|
pub handle: GLuint,
|
2022-11-14 17:49:51 +11:00
|
|
|
pub init: bool
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Framebuffer {
|
|
|
|
pub fn new(max_levels: u32) -> Framebuffer {
|
|
|
|
let mut framebuffer = 0;
|
|
|
|
unsafe {
|
|
|
|
gl::GenFramebuffers(1, &mut framebuffer);
|
|
|
|
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
|
2022-11-19 17:55:49 +11:00
|
|
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
2022-11-14 17:49:51 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
Framebuffer {
|
|
|
|
image: 0,
|
|
|
|
size: Size { width: 1, height: 1 },
|
|
|
|
format: 0,
|
|
|
|
max_levels,
|
|
|
|
levels: 0,
|
2022-11-20 15:16:19 +11:00
|
|
|
handle: framebuffer,
|
2022-11-14 17:49:51 +11:00
|
|
|
init: false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-20 14:03:58 +11:00
|
|
|
pub fn new_from_raw(texture: GLuint, handle: GLuint, format: GLenum, size: Size, miplevels: u32) -> Framebuffer {
|
|
|
|
Framebuffer {
|
|
|
|
image: texture,
|
|
|
|
size,
|
|
|
|
format,
|
|
|
|
max_levels: miplevels,
|
|
|
|
levels: miplevels,
|
2022-11-20 15:16:19 +11:00
|
|
|
handle: handle,
|
2022-11-20 14:03:58 +11:00
|
|
|
init: true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
|
|
|
|
Texture {
|
|
|
|
image: GlImage {
|
|
|
|
handle: self.image,
|
|
|
|
format: self.format,
|
|
|
|
size: self.size,
|
|
|
|
padded_size: Default::default()
|
|
|
|
},
|
|
|
|
filter,
|
|
|
|
mip_filter: filter,
|
|
|
|
wrap_mode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn scale(&mut self, scaling: Scale2D, format: ShaderFormat, viewport: &Viewport, original: &Texture, source: &Texture) -> Size {
|
|
|
|
let mut width = 0f32;
|
|
|
|
let mut height = 0f32;
|
|
|
|
|
|
|
|
match scaling.x {
|
|
|
|
Scaling {
|
|
|
|
scale_type: ScaleType::Input,
|
|
|
|
factor
|
|
|
|
} => {
|
|
|
|
width = source.image.size.width * factor
|
|
|
|
},
|
|
|
|
Scaling {
|
|
|
|
scale_type: ScaleType::Absolute,
|
|
|
|
factor
|
|
|
|
} => {
|
|
|
|
width = factor.into()
|
|
|
|
}
|
|
|
|
Scaling {
|
|
|
|
scale_type: ScaleType::Viewport,
|
|
|
|
factor
|
|
|
|
} => {
|
|
|
|
width = viewport.output.size.width * factor
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
match scaling.y {
|
|
|
|
Scaling {
|
|
|
|
scale_type: ScaleType::Input,
|
|
|
|
factor
|
|
|
|
} => {
|
|
|
|
height = source.image.size.height * factor
|
|
|
|
},
|
|
|
|
Scaling {
|
|
|
|
scale_type: ScaleType::Absolute,
|
|
|
|
factor
|
|
|
|
} => {
|
|
|
|
height = factor.into()
|
|
|
|
}
|
|
|
|
Scaling {
|
|
|
|
scale_type: ScaleType::Viewport,
|
|
|
|
factor
|
|
|
|
} => {
|
|
|
|
height = viewport.output.size.height * factor
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let size = Size {
|
|
|
|
width: width.round() as u32,
|
|
|
|
height: height.round() as u32
|
|
|
|
};
|
|
|
|
|
|
|
|
if self.size != size {
|
|
|
|
self.size = size;
|
|
|
|
|
|
|
|
self.init(size,if format == ShaderFormat::Unknown {
|
|
|
|
ShaderFormat::R8G8B8A8Unorm
|
|
|
|
} else {
|
|
|
|
format
|
|
|
|
});
|
|
|
|
}
|
|
|
|
size
|
|
|
|
}
|
|
|
|
|
|
|
|
fn init(&mut self, mut size: Size, mut format: impl Into<GLenum>) {
|
2022-11-19 17:55:49 +11:00
|
|
|
self.format = format.into();
|
2022-11-14 17:49:51 +11:00
|
|
|
self.size = size;
|
|
|
|
|
|
|
|
unsafe {
|
2022-11-20 15:16:19 +11:00
|
|
|
gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle);
|
2022-11-14 17:49:51 +11:00
|
|
|
|
|
|
|
// reset the framebuffer image
|
|
|
|
if self.image != 0 {
|
|
|
|
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0);
|
|
|
|
gl::DeleteTextures(1, &self.image);
|
|
|
|
}
|
|
|
|
|
|
|
|
gl::GenTextures(1, &mut self.image);
|
2022-11-19 17:55:49 +11:00
|
|
|
gl::BindTexture(gl::TEXTURE_2D, self.image);
|
2022-11-14 17:49:51 +11:00
|
|
|
|
|
|
|
if size.width == 0 {
|
|
|
|
size.width = 1;
|
|
|
|
}
|
|
|
|
if size.height == 0 {
|
|
|
|
size.height = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.levels = util::calc_miplevel(size.width, size.height);
|
|
|
|
if self.levels > self.max_levels {
|
|
|
|
self.levels = self.max_levels;
|
|
|
|
}
|
|
|
|
if self.levels == 0 {
|
|
|
|
self.levels = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, self.format, size.width as GLsizei, size.height as GLsizei);
|
|
|
|
gl::FramebufferTexture2D(gl::FRAMEBUFFER,
|
|
|
|
gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0);
|
|
|
|
|
|
|
|
let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
|
|
|
|
if status != gl::FRAMEBUFFER_COMPLETE {
|
|
|
|
match status {
|
|
|
|
gl::FRAMEBUFFER_UNSUPPORTED => {
|
|
|
|
eprintln!("unsupported fbo");
|
|
|
|
|
|
|
|
gl::FramebufferTexture2D(gl::FRAMEBUFFER,
|
|
|
|
gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0);
|
|
|
|
gl::DeleteTextures(1, &self.image);
|
|
|
|
gl::GenTextures(1, &mut self.image);
|
|
|
|
gl::BindTexture(1, self.image);
|
|
|
|
|
|
|
|
self.levels = util::calc_miplevel(size.width, size.height);
|
|
|
|
if self.levels > self.max_levels {
|
|
|
|
self.levels = self.max_levels;
|
|
|
|
}
|
|
|
|
if self.levels == 0 {
|
|
|
|
self.levels = 1;
|
|
|
|
}
|
|
|
|
|
2022-11-19 17:55:49 +11:00
|
|
|
gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, ShaderFormat::R8G8B8A8Unorm.into(), size.width as GLsizei, size.height as GLsizei);
|
2022-11-14 17:49:51 +11:00
|
|
|
gl::FramebufferTexture2D(gl::FRAMEBUFFER,
|
|
|
|
gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0);
|
|
|
|
self.init = gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE;
|
|
|
|
}
|
2022-11-19 17:55:49 +11:00
|
|
|
_ => panic!("failed to complete: {status:x}")
|
2022-11-14 17:49:51 +11:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
self.init = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
|
|
|
gl::BindTexture(gl::TEXTURE_2D, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-11-19 17:55:49 +11:00
|
|
|
|
|
|
|
impl Drop for Framebuffer {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
2022-11-20 15:16:19 +11:00
|
|
|
if self.handle != 0 {
|
|
|
|
gl::DeleteFramebuffers(1, &self.handle);
|
2022-11-19 17:55:49 +11:00
|
|
|
}
|
|
|
|
if self.image != 0 {
|
|
|
|
gl::DeleteTextures(1, &self.image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|