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
140
141
142
143
144
145
146
147
148
149
150
151
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( () )
}