1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
use super::*;
use super::errors::*;

use std::ptr;
use std::ffi::CString;
use std::mem::uninitialized;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderId(u32);

impl From<ShaderId> for u32 {
    fn from(shader_id: ShaderId) -> Self {
        shader_id.0
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ShaderParameter {
    ShaderType,
    DeleteStatus,
    CompileStatus,
    InfoLogLength,
    ShaderSourceLength,
}

impl From<ShaderParameter> for u32 {
    fn from(shader_parameter: ShaderParameter) -> Self {
        use self::ShaderParameter::*;
        match shader_parameter {
            ShaderType => gl::SHADER_TYPE,
            DeleteStatus => gl::DELETE_STATUS,
            CompileStatus => gl::COMPILE_STATUS,
            InfoLogLength => gl::INFO_LOG_LENGTH,
            ShaderSourceLength => gl::SHADER_SOURCE_LENGTH,
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ShaderType {
    Vertex,
    Fragment,
    Geometry,
    TessellationEvaluation,
    TessellationControl,
    Compute,
}

impl From<ShaderType> for u32 {
    fn from(shader_type: ShaderType) -> Self {
        match shader_type {
            ShaderType::Vertex => gl::VERTEX_SHADER,
            ShaderType::Fragment => gl::FRAGMENT_SHADER,
            ShaderType::Geometry => gl::GEOMETRY_SHADER,
            ShaderType::TessellationEvaluation => gl::TESS_EVALUATION_SHADER,
            ShaderType::TessellationControl => gl::TESS_CONTROL_SHADER,
            ShaderType::Compute => gl::COMPUTE_SHADER,
        }
    }
}

pub unsafe fn create_shader(shader_type: ShaderType) -> ShaderId {
    ShaderId(gl::CreateShader(shader_type.into()))
}

pub unsafe fn shader_source(id: ShaderId, sources: &[&str]) {
    let source = sources.join("");
    let source_cstr = CString::new(source.as_bytes()).unwrap();

    gl::ShaderSource(id.into(), 1, [source_cstr.as_ptr()].as_ptr(), ptr::null());
}

pub unsafe fn compile_shader(id: ShaderId) {
    gl::CompileShader(id.into());
}

pub unsafe fn get_shader(id: ShaderId, parameter: ShaderParameter) -> i32 {
    let mut value: gl::types::GLint = uninitialized();

    gl::GetShaderiv(id.into(), parameter.into(), &mut value);

    value
}

pub unsafe fn get_shader_info_log(id: ShaderId) -> Result<String> {
    let mut error_log_size: gl::types::GLint =
        get_shader(id.into(), ShaderParameter::InfoLogLength);

    let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
    gl::GetShaderInfoLog(
        id.into(),
        error_log_size,
        &mut error_log_size,
        error_log.as_mut_ptr() as *mut gl::types::GLchar,
    );

    error_log.set_len(error_log_size as usize);
    let string = match String::from_utf8(error_log) {
        Ok(s) => s,
        Err(_) => bail!("Could not convert log"),
    };

    Ok(string)
}

pub unsafe fn delete_shader(id: ShaderId) {
    gl::DeleteShader(id.into())
}