pel 0.1.0

OpenGL backed framebuffer
Documentation
use std::{ffi::CString, ptr};

use ogl33::{
    consts::{GL_FALSE, GL_FRAGMENT_SHADER, GL_INFO_LOG_LENGTH, GL_LINK_STATUS, GL_VERTEX_SHADER},
    functions::{
        glAttachShader, glCreateProgram, glDeleteProgram, glDetachShader, glGetProgramInfoLog, glGetProgramiv,
        glLinkProgram, glUseProgram,
    },
    types::{GLchar, GLint, GLuint},
};

use crate::Error;

use super::{util, Shader};

pub struct Program {
    id: GLuint,
}

impl Program {
    pub(crate) fn link(shaders: &[Shader]) -> crate::Result<Self> {
        let id: GLuint = unsafe { glCreateProgram() };

        for shader in shaders {
            unsafe {
                glAttachShader(id, shader.id());
            }
        }

        unsafe {
            glLinkProgram(id);
        }

        for shader in shaders {
            unsafe {
                glDetachShader(id, shader.id());
            }
        }

        let mut status: GLint = GL_FALSE as GLint;
        unsafe {
            glGetProgramiv(id, GL_LINK_STATUS, &mut status);
        }

        if status == GL_FALSE as GLint {
            let mut len: GLint = 0;
            unsafe {
                glGetProgramiv(id, GL_INFO_LOG_LENGTH, &mut len);
            }

            let info = unsafe {
                let info: *mut GLchar = util::make_gl_str(len);
                glGetProgramInfoLog(id, len, ptr::null_mut(), info);

                CString::from_raw(info)
            };

            unsafe {
                glDeleteProgram(id);
            }

            Err(Error::LinkProgram(info.to_string_lossy().into_owned()))
        } else {
            unsafe {
                glUseProgram(id);
            }

            Ok(Self { id })
        }
    }
}

impl Default for Program {
    fn default() -> Self {
        let vs_src = CString::new(include_str!("src/default.vs"))
            .expect("Default vertex shader source code is not a valid C string");
        let vs_bin = Shader::compile(&vs_src, GL_VERTEX_SHADER).expect("Could not compile default vertex shader");

        let fs_src = CString::new(include_str!("src/default.fs"))
            .expect("Default fragment shader source code is not a valid C string");
        let fs_bin = Shader::compile(&fs_src, GL_FRAGMENT_SHADER).expect("Could not compile default fragment shader");

        Self::link(&[vs_bin, fs_bin]).expect("Could not link default program")
    }
}

impl Drop for Program {
    fn drop(&mut self) {
        unsafe {
            glDeleteProgram(self.id);
        }
    }
}