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;
+ }
+}