1use gl;
5use gl::types::{GLboolean, GLenum, GLint, GLsizeiptr, GLuint};
6use std::ffi::CString;
7use std::{mem, ptr};
8
9#[cfg(not(feature = "glow"))]
10use gl::types::GLchar;
11
12pub struct DynamicAttribute {
14 vbo: GLuint,
16 size: i32,
18 location: GLuint,
20 normalize: GLboolean,
22 ty: GLenum,
24}
25
26impl Drop for DynamicAttribute {
27 fn drop(&mut self) {
28 unsafe {
29 gl::DeleteBuffers(1, &self.vbo);
30 }
31 }
32}
33
34impl DynamicAttribute {
35 fn bind_vao(&self, vao: GLuint) {
39 let stride = 0;
40 unsafe {
41 gl::BindVertexArray(vao);
42 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
43 gl::VertexAttribPointer(
44 self.location,
45 self.size,
46 self.ty,
47 self.normalize,
48 stride,
49 ptr::null(),
50 );
51 }
52 }
53
54 fn new(
55 program: GLuint,
56 name: &str,
57 size: i32,
58 normalize: GLboolean,
59 ty: GLenum,
60 vao: GLuint,
61 ) -> Result<Self, String> {
62 let location = attribute_location(program, name)?;
63 let mut vbo = 0;
64 unsafe {
65 gl::GenBuffers(1, &mut vbo);
66 }
67 let res = DynamicAttribute {
68 vbo,
69 size,
70 location,
71 normalize,
72 ty,
73 };
74 res.bind_vao(vao);
75 Ok(res)
76 }
77
78 pub fn xyz(program: GLuint, name: &str, vao: GLuint) -> Result<DynamicAttribute, String> {
80 DynamicAttribute::new(program, name, 3, gl::FALSE, gl::FLOAT, vao)
81 }
82
83 pub fn xy(program: GLuint, name: &str, vao: GLuint) -> Result<DynamicAttribute, String> {
85 DynamicAttribute::new(program, name, 2, gl::FALSE, gl::FLOAT, vao)
86 }
87
88 pub fn rgb(program: GLuint, name: &str, vao: GLuint) -> Result<DynamicAttribute, String> {
90 DynamicAttribute::new(program, name, 3, gl::FALSE, gl::FLOAT, vao)
91 }
92
93 pub fn rgba(program: GLuint, name: &str, vao: GLuint) -> Result<DynamicAttribute, String> {
95 DynamicAttribute::new(program, name, 4, gl::FALSE, gl::FLOAT, vao)
96 }
97
98 pub fn uv(program: GLuint, name: &str, vao: GLuint) -> Result<DynamicAttribute, String> {
100 DynamicAttribute::new(program, name, 2, gl::FALSE, gl::FLOAT, vao)
101 }
102
103 pub unsafe fn set<T>(&self, data: &[T]) {
105 gl::EnableVertexAttribArray(self.location);
106 gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
107 gl::BufferData(
108 gl::ARRAY_BUFFER,
109 data.len() as GLsizeiptr * mem::size_of::<T>() as GLsizeiptr,
110 mem::transmute(data.as_ptr()),
111 gl::DYNAMIC_DRAW,
112 );
113 }
114}
115
116pub fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
120 unsafe {
121 let shader = gl::CreateShader(shader_type);
122 let c_source = match CString::new(source) {
123 Ok(x) => x,
124 Err(err) => return Err(format!("compile_shader: {}", err)),
125 };
126 gl::ShaderSource(shader, 1, &c_source.as_ptr(), ptr::null());
127 drop(c_source);
128 gl::CompileShader(shader);
129 let mut status = gl::FALSE as GLint;
130
131 #[cfg(feature = "glow")]
132 {
133 gl::GetCompleStatus(shader, &mut status);
134 }
135 #[cfg(not(feature = "glow"))]
136 {
137 gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
138 }
139
140 if status == (gl::TRUE as GLint) {
141 Ok(shader)
142 } else {
143 #[cfg(feature = "glow")]
144 {
145 Err(gl::GetShaderInfoLog(shader))
146 }
147 #[cfg(not(feature = "glow"))]
148 {
149 let mut len = 0;
150 gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
151
152 if len == 0 {
153 Err("Compilation failed with no log. \
154 The OpenGL context might have been created on another thread, \
155 or not have been created."
156 .to_string())
157 } else {
158 let mut buf = vec![0; len as usize - 1];
160 gl::GetShaderInfoLog(
161 shader,
162 len,
163 ptr::null_mut(),
164 buf.as_mut_ptr() as *mut GLchar,
165 );
166
167 gl::DeleteShader(shader);
168
169 Err(String::from_utf8(buf).expect("ShaderInfoLog not valid utf8"))
170 }
171 }
172 }
173 }
174}
175
176pub fn attribute_location(program: GLuint, name: &str) -> Result<GLuint, String> {
180 unsafe {
181 let c_name = match CString::new(name) {
182 Ok(x) => x,
183 Err(err) => return Err(format!("attribute_location: {}", err)),
184 };
185 let id = gl::GetAttribLocation(program, c_name.as_ptr());
186 drop(c_name);
187 if id < 0 {
188 Err(format!("Attribute '{}' does not exists in shader", name))
189 } else {
190 Ok(id as GLuint)
191 }
192 }
193}
194
195pub fn uniform_location(program: GLuint, name: &str) -> Result<GLuint, String> {
199 unsafe {
200 let c_name = match CString::new(name) {
201 Ok(x) => x,
202 Err(err) => return Err(format!("uniform_location: {}", err)),
203 };
204 let id = gl::GetUniformLocation(program, c_name.as_ptr());
205 drop(c_name);
206 if id < 0 {
207 Err(format!("Uniform '{}' does not exists in shader", name))
208 } else {
209 Ok(id as GLuint)
210 }
211 }
212}