use super::cache::BufferImportKey;
use super::platform::{GlPlatform, Platform};
use super::shaders::check_gl_error;
use std::ffi::{c_void, CStr};
use std::ptr::null;
pub(super) struct Texture {
pub(super) id: u32,
pub(super) target: edgefirst_gl::gl::types::GLenum,
pub(super) width: usize,
pub(super) height: usize,
pub(super) format: edgefirst_gl::gl::types::GLenum,
bound_egl_key: Option<BufferImportKey>,
}
impl Default for Texture {
fn default() -> Self {
Self::new()
}
}
impl Texture {
pub(super) fn new() -> Self {
let mut id = 0;
unsafe { edgefirst_gl::gl::GenTextures(1, &raw mut id) };
Self {
id,
target: 0,
width: 0,
height: 0,
format: 0,
bound_egl_key: None,
}
}
pub(super) fn update_texture(
&mut self,
target: edgefirst_gl::gl::types::GLenum,
width: usize,
height: usize,
format: edgefirst_gl::gl::types::GLenum,
data: &[u8],
) {
if target != self.target
|| width != self.width
|| height != self.height
|| format != self.format
{
unsafe {
edgefirst_gl::gl::TexImage2D(
target,
0,
format as i32,
width as i32,
height as i32,
0,
format,
edgefirst_gl::gl::UNSIGNED_BYTE,
data.as_ptr() as *const c_void,
);
}
self.target = target;
self.format = format;
self.width = width;
self.height = height;
self.bound_egl_key = None;
} else {
unsafe {
edgefirst_gl::gl::TexSubImage2D(
target,
0,
0,
0,
width as i32,
height as i32,
format,
edgefirst_gl::gl::UNSIGNED_BYTE,
data.as_ptr() as *const c_void,
);
}
}
}
pub(super) unsafe fn bind_egl_image(
&mut self,
display: &<Platform as GlPlatform>::Display,
key: BufferImportKey,
handle: <Platform as GlPlatform>::ImportHandle,
) -> crate::Result<bool> {
if Platform::PERSISTENT_TEX_BINDINGS && self.bound_egl_key == Some(key) {
return Ok(false);
}
Platform::attach_tex_image_2d(display, handle)?;
if Platform::PERSISTENT_TEX_BINDINGS {
self.bound_egl_key = Some(key);
}
Ok(true)
}
pub(super) unsafe fn bind_egl_image_external(
&mut self,
display: &<Platform as GlPlatform>::Display,
key: BufferImportKey,
handle: <Platform as GlPlatform>::ImportHandle,
) -> crate::Result<bool> {
if Platform::PERSISTENT_TEX_BINDINGS && self.bound_egl_key == Some(key) {
return Ok(false);
}
Platform::attach_tex_image_external(display, handle)?;
if Platform::PERSISTENT_TEX_BINDINGS {
self.bound_egl_key = Some(key);
}
Ok(true)
}
pub(super) fn invalidate_egl_binding(&mut self) {
self.bound_egl_key = None;
}
}
impl Drop for Texture {
fn drop(&mut self) {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
edgefirst_gl::gl::DeleteTextures(1, &raw mut self.id)
}));
}
}
pub(super) struct Buffer {
pub(super) id: u32,
pub(super) buffer_index: u32,
}
impl Buffer {
pub(super) fn new(buffer_index: u32, size_per_point: usize, max_points: usize) -> Buffer {
let mut id = 0;
unsafe {
edgefirst_gl::gl::EnableVertexAttribArray(buffer_index);
edgefirst_gl::gl::GenBuffers(1, &raw mut id);
edgefirst_gl::gl::BindBuffer(edgefirst_gl::gl::ARRAY_BUFFER, id);
edgefirst_gl::gl::VertexAttribPointer(
buffer_index,
size_per_point as i32,
edgefirst_gl::gl::FLOAT,
edgefirst_gl::gl::FALSE,
0,
null(),
);
edgefirst_gl::gl::BufferData(
edgefirst_gl::gl::ARRAY_BUFFER,
(size_of::<f32>() * size_per_point * max_points) as isize,
null(),
edgefirst_gl::gl::DYNAMIC_DRAW,
);
}
Buffer { id, buffer_index }
}
}
impl Drop for Buffer {
fn drop(&mut self) {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
edgefirst_gl::gl::DeleteBuffers(1, &raw mut self.id)
}));
}
}
pub(super) struct FrameBuffer {
pub(super) id: u32,
}
impl FrameBuffer {
pub(super) fn new() -> FrameBuffer {
let mut id = 0;
unsafe {
edgefirst_gl::gl::GenFramebuffers(1, &raw mut id);
}
FrameBuffer { id }
}
pub(super) fn bind(&self) {
unsafe { edgefirst_gl::gl::BindFramebuffer(edgefirst_gl::gl::FRAMEBUFFER, self.id) };
}
pub(super) fn unbind(&self) {
unsafe { edgefirst_gl::gl::BindFramebuffer(edgefirst_gl::gl::FRAMEBUFFER, 0) };
}
}
impl Drop for FrameBuffer {
fn drop(&mut self) {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
self.unbind();
unsafe {
edgefirst_gl::gl::DeleteFramebuffers(1, &raw mut self.id);
}
}));
}
}
pub(super) struct GlProgram {
pub(super) id: u32,
}
impl GlProgram {
pub(super) fn new(vertex_shader: &str, fragment_shader: &str) -> Result<Self, crate::Error> {
let id = unsafe { super::core::compile_program(vertex_shader, fragment_shader)? };
unsafe { edgefirst_gl::gl::UseProgram(id) };
Ok(Self { id })
}
pub(super) fn load_uniform_1f(&self, name: &CStr, value: f32) -> Result<(), crate::Error> {
unsafe {
edgefirst_gl::gl::UseProgram(self.id);
let location = edgefirst_gl::gl::GetUniformLocation(self.id, name.as_ptr());
edgefirst_gl::gl::Uniform1f(location, value);
}
Ok(())
}
pub(super) fn load_uniform_1i(&self, name: &CStr, value: i32) -> Result<(), crate::Error> {
unsafe {
edgefirst_gl::gl::UseProgram(self.id);
let location = edgefirst_gl::gl::GetUniformLocation(self.id, name.as_ptr());
edgefirst_gl::gl::Uniform1i(location, value);
}
Ok(())
}
pub(super) fn load_uniform_4fv(
&self,
name: &CStr,
value: &[[f32; 4]],
) -> Result<(), crate::Error> {
unsafe {
edgefirst_gl::gl::UseProgram(self.id);
let location = edgefirst_gl::gl::GetUniformLocation(self.id, name.as_ptr());
if location == -1 {
return Err(crate::Error::OpenGl(format!(
"Could not find uniform location for '{}'",
name.to_string_lossy().into_owned()
)));
}
edgefirst_gl::gl::Uniform4fv(
location,
value.len() as i32,
value.as_flattened().as_ptr(),
);
}
check_gl_error(function!(), line!())?;
Ok(())
}
}
impl Drop for GlProgram {
fn drop(&mut self) {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| unsafe {
edgefirst_gl::gl::DeleteProgram(self.id);
}));
}
}