e2rcore/implement/render/
util_gl.rs

1extern crate gl;
2extern crate pretty_env_logger;
3
4use std::str;
5
6#[derive(Clone)]
7#[derive(Copy)]
8pub enum ShaderType {
9    VERTEX,
10    FRAGMENT,
11}
12
13/// inputs: shader src as str, shader type.
14/// outputs: shader handle
15pub fn load_and_compile_shader( shader_src : &str, shader_type: ShaderType ) -> Result< gl::types::GLuint, String > {
16    unsafe {
17        let handle = match shader_type {
18            ShaderType::VERTEX => gl::CreateShader( gl::VERTEX_SHADER ),
19            ShaderType::FRAGMENT =>  gl::CreateShader( gl::FRAGMENT_SHADER ),
20        };
21        assert!( handle != 0 );
22        let shader_src_arr = [ shader_src.as_ptr() as * const i8 ];
23        let shader_src_len_arr = [ shader_src.len() as i32 ];
24        gl::ShaderSource( handle, shader_src_arr.len() as i32, shader_src_arr.as_ptr(), &shader_src_len_arr[0] );
25        gl::CompileShader( handle );
26        let mut result = -1;
27        gl::GetShaderiv( handle, gl::COMPILE_STATUS, & mut result );
28        if 0 == result {
29            let mut log_len = 0;
30            gl::GetShaderiv( handle, gl::INFO_LOG_LENGTH, & mut log_len );
31            let log = vec![ 0i8; log_len as usize ];
32            if log_len > 0 {
33                let mut written = 0;
34                gl::GetShaderInfoLog( handle, log_len, & mut written, log.as_ptr() as * mut i8 );
35                let log_u8 = log.iter().map(|&x| x as u8 ).collect::<Vec<u8> >();
36                let log_str = str::from_utf8( &log_u8[..] ).unwrap();
37                return Err( String::from( log_str ) )
38            }else{
39                return Err( String::from( "unknown error during shader compilation" ) )
40            }
41        }
42        return Ok( handle )
43    }
44}
45
46pub fn check_program_link( handle: gl::types::GLuint ) -> Result< (), String > {
47    let mut status = -1;
48    unsafe {
49        gl::GetProgramiv( handle, gl::LINK_STATUS, & mut status );
50        if gl::FALSE as i32 == status {
51            let mut log_len = -1;
52            info!("get link status log length");
53            gl::GetProgramiv( handle, gl::INFO_LOG_LENGTH, & mut log_len );
54            info!( "log length: {}", log_len );
55            check_last_op();
56            let log = vec![ 0i8; log_len as usize ];
57            if log_len > 0 {
58                let mut written = 0;
59                info!("get link status log");
60                gl::GetProgramInfoLog( handle, log_len, & mut written, log.as_ptr() as * mut i8 );
61                check_last_op();
62                let log_u8 = log.iter().map(|&x| x as u8 ).collect::<Vec<u8> >();
63                let log_str = str::from_utf8( &log_u8[..] ).unwrap();
64                return Err( String::from( log_str ) )
65            } else {
66                return Err( String::from("unknown error during program linkage") )
67            }
68        }else{
69            return Ok(())
70        }
71    }
72}
73
74pub fn check_last_op() {
75    unsafe {
76        let err = gl::GetError();
77        match err {
78            gl::NO_ERROR => (),
79            gl::INVALID_ENUM => panic!("invalid_enum"),
80            gl::INVALID_VALUE => panic!("invalid_value"),
81            gl::INVALID_OPERATION => panic!("invalid_operation"),
82            gl::INVALID_FRAMEBUFFER_OPERATION => panic!("invalid_framebuffer_operation"),
83            gl::OUT_OF_MEMORY => panic!("out_of_memory"),
84            gl::STACK_OVERFLOW => panic!("stack_overflow"),
85            _ => panic!("unknown error"),
86        }
87    }
88}
89
90pub fn create_program_from_shaders( shader_handles: &[ gl::types::GLuint ] ) -> gl::types::GLuint {
91    create_program_from_shaders_with( shader_handles, | _program, _shader_handles | () ) //insert dummy lambda
92}
93    
94pub 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 ] )->() {
95    unsafe {
96        let gl_program = gl::CreateProgram();
97        if gl_program == 0 {
98            panic!("gl_program creation failed");
99        }
100        for i in shader_handles.into_iter() {
101            gl::AttachShader( gl_program, *i );
102        }
103        // additional operation before linking program
104        f( gl_program, shader_handles );
105        gl::LinkProgram( gl_program );
106        match check_program_link( gl_program ) {
107            Err( o ) => panic!( "{}", o ),
108            _ => ()
109        }
110        return gl_program
111    }
112}
113
114pub fn delete_shader_program( handle: i64 ){
115    unsafe {
116        gl::DeleteProgram( handle as gl::types::GLuint );
117    }
118}
119pub fn query_uniform_float_array( program: gl::types::GLuint, name: String ){
120    unsafe {
121        let loc = gl::GetUniformLocation( program, name.as_ptr() as * const i8 );
122        trace!("uniform location: {:?}", loc );
123        let mut query_val = vec![0f32;32];
124        gl::GetUniformfv( program, loc, query_val.as_mut_ptr() );
125        check_last_op();
126        trace!("query uniform float array: {:?}", query_val );
127    }
128}
129
130pub fn load_texture( program: gl::types::GLuint, texture_number: gl::types::GLuint, image: &[u8], w: usize, h: usize ) -> Result< gl::types::GLuint, String > {
131    let mut tex : gl::types::GLuint = 0;
132    //todo: mipmap
133    unsafe {
134        gl::GenTextures(1, & mut tex);
135        gl::ActiveTexture(gl::TEXTURE0 + texture_number);
136        gl::BindTexture( gl::TEXTURE_2D, tex );
137        gl::TexImage2D( gl::TEXTURE_2D, 0, gl::RGB as _, w as _, h as _, 0, gl::RGB, gl::UNSIGNED_BYTE, image.as_ptr() as _ );
138        gl::Uniform1i( gl::GetUniformLocation( program, b"tex\0".as_ptr() as _ ), 0 );
139        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as _ );
140        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as _ );
141        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as _ );
142        gl::TexParameteri( gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as _ );
143    }
144    Ok( tex )
145}
146
147pub fn delete_texture( handle: gl::types::GLuint ) -> Result< (), String > {
148    unsafe {
149        gl::DeleteTextures(1, &handle);
150    }
151    Ok( () )
152}