diff --git a/assets/shaders/pixel.fs b/assets/shaders/pixel.fs new file mode 100644 index 0000000..2148371 --- /dev/null +++ b/assets/shaders/pixel.fs @@ -0,0 +1,32 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; +in vec4 fragColor; + +// Input uniform values +uniform sampler2D texture0; +uniform vec4 colDiffuse; + +// Output fragment color +out vec4 finalColor; + +// Viewport dimensions +const float renderWidth = 1080; +const float renderHeight = 720; + +// Pixel scaling +uniform float pixelWidth = 2.0; +uniform float pixelHeight = 2.0; + +void main() +{ + float dx = pixelWidth * (1.0 / renderWidth); + float dy = pixelHeight * (1.0 / renderHeight); + + vec2 coord = vec2(dx * floor(fragTexCoord.x / dx), dy * floor(fragTexCoord.y / dy)); + + vec3 tc = texture(texture0, coord).rgb; + + finalColor = vec4(tc, 1.0); +} diff --git a/src/logic/ingame/mod.rs b/src/logic/ingame/mod.rs index 85da3a0..0f1fac4 100644 --- a/src/logic/ingame/mod.rs +++ b/src/logic/ingame/mod.rs @@ -154,9 +154,6 @@ impl Screen for InGameScreen { // Calculate DT let dt = draw_handle.get_time() - game_core.last_frame_time; - // Clear frame - draw_handle.clear_background(Color::BLACK); - // Handle the pause menu being opened if draw_handle.is_key_pressed(KeyboardKey::KEY_ESCAPE) { return Some(GameState::PauseMenu); @@ -176,38 +173,68 @@ impl Screen for InGameScreen { // Open a 2D context { - let mut context_2d = draw_handle.begin_mode2D(game_core.master_camera); - - // Render the world - self.render_world(&mut context_2d, game_core, dt); - if game_core.show_simple_debug_info { - self.render_colliders(&mut context_2d, game_core); + unsafe { + raylib::ffi::BeginTextureMode(*game_core.resources.shader_texture); } + { + let mut context_2d = draw_handle.begin_mode2D(game_core.master_camera); - // Render entities - for jellyfish in game_core.world.jellyfish.iter_mut() { - jellyfish.handle_logic(&mut game_core.player, dt); - jellyfish.render( - &mut context_2d, - &mut game_core.player, - &mut game_core.resources, - dt, - ); - } - for octopus in game_core.world.octopus.iter_mut() { - octopus.handle_logic(&mut game_core.player, dt); - octopus.render( - &mut context_2d, - &mut game_core.player, - &mut game_core.resources, - dt, - ); - } + // Clear frame + context_2d.clear_background(Color::BLACK); - // Render Player - game_core - .player - .render(&mut context_2d, &mut game_core.resources, dt); + // Render the world + self.render_world(&mut context_2d, game_core, dt); + if game_core.show_simple_debug_info { + self.render_colliders(&mut context_2d, game_core); + } + + // Render entities + for jellyfish in game_core.world.jellyfish.iter_mut() { + jellyfish.handle_logic(&mut game_core.player, dt); + jellyfish.render( + &mut context_2d, + &mut game_core.player, + &mut game_core.resources, + dt, + ); + } + for octopus in game_core.world.octopus.iter_mut() { + octopus.handle_logic(&mut game_core.player, dt); + octopus.render( + &mut context_2d, + &mut game_core.player, + &mut game_core.resources, + dt, + ); + } + + // Render Player + game_core + .player + .render(&mut context_2d, &mut game_core.resources, dt); + } + unsafe { + raylib::ffi::EndTextureMode(); + } + } + + // Render the 2D context via the ripple shader + { + let mut shader_context = + draw_handle.begin_shader_mode(&game_core.resources.pixel_shader); + + // Blit the texture + shader_context.draw_texture_rec( + &game_core.resources.shader_texture, + Rectangle { + x: 0.0, + y: 0.0, + width: game_core.resources.shader_texture.width() as f32, + height: (game_core.resources.shader_texture.height() as f32) * -1.0, + }, + Vector2::zero(), + Color::WHITE, + ); } // Render the darkness layer @@ -216,7 +243,6 @@ impl Screen for InGameScreen { // Render the hud hud::render_hud(draw_handle, game_core, window_center); - // Handle player out of breath if game_core.player.breath_percent == 0.0 { return Some(GameState::GameEnd); diff --git a/src/resources.rs b/src/resources.rs index ee128e5..b814c9d 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -1,9 +1,5 @@ use failure::Error; -use raylib::{ - math::Vector2, - texture::{Image, Texture2D}, - RaylibHandle, RaylibThread, -}; +use raylib::{RaylibHandle, RaylibThread, math::Vector2, shaders::Shader, texture::{Image, RenderTexture2D, Texture2D}}; use crate::lib::wrappers::animation::FrameAnimationWrapper; @@ -24,6 +20,8 @@ pub struct GlobalResources { // Cave pub cave_mid_layer: Texture2D, + pub pixel_shader: Shader, + pub shader_texture: RenderTexture2D, // Enemies pub jellyfish_animation_regular: FrameAnimationWrapper, @@ -106,6 +104,8 @@ impl GlobalResources { &thread, &Image::load_image("./assets/img/map/cave.png")?, )?, + pixel_shader: raylib.load_shader(&thread, None, Some("./assets/shaders/pixel.fs"))?, + shader_texture: raylib.load_render_texture(&thread, raylib.get_screen_width() as u32, raylib.get_screen_height() as u32)?, jellyfish_animation_regular: FrameAnimationWrapper::new( raylib.load_texture_from_image( &thread,