shader rendering

This commit is contained in:
Evan Pratten 2021-09-21 16:55:07 -04:00
parent f205eea928
commit 5ae4252779
6 changed files with 160 additions and 27 deletions

View File

@ -16,7 +16,8 @@ thiserror = "1.0"
chrono = "0.4"
rust-embed = "6.2.0"
raylib = "3.5"
# cgmath = "0.18"
puffin = "0.9"
puffin_http = "0.6"
[profile.release]
lto = true

View File

@ -1,7 +1,10 @@
use discord_sdk::activity::ActivityBuilder;
use raylib::prelude::*;
use shaders::util::{dynamic_screen_texture::DynScreenTexture, render_texture::render_to_texture};
use tracing::error;
use shaders::{
shader::ShaderWrapper,
util::{dynamic_screen_texture::DynScreenTexture, render_texture::render_to_texture},
};
use tracing::{error, info};
use utilities::{
datastore::StaticGameData,
discord::{DiscordConfig, DiscordRpcClient},
@ -25,46 +28,68 @@ pub async fn game_begin() {
)
.expect("Could not load general game config data");
// Set up profiling
// #[cfg(debug_assertions)]
// {
let _puffin_server = puffin_http::Server::new(&format!("0.0.0.0:{}", puffin_http::DEFAULT_PORT)).unwrap();
puffin::set_scopes_on(true);
// }
// Attempt to connect to a locally running Discord instance for rich presence access
let discord_config = DiscordConfig::load(
StaticGameData::get("configs/discord.json").expect("Failed to load discord.json"),
)
.expect("Could not load Discord config data");
// let discord_rpc =
// match DiscordRpcClient::new(discord_config.app_id, discord_sdk::Subscriptions::ACTIVITY)
// .await
// {
// Ok(client) => Some(client),
// Err(err) => {
// error!("Could not connect to or find a locally running Discord instance.");
// error!("Discord connection error: {:?}", err);
// None
// }
// };
let discord_rpc =
match DiscordRpcClient::new(discord_config.app_id, discord_sdk::Subscriptions::ACTIVITY)
.await
{
Ok(client) => Some(client),
Err(err) => {
error!("Could not connect to or find a locally running Discord instance.");
error!("Discord connection error: {:?}", err);
None
}
};
// if let Some(rpc) = discord_rpc {
// rpc.set_rich_presence(ActivityBuilder::default().details("Testing..."))
// .await
// .unwrap();
// }
if let Some(rpc) = discord_rpc {
rpc.set_rich_presence(ActivityBuilder::default().details("Testing..."))
.await
.unwrap();
}
let (mut rl, thread) = raylib::init()
.size(640, 480)
.title(&game_config.name)
.vsync()
// .vsync()
.msaa_4x()
.resizable()
.build();
// Create a dynamic texture to draw to for processing by shaders
info!("Allocating a resizable texture for the screen");
let mut dynamic_texture =
DynScreenTexture::new(&mut rl, &thread).expect("Failed to allocate a screen texture");
// Load the pixel art shader
info!("Loading the pixel art shader");
let pixel_shader = ShaderWrapper::new(
None,
Some(StaticGameData::get("shaders/pixelart.fs")).expect("Failed to load pixelart.fs"),
&mut rl,
&thread,
)
.unwrap();
info!("Starting the render loop");
while !rl.window_should_close() {
puffin::profile_scope!("main_loop");
puffin::GlobalProfiler::lock().new_frame();
dynamic_texture.update(&mut rl, &thread).unwrap();
let mut d = rl.begin_drawing(&thread);
render_to_texture(&mut dynamic_texture, || {
puffin::profile_scope!("internal_shaded_render");
d.clear_background(Color::WHITE);
d.draw_text("Hello, world!", 12, 12, 20, Color::BLACK);
@ -81,6 +106,6 @@ pub async fn game_begin() {
d.draw_fps(10, 100);
});
pixel_shader.process_texture_and_render(&mut d, &thread, &dynamic_texture);
}
}

View File

@ -1,14 +1,116 @@
use std::{ffi::CString, str::Utf8Error, string::FromUtf8Error};
use raylib::color::Color;
use raylib::math::Vector2;
use raylib::prelude::RaylibTexture2D;
use raylib::{
math::Rectangle,
prelude::{RaylibDraw, RaylibShaderModeExt},
shaders::Shader,
texture::RenderTexture2D,
RaylibHandle, RaylibThread,
};
use rust_embed::EmbeddedFile;
use tracing::info;
#[derive(Debug, Error)]
pub enum ShaderError {
#[error(transparent)]
UtfConversionError(#[from] FromUtf8Error),
}
pub struct ShaderWrapper {
shader: Shader,
}
impl ShaderWrapper {
/// Construct a new shader wrapper.
pub fn new() -> Self {
Self {
}
pub fn new(
vertex_shader: Option<EmbeddedFile>,
fragment_shader: Option<EmbeddedFile>,
raylib: &mut RaylibHandle,
thread: &RaylibThread,
) -> Result<Self, ShaderError> {
let vertex_shader_code = vertex_shader.map(|file| String::from_utf8(file.data.to_vec()));
let fragment_shader_code =
fragment_shader.map(|file| String::from_utf8(file.data.to_vec()));
Ok(Self {
shader: load_shader_from_heap(
raylib,
&thread,
match vertex_shader_code {
Some(result) => match result {
Ok(code) => Some(code),
Err(err) => return Err(ShaderError::UtfConversionError(err)),
},
None => None,
},
match fragment_shader_code {
Some(result) => match result {
Ok(code) => Some(code),
Err(err) => return Err(ShaderError::UtfConversionError(err)),
},
None => None,
},
),
})
}
}
pub fn process_texture_and_render<H>(
&self,
raylib: &mut H,
thread: &RaylibThread,
texture: &RenderTexture2D,
) where
H: RaylibShaderModeExt + RaylibDraw,
{
puffin::profile_function!();
// Create a shader context to work under
let mut shader_context = raylib.begin_shader_mode(&self.shader);
// Blit the texture
shader_context.draw_texture_pro(
&texture,
Rectangle {
x: 0.0,
y: 0.0,
width: texture.width() as f32,
height: (texture.height() as f32) * -1.0,
},
Rectangle {
x: 0.0,
y: 0.0,
width: texture.width() as f32,
height: texture.height() as f32,
},
Vector2::zero(),
0.0,
Color::WHITE,
);
}
}
/// Too lazy to write this upstream
fn load_shader_from_heap(
handle: &mut RaylibHandle,
thread: &RaylibThread,
vs: Option<String>,
fs: Option<String>,
) -> Shader {
let vs_code = vs.unwrap_or(String::new());
let vs_code_str = vs_code.as_str();
let fs_code = fs.unwrap_or(String::new());
let fs_code_str = fs_code.as_str();
handle.load_shader_code(
thread,
match vs_code.len() {
0 => None,
_ => Some(vs_code_str),
},
match fs_code.len() {
0 => None,
_ => Some(fs_code_str),
},
)
}

View File

@ -28,6 +28,7 @@ impl DynScreenTexture {
raylib: &mut RaylibHandle,
thread: &RaylibThread,
) -> Result<(), String> {
puffin::profile_function!();
// Check if the window has been resized
if self.texture.width() != raylib.get_screen_width()
|| self.texture.height() != raylib.get_screen_height()
@ -40,6 +41,7 @@ impl DynScreenTexture {
}
Ok(())
}
}
impl Deref for DynScreenTexture {

View File

@ -2,6 +2,7 @@ use raylib::ffi::RenderTexture;
/// Renders everything in the draw function to a texture
pub fn render_to_texture<Func>(texture: &mut RenderTexture, draw_fn: Func) where Func: FnOnce() {
puffin::profile_function!();
unsafe {
raylib::ffi::BeginTextureMode(*texture);
}

View File

@ -61,6 +61,7 @@ impl DiscordRpcClient {
/// Clears the user rich presence
pub async fn clear_rich_presence(&self) -> Result<Option<Activity>, discord_sdk::Error> {
puffin::profile_function!();
self.discord
.update_activity(ActivityBuilder::default())
.await
@ -71,6 +72,7 @@ impl DiscordRpcClient {
&self,
activity: ActivityBuilder,
) -> Result<Option<Activity>, discord_sdk::Error> {
puffin::profile_function!();
self.discord.update_activity(activity).await
}
}