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(())
}