]> git.seodisparate.com - LudumDare45_StartWithNothing/commitdiff
Setup for drawing with transforms by using shaders
authorStephen Seo <seo.disparate@gmail.com>
Mon, 20 Feb 2023 11:07:44 +0000 (20:07 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 20 Feb 2023 11:07:44 +0000 (20:07 +0900)
Cargo.toml
build.rs
raylib/simple.fs [new file with mode: 0644]
raylib/transform.vs [new file with mode: 0644]
src/agnostic_interface.rs
src/agnostic_interface/raylib_impl.rs
src/faux_quicksilver.rs
src/main.rs
src/shaders.rs [new file with mode: 0644]

index 9842d9ff9a42bd6dee3e65f75b0001ce7f7e2678..a503789e798d986a6502ea92b71a7a1e7a33f18a 100644 (file)
@@ -16,4 +16,4 @@ bindgen = "0.64"
 
 [features]
 default = []
-no_link_raylib  = []
+no_link_libs  = []
index fd45ada70a19509eb2b65f038226f5b9e46c8721..1ed36cf91d85070f53ef7e69ee240a5098a631b3 100644 (file)
--- a/build.rs
+++ b/build.rs
@@ -3,16 +3,17 @@ extern crate bindgen;
 use std::env;
 use std::path::PathBuf;
 
-#[cfg(not(feature = "no_link_raylib"))]
-fn linking_raylib() {
+#[cfg(not(feature = "no_link_libs"))]
+fn linking_libs() {
     println!("cargo:rustc-link-lib=raylib");
+    println!("cargo:rustc-link-lib=OpenGL");
 }
 
-#[cfg(feature = "no_link_raylib")]
-fn linking_raylib() {}
+#[cfg(feature = "no_link_libs")]
+fn linking_libs() {}
 
 fn main() {
-    linking_raylib();
+    linking_libs();
     println!("cargo:rerun-if-changed=raylib/raylib.h");
 
     let bindings = bindgen::Builder::default()
diff --git a/raylib/simple.fs b/raylib/simple.fs
new file mode 100644 (file)
index 0000000..3884320
--- /dev/null
@@ -0,0 +1,20 @@
+#version 100
+
+// Default fragment shader used by Raylib.
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform vec4 colDiffuse;
+
+void main() {
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture2D(texture0, fragTexCoord);
+
+    gl_FragColor = texelColor*colDiffuse*fragColor;
+}
diff --git a/raylib/transform.vs b/raylib/transform.vs
new file mode 100644 (file)
index 0000000..9e1a9f4
--- /dev/null
@@ -0,0 +1,25 @@
+#version 100
+
+// Input vertex attributes
+attribute vec3 vertexPosition;
+attribute vec2 vertexTexCoord;
+attribute vec4 vertexColor;
+
+// Input uniform values
+uniform mat4 mvp;
+
+// Output vertex attributes (to fragment shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// custom
+attribute vec2 origin;
+attribute mat3 transform;
+
+void main() {
+  fragTexCoord = vertexTexCoord;
+  fragColor = vertexColor;
+
+  vec3 pos = transform * (vertexPosition - vec3(origin, 0.0)) + vec3(origin, 0.0);
+  gl_Position = mvp * vec4(pos, 1.0);
+}
index 0efd40517deb47df158ae0829264404a4a20f1b0..8e57ca3104270d0f45152bf9dc7a2ae9a6559a8e 100644 (file)
@@ -49,6 +49,13 @@ pub trait MusicInterface {
     fn update(&mut self) -> Result<(), String>;
 }
 
+pub trait ShaderInterface {
+    fn set_transform_attrib(&mut self, transform: Transform) -> Result<(), String>;
+    fn set_origin_attrib(&mut self, origin: Vector) -> Result<(), String>;
+    fn begin_draw_shader(&self) -> Result<(), String>;
+    fn end_draw_shader(&self) -> Result<(), String>;
+}
+
 pub trait CameraInterface {
     fn get_view(&self) -> Result<Rectangle, String>;
     fn get_view_xy(&self) -> Result<(f32, f32), String>;
@@ -96,6 +103,12 @@ pub trait GameInterface {
     fn load_font(&mut self, path: &Path) -> Result<Box<dyn FontInterface>, String>;
     fn load_sound(&mut self, path: &Path) -> Result<Box<dyn SoundInterface>, String>;
     fn load_music(&mut self, path: &Path) -> Result<Box<dyn MusicInterface>, String>;
+    fn load_shader(
+        &mut self,
+        name: String,
+        vs: &Path,
+        fs: &Path,
+    ) -> Result<Box<dyn ShaderInterface>, String>;
 
     fn get_camera(&mut self) -> Result<Box<dyn CameraInterface>, String>;
     fn get_default_camera(&mut self) -> Result<Box<dyn CameraInterface>, String>;
index 1812577387771c4483b8a50f31e93ebc6d662771..c8b7e09e8b5621d8e9cc7dd7f12c108b5a23597b 100644 (file)
@@ -12,12 +12,18 @@ use std::{
     collections::HashMap,
     ffi::CString,
     os::raw::{c_char, c_int},
+    path::Path,
     rc::Rc,
 };
 
-use crate::faux_quicksilver::Vector;
+use crate::{
+    faux_quicksilver::{Transform, Vector},
+    shaders::{get_attrib_location, set_origin_2f, set_transform_3f},
+};
 
-use super::{FontInterface, GameInterface, ImageInterface, MusicInterface, SoundInterface};
+use super::{
+    FontInterface, GameInterface, ImageInterface, MusicInterface, ShaderInterface, SoundInterface,
+};
 
 fn fqcolor_to_color(c: crate::faux_quicksilver::Color) -> ffi::Color {
     ffi::Color {
@@ -41,6 +47,78 @@ fn fqvector_to_vector2(v: crate::faux_quicksilver::Vector) -> ffi::Vector2 {
     ffi::Vector2 { x: v.x, y: v.y }
 }
 
+#[derive(Clone, Debug)]
+pub struct RaylibShader {
+    shader: ffi::Shader,
+}
+
+impl RaylibShader {
+    pub fn get_shader_id(&self) -> ::std::os::raw::c_uint {
+        self.shader.id as ::std::os::raw::c_uint
+    }
+}
+
+#[derive(Clone, Debug)]
+struct RaylibShaderHandler {
+    shader: Rc<RefCell<RaylibShader>>,
+}
+
+impl ShaderInterface for RaylibShaderHandler {
+    fn set_transform_attrib(&mut self, transform: Transform) -> Result<(), String> {
+        let transform_cstr = CString::new("transform")
+            .map_err(|_| String::from("Failed to create \"transform\" CString!"))?;
+        let attr_loc = get_attrib_location(&self.shader.borrow(), &transform_cstr);
+        set_transform_3f(attr_loc, transform);
+        Ok(())
+    }
+
+    fn begin_draw_shader(&self) -> Result<(), String> {
+        unsafe {
+            ffi::BeginShaderMode(self.shader.borrow().shader);
+        }
+        Ok(())
+    }
+
+    fn end_draw_shader(&self) -> Result<(), String> {
+        unsafe {
+            ffi::EndShaderMode();
+        }
+        Ok(())
+    }
+
+    fn set_origin_attrib(&mut self, origin: Vector) -> Result<(), String> {
+        let origin_cstr = CString::new("origin")
+            .map_err(|_| String::from("Failed to create \"origin\" CString!"))?;
+        let attr_loc = get_attrib_location(&self.shader.borrow(), &origin_cstr);
+        set_origin_2f(attr_loc, origin);
+        Ok(())
+    }
+}
+
+impl RaylibShaderHandler {
+    pub fn load_shader(vs: &Path, fs: &Path) -> Result<Self, String> {
+        unsafe {
+            let vs_cstr: CString = CString::from_vec_unchecked(
+                vs.to_str()
+                    .ok_or_else(|| format!("Cannot convert path \"{vs:?}\" to str!"))?
+                    .as_bytes()
+                    .to_owned(),
+            );
+            let fs_cstr: CString = CString::from_vec_unchecked(
+                fs.to_str()
+                    .ok_or_else(|| format!("Cannot convert path \"{fs:?}\" to str!"))?
+                    .as_bytes()
+                    .to_owned(),
+            );
+            Ok(Self {
+                shader: Rc::new(RefCell::new(RaylibShader {
+                    shader: ffi::LoadShader(vs_cstr.as_ptr(), fs_cstr.as_ptr()),
+                })),
+            })
+        }
+    }
+}
+
 #[derive(Clone, Debug)]
 struct RaylibImage {
     image: ffi::Image,
@@ -263,6 +341,7 @@ struct RaylibGame {
     fonts: HashMap<String, Rc<RaylibFont>>,
     sounds: HashMap<String, Rc<RaylibSound>>,
     music: HashMap<String, Rc<RefCell<RaylibMusic>>>,
+    shaders: HashMap<String, Rc<RefCell<RaylibShader>>>,
 }
 
 impl RaylibGame {
@@ -280,6 +359,7 @@ impl RaylibGame {
             fonts: HashMap::new(),
             sounds: HashMap::new(),
             music: HashMap::new(),
+            shaders: HashMap::new(),
         })
     }
 }
@@ -287,6 +367,9 @@ impl RaylibGame {
 impl Drop for RaylibGame {
     fn drop(&mut self) {
         unsafe {
+            for (_, shader) in &self.shaders {
+                ffi::UnloadShader(shader.borrow().shader);
+            }
             for (_, image) in &self.images {
                 if let Some(texture) = image.borrow_mut().texture.take() {
                     ffi::UnloadTexture(texture);
@@ -528,6 +611,17 @@ impl GameInterface for RaylibGame {
         }
     }
 
+    fn load_shader(
+        &mut self,
+        name: String,
+        vs: &Path,
+        fs: &Path,
+    ) -> Result<Box<dyn ShaderInterface>, String> {
+        let raylib_shader = RaylibShaderHandler::load_shader(vs, fs)?;
+        self.shaders.insert(name, raylib_shader.shader.clone());
+        Ok(Box::new(raylib_shader))
+    }
+
     fn get_camera(&mut self) -> Result<Box<dyn super::CameraInterface>, String> {
         todo!()
     }
index a78519a4fa8cd406587b9aa45c3d7df258bcffb0..8fc6d16f8a17c34a1e407c44fe9cbaefb5ef42f9 100644 (file)
@@ -146,16 +146,12 @@ impl Vector {
 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub struct Transform {
     pub mat: [f32; 9],
-    //translate: Vector,
-    //rotate: f32,
 }
 
 impl Default for Transform {
     fn default() -> Self {
         Self {
             mat: [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
-            //translate: Vector { x: 0.0, y: 0.0 },
-            //rotate: 0.0,
         }
     }
 }
@@ -187,8 +183,6 @@ impl Mul<Transform> for Transform {
                 self.mat[6] * rhs.mat[1] + self.mat[7] * rhs.mat[4] + self.mat[8] * rhs.mat[7],
                 self.mat[6] * rhs.mat[2] + self.mat[7] * rhs.mat[5] + self.mat[8] * rhs.mat[8],
             ],
-            //translate: self.translate + rhs.translate,
-            //rotate: self.rotate + rhs.rotate,
         }
     }
 }
@@ -211,26 +205,14 @@ impl Transform {
                 0.0,
                 1.0,
             ],
-            //rotate: rot,
-            ..Default::default()
         }
     }
 
     pub fn translate(x: f32, y: f32) -> Self {
         Self {
             mat: [1.0, 0.0, x, 0.0, 1.0, y, 0.0, 0.0, 1.0],
-            //translate: Vector { x, y },
-            ..Default::default()
         }
     }
-
-    //pub fn get_translate(&self) -> Vector {
-    //    self.translate
-    //}
-
-    //pub fn get_rotation(&self) -> f32 {
-    //    self.rotate
-    //}
 }
 
 pub struct Window {
index dd8a4ef4899614300cbe7f4ac795a047bc4d7bf3..4b66d33fbd4d9a2bc6c4637715301af94fe6be43 100644 (file)
@@ -1,6 +1,7 @@
 mod agnostic_interface;
 mod faux_quicksilver;
 mod original_impl;
+mod shaders;
 
 fn main() {
     // TODO
diff --git a/src/shaders.rs b/src/shaders.rs
new file mode 100644 (file)
index 0000000..b1755a4
--- /dev/null
@@ -0,0 +1,47 @@
+use crate::{
+    agnostic_interface::raylib_impl::RaylibShader,
+    faux_quicksilver::{Transform, Vector},
+};
+use std::ffi::CStr;
+
+extern "C" {
+    pub fn glVertexAttrib2f(index: ::std::os::raw::c_uint, x: f32, y: f32);
+}
+extern "C" {
+    pub fn glVertexAttrib3f(index: ::std::os::raw::c_uint, x: f32, y: f32, z: f32);
+}
+extern "C" {
+    pub fn glVertexAttrib4f(index: ::std::os::raw::c_uint, x: f32, y: f32, z: f32, w: f32);
+}
+extern "C" {
+    pub fn glGetAttribLocation(
+        program: ::std::os::raw::c_uint,
+        name: *const ::std::os::raw::c_char,
+    ) -> ::std::os::raw::c_int;
+}
+
+pub fn get_attrib_location(raylib_shader: &RaylibShader, name: &CStr) -> ::std::os::raw::c_uint {
+    unsafe {
+        glGetAttribLocation(raylib_shader.get_shader_id(), name.as_ptr()) as ::std::os::raw::c_uint
+    }
+}
+
+pub fn set_transform_3f(index: ::std::os::raw::c_uint, transform: Transform) {
+    // OpenGL stores matrix indices in column major order.
+    for idx in index..(index + 3) {
+        unsafe {
+            glVertexAttrib3f(
+                idx,
+                transform.mat[0 + idx as usize],
+                transform.mat[3 + idx as usize],
+                transform.mat[6 + idx as usize],
+            );
+        }
+    }
+}
+
+pub fn set_origin_2f(index: ::std::os::raw::c_uint, origin: Vector) {
+    unsafe {
+        glVertexAttrib2f(index, origin.x, origin.y);
+    }
+}