Skip to main content

cognitive_graphics/
gl_tools.rs

1// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
2// the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/
3
4//! This module contains common GL-related tools.
5
6// -------------------------------------------------------------------------------------------------
7
8use std;
9use gl;
10
11// -------------------------------------------------------------------------------------------------
12
13pub enum GlslVersion {
14    Unknown,
15    Glsl100,
16    Glsl300,
17}
18
19// -------------------------------------------------------------------------------------------------
20
21/// Get GL info log.
22pub fn get_info_log(object: gl::types::GLuint) -> String {
23    unsafe {
24        let mut log_length: i32 = 0;
25        if gl::IsShader(object) == gl::TRUE {
26            gl::GetShaderiv(object, gl::INFO_LOG_LENGTH, &mut log_length);
27        } else if gl::IsProgram(object) == gl::TRUE {
28            gl::GetProgramiv(object, gl::INFO_LOG_LENGTH, &mut log_length);
29        } else {
30            return "GL: Not a shader or a program".to_owned();
31        }
32
33        let mut length: i32 = 0;
34        let mut buffer = [0u8; 512];
35        if gl::IsShader(object) == gl::TRUE {
36            gl::GetShaderInfoLog(object,
37                                 buffer.len() as i32,
38                                 &mut length,
39                                 buffer.as_mut_ptr() as *mut i8);
40        } else if gl::IsProgram(object) == gl::TRUE {
41            gl::GetProgramInfoLog(object,
42                                  buffer.len() as i32,
43                                  &mut length,
44                                  buffer.as_mut_ptr() as *mut i8);
45        }
46
47        let cstr = std::ffi::CStr::from_ptr(std::mem::transmute(&buffer));
48        format!("GL: {}", std::str::from_utf8(cstr.to_bytes()).expect("Info log is invalid"))
49    }
50}
51
52// -------------------------------------------------------------------------------------------------
53
54/// Get latests supported version of GL ES shading language.
55pub fn get_shading_lang_version() -> GlslVersion {
56    let version = unsafe {
57        let ptr = gl::GetString(gl::SHADING_LANGUAGE_VERSION);
58        let cstr: &std::ffi::CStr = std::ffi::CStr::from_ptr(ptr as *const i8);
59        std::str::from_utf8(cstr.to_bytes()).expect("Shading lang string is invalid")
60    };
61
62    if version.find("ES 3.").is_some() {
63        GlslVersion::Glsl300
64    } else if version.find("ES 1.").is_some() {
65        GlslVersion::Glsl100
66    } else {
67        GlslVersion::Unknown
68    }
69}
70
71// -------------------------------------------------------------------------------------------------
72
73/// Create and compile shader.
74pub fn create_shader(source: String,
75                     shader_type: gl::types::GLenum)
76                     -> Result<gl::types::GLuint, String> {
77    unsafe {
78        let shader = gl::CreateShader(shader_type);
79        let cstr = std::ffi::CString::new(source.as_bytes()).unwrap();
80        gl::ShaderSource(shader, 1, &cstr.as_ptr(), std::ptr::null());
81        gl::CompileShader(shader);
82
83        let mut status = gl::FALSE as gl::types::GLint;
84        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
85        if status != (gl::TRUE as gl::types::GLint) {
86            let info_log = get_info_log(shader);
87            gl::DeleteShader(shader);
88            Err(info_log)
89        } else {
90            Ok(shader)
91        }
92    }
93}
94
95// -------------------------------------------------------------------------------------------------
96
97/// Create and link shader program.
98pub fn create_program(vertex_shader: gl::types::GLenum,
99                      fragment_shader: gl::types::GLenum)
100                      -> Result<gl::types::GLuint, String> {
101    unsafe {
102        // Create program
103        let shader_program = gl::CreateProgram();
104
105        // Link with shaders
106        gl::AttachShader(shader_program, vertex_shader);
107        gl::AttachShader(shader_program, fragment_shader);
108        gl::LinkProgram(shader_program);
109
110        // Handle errors
111        let mut link_ok = gl::FALSE as i32;
112        gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut link_ok);
113        if link_ok == gl::TRUE as i32 {
114            Ok(shader_program)
115        } else {
116            let info_log = get_info_log(shader_program);
117            gl::DeleteProgram(shader_program);
118            Err(info_log)
119        }
120    }
121}
122
123// -------------------------------------------------------------------------------------------------
124
125/// Create program and link with shaders.
126pub fn prepare_shader_program(vertex_source: String,
127                              fragment_source: String)
128                              -> Result<gl::types::GLuint, String> {
129    // Create vertex shader
130    let vertex_shader = create_shader(vertex_source, gl::VERTEX_SHADER)?;
131
132    // Create fragment shader
133    let fragment_shader = create_shader(fragment_source, gl::FRAGMENT_SHADER)?;
134
135    // Create and link shader program
136    create_program(vertex_shader, fragment_shader)
137}
138
139// -------------------------------------------------------------------------------------------------
140
141/// Get location attribute variable in linked program.
142pub fn get_attrib_location(program: gl::types::GLuint,
143                           name: String)
144                           -> Result<gl::types::GLint, String> {
145    let cstr = std::ffi::CString::new(name.as_bytes()).unwrap();
146    let location =
147        unsafe { gl::GetAttribLocation(program, cstr.as_bytes_with_nul().as_ptr() as *const i8) };
148
149    if location < 0 {
150        Err(format!("Could not get location for attribute '{}'", name))
151    } else {
152        Ok(location)
153    }
154}
155
156// -------------------------------------------------------------------------------------------------
157
158/// Get location of uniform variable in linked program.
159pub fn get_uniform_location(program: gl::types::GLuint,
160                            name: String)
161                            -> Result<gl::types::GLint, String> {
162    let cstr = std::ffi::CString::new(name.as_bytes()).unwrap();
163    let location =
164        unsafe { gl::GetUniformLocation(program, cstr.as_bytes_with_nul().as_ptr() as *const i8) };
165
166    if location < 0 {
167        Err(format!("Could not get location for uniform '{}'", name))
168    } else {
169        Ok(location)
170    }
171}
172
173// -------------------------------------------------------------------------------------------------