From 358e139c9cf8082cd19c1899a861e60f29bdbc59 Mon Sep 17 00:00:00 2001 From: _ <> Date: Sun, 16 Feb 2020 23:07:32 +0000 Subject: [PATCH] :recycle: Extract texture.rs and add forgotten shader.rs --- src/main.rs | 29 ++--------- src/shader.rs | 133 +++++++++++++++++++++++++++++++++++++++++++++++++ src/texture.rs | 64 ++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 25 deletions(-) create mode 100644 src/shader.rs create mode 100644 src/texture.rs diff --git a/src/main.rs b/src/main.rs index 56506d6..8b05d75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,10 +12,12 @@ use std::time::{Duration}; mod iqm; mod shader; +mod texture; mod timestep; use iqm::Model; use shader::{ShaderProgram, ShaderObject}; +use texture::Texture; use timestep::TimeStep; pub fn load_small_file

(name: P) -> Vec @@ -47,30 +49,6 @@ where V: Into )) } -pub fn ugly_load_texture

(name: P) -> u32 -where P: AsRef -{ - let decoder = png::Decoder::new (File::open (name).unwrap ()); - let (info, mut reader) = decoder.read_info ().unwrap (); - // Allocate the output buffer. - let mut buf = vec! [0; info.buffer_size ()]; - // Read the next frame. Currently this function should only called once. - // The default options - reader.next_frame (&mut buf).unwrap (); - - unsafe { - gl::BindTexture (gl::TEXTURE_2D, 1); - gl::TexImage2D (gl::TEXTURE_2D, 0, gl::RGBA.try_into ().unwrap (), 1024, 1024, 0, gl::RGBA, gl::UNSIGNED_BYTE, &buf [0] as *const u8 as *const c_void); - - gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); - gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); - gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32); - gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32); - } - - 1 -} - const VERT_SHADER_SRC: &str = " #define lowp @@ -304,7 +282,8 @@ fn main () { }) .collect (); - let texture = ugly_load_texture ("sky.png"); + let texture = Texture::from_file ("sky.png"); + texture.bind (); let model_data = load_small_file ("pumpking.iqm"); let model = Model::from_slice (&model_data [..]); diff --git a/src/shader.rs b/src/shader.rs new file mode 100644 index 0000000..64bf307 --- /dev/null +++ b/src/shader.rs @@ -0,0 +1,133 @@ +use std::convert::TryInto; +use std::ffi::CStr; + +pub struct ShaderObject { + id: u32, +} + +impl ShaderObject { + pub fn id (&self) -> u32 { + self.id + } + + pub fn new (shader_type: u32, source: &str) -> Result + { + let id = unsafe { + gl::CreateShader (shader_type) + }; + + let sources = [ + source.as_ptr () as *const i8, + ]; + + let lengths = [ + source.len ().try_into ().unwrap (), + ]; + + let success = unsafe { + gl::ShaderSource (id, sources.len ().try_into ().unwrap (), sources.as_ptr (), lengths.as_ptr ()); + gl::CompileShader (id); + + let mut success = 0; + gl::GetShaderiv (id, gl::COMPILE_STATUS, &mut success); + success == 1 + }; + + if success { + Ok (ShaderObject { + id, + }) + } + else { + let mut info_log = vec! [0u8; 4096]; + let mut log_length = 0; + + unsafe { + gl::GetShaderInfoLog (id, (info_log.len () - 1).try_into ().unwrap (), &mut log_length, info_log.as_mut_ptr () as *mut i8); + } + + info_log.truncate (log_length.try_into ().unwrap ()); + + let info = String::from_utf8 (info_log).unwrap (); + + Err (info) + } + } +} + +impl Drop for ShaderObject { + fn drop (&mut self) { + unsafe { + gl::DeleteShader (self.id); + } + } +} + +pub struct ShaderProgram { + id: u32, +} + +impl ShaderProgram { + pub fn new (vert: &ShaderObject, frag: &ShaderObject) + -> Result + { + let id = unsafe { + gl::CreateProgram () + }; + + unsafe { + gl::AttachShader (id, vert.id ()); + gl::AttachShader (id, frag.id ()); + + gl::LinkProgram (id); + } + + let success = unsafe { + let mut success = 0; + gl::GetProgramiv (id, gl::LINK_STATUS, &mut success); + success == 1 + }; + + if success { + Ok (ShaderProgram { + id, + }) + } + else { + let mut info_log = vec! [0u8; 4096]; + let mut log_length = 0; + + unsafe { + gl::GetProgramInfoLog (id, (info_log.len () - 1).try_into ().unwrap (), &mut log_length, info_log.as_mut_ptr () as *mut i8); + } + + info_log.truncate (log_length.try_into ().unwrap ()); + + let info = String::from_utf8 (info_log).unwrap (); + + Err (info) + } + } + + pub fn get_uniform_location (&self, name: &CStr) -> i32 { + unsafe { + gl::UseProgram (self.id); + gl::GetUniformLocation (self.id, name.as_ptr ()) + } + } + + pub fn get_attribute_location (&self, name: &CStr) -> i32 { + unsafe { + gl::UseProgram (self.id); + gl::GetAttribLocation (self.id, name.as_ptr ()) + } + } +} + +impl Drop for ShaderProgram { + fn drop (&mut self) { + unsafe { + gl::DeleteProgram (self.id); + } + } +} diff --git a/src/texture.rs b/src/texture.rs new file mode 100644 index 0000000..384ae15 --- /dev/null +++ b/src/texture.rs @@ -0,0 +1,64 @@ +use std::convert::TryInto; +use std::ffi::c_void; +use std::fs::File; +use std::path::Path; + +pub struct Texture { + id: u32, +} + +impl Texture { + pub fn from_file

(name: P) -> Texture + where P: AsRef + { + let decoder = png::Decoder::new (File::open (name).unwrap ()); + let (info, mut reader) = decoder.read_info ().unwrap (); + // Allocate the output buffer. + let mut buf = vec! [0; info.buffer_size ()]; + // Read the next frame. Currently this function should only called once. + // The default options + reader.next_frame (&mut buf).unwrap (); + + let id = unsafe { + let mut id = 0; + + gl::GenTextures (1, &mut id); + assert! (id != 0); + + gl::BindTexture (gl::TEXTURE_2D, id); + gl::TexImage2D (gl::TEXTURE_2D, 0, gl::RGBA.try_into ().unwrap (), 1024, 1024, 0, gl::RGBA, gl::UNSIGNED_BYTE, &buf [0] as *const u8 as *const c_void); + + gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); + gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); + gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32); + gl::TexParameteri (gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32); + + id + }; + + Texture { + id, + } + } + + pub fn bind (&self) { + unsafe { + gl::BindTexture (gl::TEXTURE_2D, self.id); + } + } +} + +impl Drop for Texture { + fn drop (&mut self) + { + if self.id == 0 { + return; + } + + unsafe { + gl::DeleteTextures (1, &mut self.id); + } + + self.id = 0; + } +}