From 55afe1292f175fc606d4e8763dcd04ed90767851 Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Mon, 16 Aug 2021 18:41:42 +0200 Subject: [PATCH] various lighting improvements --- src/components/water_renderer.rs | 58 +++++++++++++++------- src/engine_constants/mod.rs | 15 ++++-- src/npc/ai/sand_zone.rs | 9 ++-- src/scene/game_scene.rs | 78 +++++++++++++++++++++--------- src/texture_set.rs | 83 ++++++++++++++++++++------------ 5 files changed, 165 insertions(+), 78 deletions(-) diff --git a/src/components/water_renderer.rs b/src/components/water_renderer.rs index ac1cce5..dd43ed1 100644 --- a/src/components/water_renderer.rs +++ b/src/components/water_renderer.rs @@ -8,6 +8,8 @@ use crate::framework::graphics; use crate::map::WaterRegionType; use crate::player::Player; use crate::shared_game_state::SharedGameState; +use crate::physics::PhysicalEntity; +use crate::npc::list::NPCList; const TENSION: f32 = 0.03; const DAMPENING: f32 = 0.01; @@ -115,29 +117,49 @@ impl WaterRenderer { } } -impl GameEntity<&Player> for WaterRenderer { - fn tick(&mut self, state: &mut SharedGameState, player: &Player) -> GameResult<()> { - let player_x = player.x as f32 / 512.0 + 8.0; - let player_y = player.y as f32 / 512.0 + 8.0; +impl GameEntity<(&[&Player], &NPCList)> for WaterRenderer { + fn tick(&mut self, state: &mut SharedGameState, (players, npc_list): (&[&Player], &NPCList)) -> GameResult<()> { + if !state.settings.shader_effects { + return Ok(()); + } for surf in self.water_surfaces.iter_mut() { let line_x = surf.x as f32 * 16.0; let line_y = surf.y as f32 * 16.0; - if (player.vel_y > 0x80 || player.vel_y < -0x80) - && player_x > line_x - && player_x < surf.end_x as f32 * 16.0 - && player_y > line_y - 5.0 - && player_y < line_y + 4.0 - { - let col_idx_center = (((player_x - line_x) / 2.0) as i32).clamp(0, surf.columns.len() as i32); - let col_idx_left = (col_idx_center - (player.hit_bounds.left as i32 / (8 * 0x200))) - .clamp(0, surf.columns.len() as i32) as usize; - let col_idx_right = (col_idx_center + (player.hit_bounds.left as i32 / (8 * 0x200))) - .clamp(0, surf.columns.len() as i32) as usize; - for col in surf.columns[col_idx_left..=col_idx_right].iter_mut() { - col.speed = player.vel_y as f32 / 512.0; + let mut tick_object = |obj: &dyn PhysicalEntity| { + let obj_x = obj.x() as f32 / 512.0 + 8.0; + let obj_y = obj.y() as f32 / 512.0 + 8.0; + + if (obj.vel_y() > 0x80 || obj.vel_y() < -0x80) + && obj_x > line_x + && obj_x < surf.end_x as f32 * 16.0 + && obj_y > line_y - 5.0 + && obj_y < line_y + 4.0 + { + let col_idx_center = (((obj_x - line_x) / 2.0) as i32).clamp(0, surf.columns.len() as i32); + let col_idx_left = (col_idx_center - (obj.hit_bounds().left as i32 / (8 * 0x200))) + .clamp(0, surf.columns.len() as i32) as usize; + let col_idx_right = (col_idx_center + (obj.hit_bounds().left as i32 / (8 * 0x200))) + .clamp(0, surf.columns.len() as i32) as usize; + + for col in surf.columns[col_idx_left..=col_idx_right].iter_mut() { + col.speed = (obj.vel_y() as f32 / 512.0) * (obj.hit_rect_size() as f32 * 0.25).clamp(0.1, 1.0); + } } + }; + + for player in players { + tick_object(*player); + } + + for npc in npc_list.iter_alive() { + static NO_COLL_NPCS: [u16; 3] = [0, 3, 4]; + if NO_COLL_NPCS.contains(&npc.npc_type) { + continue; + } + + tick_object(npc); } surf.tick(); @@ -160,7 +182,7 @@ impl GameEntity<&Player> for WaterRenderer { graphics::draw_rect(ctx, out_rect, water_color)?; } - if !graphics::supports_vertex_draw(ctx)? { + if !state.settings.shader_effects || !graphics::supports_vertex_draw(ctx)? { for region in self.surf_regions.iter() { out_rect.left = ((region.left as f32 * 16.0 - o_x - 8.0) * state.scale) as isize; out_rect.top = ((region.top as f32 * 16.0 - o_y - 5.0) * state.scale) as isize; diff --git a/src/engine_constants/mod.rs b/src/engine_constants/mod.rs index 83d4dea..0b7c878 100644 --- a/src/engine_constants/mod.rs +++ b/src/engine_constants/mod.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use case_insensitive_hashmap::CaseInsensitiveHashMap; -use log::info; use crate::case_insensitive_hashmap; use crate::common::{BulletFlag, Color, Rect}; @@ -80,6 +79,12 @@ pub struct CaretConsts { pub question_right_rect: Rect, } +#[derive(serde::Serialize, serde::Deserialize)] +pub struct TextureSizeTable { + r#override: bool, + sizes: HashMap, +} + impl Clone for CaretConsts { fn clone(&self) -> Self { Self { @@ -1487,7 +1492,7 @@ impl EngineConstants { } pub fn apply_csplus_patches(&mut self, sound_manager: &SoundManager) { - info!("Applying Cave Story+ constants patches..."); + log::info!("Applying Cave Story+ constants patches..."); self.is_cs_plus = true; self.supports_og_textures = true; @@ -1530,7 +1535,7 @@ impl EngineConstants { } pub fn apply_csplus_nx_patches(&mut self) { - info!("Applying Switch-specific Cave Story+ constants patches..."); + log::info!("Applying Switch-specific Cave Story+ constants patches..."); self.is_switch = true; self.supports_og_textures = true; @@ -1547,4 +1552,8 @@ impl EngineConstants { self.soundtracks.insert("Famitracks".to_string(), "/base/ogg17/".to_string()); self.soundtracks.insert("Ridiculon".to_string(), "/base/ogg_ridic/".to_string()); } + + pub fn apply_constant_json_files(&mut self) { + + } } diff --git a/src/npc/ai/sand_zone.rs b/src/npc/ai/sand_zone.rs index bb601dd..908ec9b 100644 --- a/src/npc/ai/sand_zone.rs +++ b/src/npc/ai/sand_zone.rs @@ -1,7 +1,7 @@ use num_traits::{abs, clamp}; use crate::caret::CaretType; -use crate::common::{CDEG_RAD, Direction}; +use crate::common::{Direction, CDEG_RAD}; use crate::framework::error::GameResult; use crate::npc::list::NPCList; use crate::npc::NPC; @@ -1038,7 +1038,6 @@ impl NPC { self.y += self.vel_y; self.x += self.vel_x; - let dir_offset = if self.direction == Direction::Left { 0 } else { 10 }; self.anim_rect = state.constants.npc.n122_colon_enraged[self.anim_num as usize + dir_offset]; @@ -1483,13 +1482,13 @@ impl NPC { self.anim_counter = 0; self.anim_num += 1; } - if (self.anim_num > 1) { + if self.anim_num > 1 { self.anim_num = 0; } - if (self.direction == Direction::Left && self.flags.hit_left_wall()) { + if self.direction == Direction::Left && self.flags.hit_left_wall() { self.direction = Direction::Right; } - if (self.direction == Direction::Right && self.flags.hit_right_wall()) { + if self.direction == Direction::Right && self.flags.hit_right_wall() { self.direction = Direction::Left; } self.x += self.direction.vector_x() * 0x100; diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 2968fe5..28a36a2 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -690,12 +690,12 @@ impl GameScene { let d = deg as f32 * (std::f32::consts::PI / 180.0); let dx = d.cos() * -5.0; let dy = d.sin() * -5.0; - let m = 1.0 - ((ahalf - i as f32).abs() / ahalf) * 0.3; + let m = 1.0 - ((ahalf - i as f32).abs() / ahalf); let mut x = px; let mut y = py; - let mut r = br * m; - let mut g = bg * m; - let mut b = bb * m; + let mut r = br; + let mut g = bg; + let mut b = bb; for i in 0..40 { x += dx; @@ -762,15 +762,21 @@ impl GameScene { } } - r -= att; - g -= att; - b -= att; + r *= att; + g *= att; + b *= att; - if r <= 0.0 && g <= 0.0 && b <= 0.0 { + if r <= 1.0 && g <= 1.0 && b <= 1.0 { continue 'ray; } - self.draw_light(x - fx2, y - fy2, 0.12 + i as f32 / 75.0, (r as u8, g as u8, b as u8), batch); + self.draw_light( + x - fx2, + y - fy2, + 0.15 + i as f32 / 75.0, + ((r * m) as u8, (g * m) as u8, (b * m) as u8), + batch, + ); } } } @@ -803,10 +809,11 @@ impl GameScene { }; let (color, att) = match inv.get_current_weapon() { - Some(Weapon { wtype: WeaponType::Fireball, .. }) => ((200u8, 90u8, 10u8), 4.0), - Some(Weapon { wtype: WeaponType::Spur, .. }) => ((170u8, 170u8, 200u8), 6.0), + Some(Weapon { wtype: WeaponType::Fireball, .. }) => ((170u8, 80u8, 0u8), 0.92), + Some(Weapon { wtype: WeaponType::PolarStar, .. }) => ((150u8, 150u8, 160u8), 0.92), + Some(Weapon { wtype: WeaponType::Spur, .. }) => ((170u8, 170u8, 200u8), 0.92), Some(Weapon { wtype: WeaponType::Blade, .. }) => continue 'cc, - _ => ((100u8, 100u8, 100u8), 4.0), + _ => ((150u8, 150u8, 150u8), 0.92), }; let (_, gun_off_y) = player.skin.get_gun_offset(); @@ -1004,7 +1011,7 @@ impl GameScene { ); } 38 => { - let flicker = ((npc.anim_num.wrapping_add(npc.id) ^ 5) & 3) as u8 * 15; + let flicker = ((npc.anim_num.wrapping_add(npc.id) ^ 5) & 3) as u8 * 24; self.draw_light( interpolate_fix9_scale( npc.prev_x - self.frame.prev_x, @@ -1021,6 +1028,23 @@ impl GameScene { batch, ); } + 69 | 81 => { + self.draw_light( + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), + if npc.npc_type == 69 { 0.5 } else { 1.0 }, + (200, 200, 200), + batch, + ); + } 70 => { let flicker = 50 + npc.anim_num as u8 * 15; self.draw_light( @@ -1039,13 +1063,6 @@ impl GameScene { batch, ); } - 75 | 77 => self.draw_light( - interpolate_fix9_scale(npc.prev_x - self.frame.prev_x, npc.x - self.frame.x, state.frame_time), - interpolate_fix9_scale(npc.prev_y - self.frame.prev_y, npc.y - self.frame.y, state.frame_time), - 3.0, - (255, 100, 0), - batch, - ), 85 if npc.action_num == 1 => { let (color, color2) = if npc.direction == Direction::Left { if state.constants.is_cs_plus { @@ -1091,6 +1108,23 @@ impl GameScene { ); } } + 175 if npc.action_num < 10 => { + self.draw_light( + interpolate_fix9_scale( + npc.prev_x - self.frame.prev_x, + npc.x - self.frame.x, + state.frame_time, + ), + interpolate_fix9_scale( + npc.prev_y - self.frame.prev_y, + npc.y - self.frame.y, + state.frame_time, + ), + 1.0, + (128, 175, 200), + batch, + ); + } _ => {} } } @@ -1115,7 +1149,7 @@ impl GameScene { right: (state.screen_size.0 + 1.0) as isize, bottom: (state.screen_size.1 + 1.0) as isize, }, - Color { r: 0.15, g: 0.15, b: 0.15, a: 1.0 }, + Color { r: 0.15, g: 0.12, b: 0.12, a: 1.0 }, )?; graphics::set_render_target(ctx, None)?; graphics::set_blend_mode(ctx, BlendMode::Add)?; @@ -1584,7 +1618,7 @@ impl GameScene { } } - self.water_renderer.tick(state, &self.player1)?; + self.water_renderer.tick(state, (&[&self.player1, &self.player2], &self.npc_list))?; if self.map_name_counter > 0 { self.map_name_counter -= 1; diff --git a/src/texture_set.rs b/src/texture_set.rs index f717a74..7364d02 100644 --- a/src/texture_set.rs +++ b/src/texture_set.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use log::info; use crate::common; -use crate::common::{FILE_TYPES, Rect}; +use crate::common::{Rect, FILE_TYPES}; use crate::engine_constants::EngineConstants; use crate::framework::backend::{BackendTexture, SpriteBatchCommand}; use crate::framework::context::Context; @@ -28,6 +28,8 @@ pub struct SizedBatch { real_height: usize, scale_x: f32, scale_y: f32, + has_glow_layer: bool, + has_normal_layer: bool, } impl SizedBatch { @@ -56,6 +58,16 @@ impl SizedBatch { (self.scale_x, self.scale_y) } + #[inline(always)] + pub fn has_glow_layer(&self) -> bool { + self.has_glow_layer + } + + #[inline(always)] + pub fn has_normal_layer(&self) -> bool { + self.has_normal_layer + } + #[inline(always)] pub fn to_rect(&self) -> common::Rect { common::Rect::::new(0, 0, self.width, self.height) @@ -74,12 +86,7 @@ impl SizedBatch { let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRect( - Rect { - left: 0 as f32, - top: 0 as f32, - right: self.real_width as f32, - bottom: self.real_height as f32, - }, + Rect { left: 0 as f32, top: 0 as f32, right: self.real_width as f32, bottom: self.real_height as f32 }, Rect { left: x * mag, top: y * mag, @@ -99,10 +106,6 @@ impl SizedBatch { return; } - /*unsafe { - x = (x * G_MAG).floor() / G_MAG; - y = (y * G_MAG).floor() / G_MAG; - }*/ let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRectFlip( @@ -118,7 +121,8 @@ impl SizedBatch { right: (x + rect.width() as f32) * mag, bottom: (y + rect.height() as f32) * mag, }, - flip_x, flip_y + flip_x, + flip_y, )); } @@ -154,7 +158,15 @@ impl SizedBatch { )); } - pub fn add_rect_scaled_tinted(&mut self, mut x: f32, mut y: f32, color: (u8, u8, u8, u8), scale_x: f32, scale_y: f32, rect: &common::Rect) { + pub fn add_rect_scaled_tinted( + &mut self, + mut x: f32, + mut y: f32, + color: (u8, u8, u8, u8), + scale_x: f32, + scale_y: f32, + rect: &common::Rect, + ) { if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 { return; } @@ -166,12 +178,7 @@ impl SizedBatch { let mag = unsafe { I_MAG }; self.batch.add(SpriteBatchCommand::DrawRectTinted( - Rect { - left: rect.left as f32, - top: rect.top as f32, - right: rect.right as f32, - bottom: rect.bottom as f32, - }, + Rect { left: rect.left as f32, top: rect.top as f32, right: rect.right as f32, bottom: rect.bottom as f32 }, Rect { left: x * mag, top: y * mag, @@ -202,10 +209,7 @@ pub struct TextureSet { impl TextureSet { pub fn new(base_path: &str) -> TextureSet { - TextureSet { - tex_map: HashMap::new(), - paths: vec![base_path.to_string(), "".to_string()], - } + TextureSet { tex_map: HashMap::new(), paths: vec![base_path.to_string(), "".to_string()] } } pub fn apply_seasonal_content(&mut self, season: Season, settings: &Settings) { @@ -248,14 +252,26 @@ impl TextureSet { } pub fn load_texture(&self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult { - let path = self.paths.iter().find_map(|s| FILE_TYPES + let path = self + .paths .iter() - .map(|ext| [s, name, ext].join("")) - .find(|path| { - println!("{}", path); - filesystem::exists(ctx, path) + .find_map(|s| { + FILE_TYPES.iter().map(|ext| [s, name, ext].join("")).find(|path| { + println!("{}", path); + filesystem::exists(ctx, path) + }) }) - ).ok_or_else(|| GameError::ResourceLoadError(format!("Texture {} does not exist.", name)))?; + .ok_or_else(|| GameError::ResourceLoadError(format!("Texture {} does not exist.", name)))?; + + let has_glow_layer = self + .paths + .iter() + .find_map(|s| { + FILE_TYPES.iter().map(|ext| [s, name, ".glow", ext].join("")).find(|path| { + println!("{}", path); + filesystem::exists(ctx, path) + }) + }).is_some(); info!("Loading texture: {}", path); @@ -278,10 +294,17 @@ impl TextureSet { scale_y: scale, real_width: size.0 as usize, real_height: size.1 as usize, + has_glow_layer, + has_normal_layer: false, }) } - pub fn get_or_load_batch(&mut self, ctx: &mut Context, constants: &EngineConstants, name: &str) -> GameResult<&mut SizedBatch> { + pub fn get_or_load_batch( + &mut self, + ctx: &mut Context, + constants: &EngineConstants, + name: &str, + ) -> GameResult<&mut SizedBatch> { if !self.tex_map.contains_key(name) { let batch = self.load_texture(ctx, constants, name)?; self.tex_map.insert(str!(name), batch);