e2r 0.2.0

experimental rendering engine in rust
Documentation
extern crate gl;

use std::str;

#[derive(Clone)]
#[derive(Copy)]
pub enum ShaderType {
    VERTEX,
    FRAGMENT,
}

/// inputs: shader src as str, shader type.
/// outputs: shader handle
pub fn load_and_compile_shader( shader_src : &str, shader_type: ShaderType ) -> Result< gl::types::GLuint, String > {
    unsafe {
        let handle = match shader_type {
            ShaderType::VERTEX => gl::CreateShader( gl::VERTEX_SHADER ),
            ShaderType::FRAGMENT =>  gl::CreateShader( gl::FRAGMENT_SHADER ),
        };
        assert!( handle != 0 );
        let shader_src_arr = [ shader_src.as_ptr() as * const i8 ];
        let shader_src_len_arr = [ shader_src.len() as i32 ];
        gl::ShaderSource( handle, shader_src_arr.len() as i32, shader_src_arr.as_ptr(), &shader_src_len_arr[0] );
        gl::CompileShader( handle );
        let mut result = -1;
        gl::GetShaderiv( handle, gl::COMPILE_STATUS, & mut result );
        if 0 == result {
            let mut log_len = 0;
            gl::GetShaderiv( handle, gl::INFO_LOG_LENGTH, & mut log_len );
            let log = vec![ 0i8; log_len as usize ];
            if log_len > 0 {
                let mut written = 0;
                gl::GetShaderInfoLog( handle, log_len, & mut written, log.as_ptr() as * mut i8 );
                let log_u8 = log.iter().map(|&x| x as u8 ).collect::<Vec<u8> >();
                let log_str = str::from_utf8( &log_u8[..] ).unwrap();
                return Err( String::from( log_str ) )
            }else{
                return Err( String::from( "unknown error during shader compilation" ) )
            }
        }
        return Ok( handle )
    }
}

pub fn check_program_link( handle: gl::types::GLuint ) -> Result< (), String > {
    let mut status = -1;
    unsafe {
        gl::GetProgramiv( handle, gl::LINK_STATUS, & mut status );
        if gl::FALSE as i32 == status {
            let mut log_len = -1;
            println!("get link status log length");
            gl::GetProgramiv( handle, gl::INFO_LOG_LENGTH, & mut log_len );
            println!( "log length: {}", log_len );
            check_last_op();
            let log = vec![ 0i8; log_len as usize ];
            if log_len > 0 {
                let mut written = 0;
                println!("get link status log");
                gl::GetProgramInfoLog( handle, log_len, & mut written, log.as_ptr() as * mut i8 );
                check_last_op();
                let log_u8 = log.iter().map(|&x| x as u8 ).collect::<Vec<u8> >();
                let log_str = str::from_utf8( &log_u8[..] ).unwrap();
                return Err( String::from( log_str ) )
            } else {
                return Err( String::from("unknown error during program linkage") )
            }
        }else{
            return Ok(())
        }
    }
}

pub fn check_last_op() {
    unsafe {
        let err = gl::GetError();
        match err {
            gl::NO_ERROR => (),
            gl::INVALID_ENUM => panic!("invalid_enum"),
            gl::INVALID_VALUE => panic!("invalid_value"),
            gl::INVALID_OPERATION => panic!("invalid_operation"),
            gl::INVALID_FRAMEBUFFER_OPERATION => panic!("invalid_framebuffer_operation"),
            gl::OUT_OF_MEMORY => panic!("out_of_memory"),
            gl::STACK_OVERFLOW => panic!("stack_overflow"),
            _ => panic!("unknown"),
        }
    }
}

pub fn create_program_from_shaders( shader_handles: &[ gl::types::GLuint ] ) -> gl::types::GLuint {
    create_program_from_shaders_with( shader_handles, | _program, _shader_handles | () ) //insert dummy lambda
}
    
pub fn create_program_from_shaders_with< F >( shader_handles: &[ gl::types::GLuint ], f: F ) -> gl::types::GLuint  where F: Fn( gl::types::GLuint, &[ gl::types::GLuint ] )->() {
    unsafe {
        let gl_program = gl::CreateProgram();
        if gl_program == 0 {
            panic!("gl_program creation failed");
        }
        for i in shader_handles.into_iter() {
            gl::AttachShader( gl_program, *i );
        }
        // additional operation before linking program
        f( gl_program, shader_handles );
        gl::LinkProgram( gl_program );
        match check_program_link( gl_program ) {
            Err( o ) => panic!( "{}", o ),
            _ => ()
        }
        return gl_program
    }
}

pub fn delete_shader_program( handle: i64 ){
    unsafe {
        gl::DeleteProgram( handle as gl::types::GLuint );
    }
}
pub fn query_uniform_float_array( program: gl::types::GLuint, name: String ){
    unsafe {
        let loc = gl::GetUniformLocation( program, name.as_ptr() as * const i8 );
        println!("uniform location: {:?}", loc );
        let mut query_val = vec![0f32;32];
        gl::GetUniformfv( program, loc, query_val.as_mut_ptr() );
        check_last_op();
        println!("query uniform float array: {:?}", query_val );
    }
}

pub fn load_texture( program: gl::types::GLuint, texture_number: gl::types::GLuint, image: &[u8], w: usize, h: usize ) -> Result< gl::types::GLuint, String > {
    let mut tex : gl::types::GLuint = 0;
    //todo: mipmap
    unsafe {
        gl::GenTextures(1, & mut tex);
        gl::ActiveTexture(gl::TEXTURE0 + texture_number);
        gl::BindTexture( gl::TEXTURE_2D, tex );
        gl::TexImage2D( gl::TEXTURE_2D, 0, gl::RGB as _, w as _, h as _, 0, gl::RGB, gl::UNSIGNED_BYTE, image.as_ptr() as _ );
        gl::Uniform1i( gl::GetUniformLocation( program, b"tex\0".as_ptr() as _ ), 0 );
        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as _ );
        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as _ );
        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as _ );
        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as _ );
    }
    Ok( tex )
}

pub fn delete_texture( handle: gl::types::GLuint ) -> Result< (), String > {
    unsafe {
        gl::DeleteTextures(1, &handle);
    }
    Ok( () )
}