diff --git a/Cargo.toml b/Cargo.toml index 9842d9f..a503789 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,4 @@ bindgen = "0.64" [features] default = [] -no_link_raylib = [] +no_link_libs = [] diff --git a/build.rs b/build.rs index fd45ada..1ed36cf 100644 --- 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 index 0000000..3884320 --- /dev/null +++ b/raylib/simple.fs @@ -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 index 0000000..9e1a9f4 --- /dev/null +++ b/raylib/transform.vs @@ -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); +} diff --git a/src/agnostic_interface.rs b/src/agnostic_interface.rs index 0efd405..8e57ca3 100644 --- a/src/agnostic_interface.rs +++ b/src/agnostic_interface.rs @@ -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; fn get_view_xy(&self) -> Result<(f32, f32), String>; @@ -96,6 +103,12 @@ pub trait GameInterface { fn load_font(&mut self, path: &Path) -> Result, String>; fn load_sound(&mut self, path: &Path) -> Result, String>; fn load_music(&mut self, path: &Path) -> Result, String>; + fn load_shader( + &mut self, + name: String, + vs: &Path, + fs: &Path, + ) -> Result, String>; fn get_camera(&mut self) -> Result, String>; fn get_default_camera(&mut self) -> Result, String>; diff --git a/src/agnostic_interface/raylib_impl.rs b/src/agnostic_interface/raylib_impl.rs index 1812577..c8b7e09 100644 --- a/src/agnostic_interface/raylib_impl.rs +++ b/src/agnostic_interface/raylib_impl.rs @@ -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>, +} + +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 { + 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>, sounds: HashMap>, music: HashMap>>, + shaders: HashMap>>, } 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, 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, String> { todo!() } diff --git a/src/faux_quicksilver.rs b/src/faux_quicksilver.rs index a78519a..8fc6d16 100644 --- a/src/faux_quicksilver.rs +++ b/src/faux_quicksilver.rs @@ -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 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 { diff --git a/src/main.rs b/src/main.rs index dd8a4ef..4b66d33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 index 0000000..b1755a4 --- /dev/null +++ b/src/shaders.rs @@ -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); + } +}