1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-12-01 08:37:23 +00:00

various lighting improvements

This commit is contained in:
Alula 2021-08-16 18:41:42 +02:00
parent 8a94f7f9d1
commit 55afe1292f
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
5 changed files with 165 additions and 78 deletions

View file

@ -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,30 +117,50 @@ 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 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 = (((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)))
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 + (player.hit_bounds.left as i32 / (8 * 0x200)))
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 = player.vel_y as f32 / 512.0;
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;

View file

@ -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<u16>,
}
#[derive(serde::Serialize, serde::Deserialize)]
pub struct TextureSizeTable {
r#override: bool,
sizes: HashMap<String, (u16, u16)>,
}
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) {
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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<usize> {
common::Rect::<usize>::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<u16>) {
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<u16>,
) {
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<SizedBatch> {
let path = self.paths.iter().find_map(|s| FILE_TYPES
let path = self
.paths
.iter()
.map(|ext| [s, name, ext].join(""))
.find(|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);