use super::*;
use super::errors::*;
use std::ffi::CString;
use std::mem::uninitialized;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ShaderProgramId(u32);
impl From<ShaderProgramId> for u32 {
fn from(shader_id: ShaderProgramId) -> Self {
shader_id.0
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ShaderProgramParameter {
DeleteStatus,
LinkStatus,
ValidateStatus,
InfoLogLength,
AttachedShaders,
ActiveAtomicCounterBuffers,
ActiveAttributes,
ActiveAttributeMaxLength,
ActiveUniforms,
ActiveUniformBlocks,
ActiveUniformBlockMaxNameLength,
ActiveUniformMaxLength,
ComputeWorkGroupSize,
ProgramBinaryLength,
TransformFeedbackBufferMode,
TransformFeedbackVaryings,
TransformFeedbackVaryingMaxLength,
GeometryVerticesOut,
GeometryInputType,
GeometryOutputType,
}
impl From<ShaderProgramParameter> for u32 {
fn from(parameter: ShaderProgramParameter) -> Self {
use self::ShaderProgramParameter::*;
match parameter {
DeleteStatus => gl::DELETE_STATUS,
LinkStatus => gl::LINK_STATUS,
ValidateStatus => gl::VALIDATE_STATUS,
InfoLogLength => gl::INFO_LOG_LENGTH,
AttachedShaders => gl::ATTACHED_SHADERS,
ActiveAtomicCounterBuffers => gl::ACTIVE_ATOMIC_COUNTER_BUFFERS,
ActiveAttributes => gl::ACTIVE_ATTRIBUTES,
ActiveAttributeMaxLength => gl::ACTIVE_ATTRIBUTE_MAX_LENGTH,
ActiveUniforms => gl::ACTIVE_UNIFORMS,
ActiveUniformBlocks => gl::ACTIVE_UNIFORM_BLOCKS,
ActiveUniformBlockMaxNameLength => gl::ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
ActiveUniformMaxLength => gl::ACTIVE_UNIFORM_MAX_LENGTH,
ComputeWorkGroupSize => gl::COMPUTE_WORK_GROUP_SIZE,
ProgramBinaryLength => gl::PROGRAM_BINARY_LENGTH,
TransformFeedbackBufferMode => gl::TRANSFORM_FEEDBACK_BUFFER_MODE,
TransformFeedbackVaryings => gl::TRANSFORM_FEEDBACK_VARYINGS,
TransformFeedbackVaryingMaxLength => gl::TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH,
GeometryVerticesOut => gl::GEOMETRY_VERTICES_OUT,
GeometryInputType => gl::GEOMETRY_INPUT_TYPE,
GeometryOutputType => gl::GEOMETRY_OUTPUT_TYPE,
}
}
}
pub unsafe fn create_shader_program<T: AsRef<str>>(gl_type: ShaderType, sources: &[T]) -> Result<ShaderProgramId> {
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();
let id = gl::CreateShaderProgramv(gl_type.into(), 1, [source_cstr.as_ptr()].as_ptr());
get_error(ShaderProgramId(id))
}
pub unsafe fn delete_shader_program(id: ShaderProgramId) {
gl::DeleteProgram(id.into());
}
pub unsafe fn get_shader_program(id: ShaderProgramId, parameter: ShaderProgramParameter) -> Result<i32> {
let mut value: gl::types::GLint = uninitialized();
gl::GetProgramiv(id.into(), parameter.into(), &mut value);
get_error(value)
}
pub unsafe fn get_shader_program_info_log(id: ShaderProgramId) -> Result<String> {
let mut error_log_size: gl::types::GLint =
get_shader_program(id.into(), ShaderProgramParameter::InfoLogLength).chain_err(|| "Could not get log length")?;
let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as usize);
gl::GetProgramInfoLog(
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)
}