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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
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<T: AsRef<str>>(id: ShaderId, sources: &[T]) {
    let mut source: String = String::new();
    for s in sources {
        source.push_str(s.as_ref());
    }
    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())
}

pub unsafe fn get_shader_compiled(id: ShaderId) -> bool {
    get_shader(id.into(), ShaderParameter::CompileStatus) == 1
}

pub unsafe fn shader_binary(id: ShaderId, data: &[u8]) -> Result<()> {
    gl::ShaderBinary(
        1,
        &(id.0) as &u32 as *const u32,
        gl::SHADER_BINARY_FORMAT_SPIR_V_ARB,
        data.as_ptr() as *const ::std::os::raw::c_void,
        data.len() as i32,
    );

    get_error(())
}

pub unsafe fn specialize_shader(id: ShaderId) -> Result<()> {
    let entry_point = ::std::ffi::CString::new("main").unwrap();
    gl::SpecializeShaderARB(
        id.into(),
        entry_point.as_ptr(),
        0,
        ::std::ptr::null(),
        ::std::ptr::null(),
    );

    get_error(())
}