mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2024-09-29 21:49:33 +00:00
improved npc lighting
This commit is contained in:
parent
23f0feaae0
commit
1b424f0b80
|
@ -182,6 +182,36 @@ impl NPC {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn draw_lightmap(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult {
|
||||
if !self.cond.alive() || self.cond.hidden() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let texture = state.npc_table.get_texture_name(self.spritesheet_id);
|
||||
|
||||
if let Some(batch) = state.texture_set.get_or_load_batch(ctx, &state.constants, texture)?.glow() {
|
||||
let off_x =
|
||||
if self.direction == Direction::Left { self.display_bounds.left } else { self.display_bounds.right } as i32;
|
||||
let shock = if self.shock > 0 { (2 * ((self.shock as i32 / 2) % 2) - 1) as f32 } else { 0.0 };
|
||||
|
||||
let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time);
|
||||
|
||||
batch.add_rect(
|
||||
interpolate_fix9_scale(self.prev_x - off_x, self.x - off_x, state.frame_time) + shock - frame_x,
|
||||
interpolate_fix9_scale(
|
||||
self.prev_y - self.display_bounds.top as i32,
|
||||
self.y - self.display_bounds.top as i32,
|
||||
state.frame_time,
|
||||
) - frame_y,
|
||||
&self.anim_rect,
|
||||
);
|
||||
|
||||
batch.draw(ctx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mut Flash)> for NPC {
|
||||
|
|
|
@ -795,17 +795,39 @@ impl GameScene {
|
|||
}
|
||||
|
||||
fn draw_light_map(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||
{
|
||||
let canvas = state.lightmap_canvas.as_mut();
|
||||
|
||||
if let None = canvas {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let canvas = canvas.unwrap();
|
||||
|
||||
graphics::set_render_target(ctx, Some(canvas))?;
|
||||
}
|
||||
|
||||
graphics::set_blend_mode(ctx, BlendMode::Add)?;
|
||||
|
||||
graphics::clear(ctx, Color::from_rgb(100, 100, 110));
|
||||
|
||||
for npc in self.npc_list.iter_alive() {
|
||||
if npc.x < (self.frame.x - 128 * 0x200 - npc.display_bounds.width() as i32 * 0x200)
|
||||
|| npc.x
|
||||
> (self.frame.x
|
||||
+ 128 * 0x200
|
||||
+ (state.canvas_size.0 as i32 + npc.display_bounds.width() as i32) * 0x200)
|
||||
&& npc.y < (self.frame.y - 128 * 0x200 - npc.display_bounds.height() as i32 * 0x200)
|
||||
|| npc.y
|
||||
> (self.frame.y
|
||||
+ 128 * 0x200
|
||||
+ (state.canvas_size.1 as i32 + npc.display_bounds.height() as i32) * 0x200)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
npc.draw_lightmap(state, ctx, &self.frame)?;
|
||||
}
|
||||
|
||||
{
|
||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?;
|
||||
|
||||
|
@ -1024,7 +1046,7 @@ impl GameScene {
|
|||
(0, 0, 255),
|
||||
batch,
|
||||
),
|
||||
32 | 87 | 211 => {
|
||||
32 | 87 => {
|
||||
self.draw_light(
|
||||
interpolate_fix9_scale(
|
||||
npc.prev_x - self.frame.prev_x,
|
||||
|
@ -1041,6 +1063,23 @@ impl GameScene {
|
|||
batch,
|
||||
);
|
||||
}
|
||||
211 => {
|
||||
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.5,
|
||||
(128, 0, 0),
|
||||
batch,
|
||||
);
|
||||
}
|
||||
38 => {
|
||||
let flicker = ((npc.anim_num.wrapping_add(npc.id) ^ 5) & 3) as u8 * 24;
|
||||
self.draw_light(
|
||||
|
@ -1139,6 +1178,13 @@ impl GameScene {
|
|||
);
|
||||
}
|
||||
}
|
||||
101 | 102 => 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,
|
||||
(100, 100, 200),
|
||||
batch,
|
||||
),
|
||||
175 if npc.action_num < 10 => {
|
||||
self.draw_light(
|
||||
interpolate_fix9_scale(
|
||||
|
@ -1156,6 +1202,13 @@ impl GameScene {
|
|||
batch,
|
||||
);
|
||||
}
|
||||
189 => 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,
|
||||
(10, 50, 255),
|
||||
batch,
|
||||
),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1166,11 +1219,15 @@ impl GameScene {
|
|||
graphics::set_blend_mode(ctx, BlendMode::Multiply)?;
|
||||
graphics::set_render_target(ctx, None)?;
|
||||
|
||||
{
|
||||
let canvas = state.lightmap_canvas.as_mut().unwrap();
|
||||
let rect = Rect { left: 0.0, top: 0.0, right: state.screen_size.0, bottom: state.screen_size.1 };
|
||||
|
||||
canvas.clear();
|
||||
canvas.add(SpriteBatchCommand::DrawRect(rect, rect));
|
||||
canvas.draw()?;
|
||||
|
||||
|
||||
graphics::set_render_target(ctx, Some(canvas))?;
|
||||
graphics::draw_rect(
|
||||
ctx,
|
||||
|
@ -1187,6 +1244,7 @@ impl GameScene {
|
|||
canvas.draw()?;
|
||||
|
||||
graphics::set_blend_mode(ctx, BlendMode::Alpha)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -34,6 +34,14 @@ pub trait SpriteBatch {
|
|||
|
||||
fn has_normal_layer(&self) -> bool;
|
||||
|
||||
fn glow(&mut self) -> Option<&mut dyn SpriteBatch> {
|
||||
None
|
||||
}
|
||||
|
||||
fn normal(&mut self) -> Option<&mut dyn SpriteBatch> {
|
||||
None
|
||||
}
|
||||
|
||||
fn to_rect(&self) -> common::Rect<usize>;
|
||||
|
||||
fn clear(&mut self);
|
||||
|
@ -130,37 +138,40 @@ impl SpriteBatch for DummyBatch {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SizedBatch {
|
||||
pub struct SubBatch {
|
||||
batch: Box<dyn BackendTexture>,
|
||||
width: usize,
|
||||
height: usize,
|
||||
real_width: usize,
|
||||
real_height: usize,
|
||||
width: u16,
|
||||
height: u16,
|
||||
real_width: u16,
|
||||
real_height: u16,
|
||||
scale_x: f32,
|
||||
scale_y: f32,
|
||||
has_glow_layer: bool,
|
||||
has_normal_layer: bool,
|
||||
}
|
||||
|
||||
impl SpriteBatch for SizedBatch {
|
||||
pub struct CombinedBatch {
|
||||
main_batch: SubBatch,
|
||||
glow_batch: Option<SubBatch>,
|
||||
}
|
||||
|
||||
impl SpriteBatch for SubBatch {
|
||||
#[inline(always)]
|
||||
fn width(&self) -> usize {
|
||||
self.width
|
||||
self.width as _
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn height(&self) -> usize {
|
||||
self.height
|
||||
self.height as _
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn dimensions(&self) -> (usize, usize) {
|
||||
(self.width, self.height)
|
||||
(self.width as _, self.height as _)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn real_dimensions(&self) -> (usize, usize) {
|
||||
(self.real_width, self.real_height)
|
||||
(self.real_width as _, self.real_height as _)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -170,17 +181,17 @@ impl SpriteBatch for SizedBatch {
|
|||
|
||||
#[inline(always)]
|
||||
fn has_glow_layer(&self) -> bool {
|
||||
self.has_glow_layer
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn has_normal_layer(&self) -> bool {
|
||||
self.has_normal_layer
|
||||
false
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn to_rect(&self) -> common::Rect<usize> {
|
||||
common::Rect::<usize>::new(0, 0, self.width, self.height)
|
||||
common::Rect::<usize>::new(0, 0, self.width as _, self.height as _)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -300,6 +311,92 @@ impl SpriteBatch for SizedBatch {
|
|||
}
|
||||
}
|
||||
|
||||
impl SpriteBatch for CombinedBatch {
|
||||
fn width(&self) -> usize {
|
||||
self.main_batch.width as _
|
||||
}
|
||||
|
||||
fn height(&self) -> usize {
|
||||
self.main_batch.height as _
|
||||
}
|
||||
|
||||
fn dimensions(&self) -> (usize, usize) {
|
||||
self.main_batch.dimensions()
|
||||
}
|
||||
|
||||
fn real_dimensions(&self) -> (usize, usize) {
|
||||
self.main_batch.real_dimensions()
|
||||
}
|
||||
|
||||
fn scale(&self) -> (f32, f32) {
|
||||
self.main_batch.scale()
|
||||
}
|
||||
|
||||
fn has_glow_layer(&self) -> bool {
|
||||
self.glow_batch.is_some()
|
||||
}
|
||||
|
||||
fn has_normal_layer(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn glow(&mut self) -> Option<&mut dyn SpriteBatch> {
|
||||
if let Some(batch) = self.glow_batch.as_mut() {
|
||||
Some(batch)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn to_rect(&self) -> Rect<usize> {
|
||||
self.main_batch.to_rect()
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.main_batch.clear()
|
||||
}
|
||||
|
||||
fn add(&mut self, x: f32, y: f32) {
|
||||
self.main_batch.add(x, y)
|
||||
}
|
||||
|
||||
fn add_rect(&mut self, x: f32, y: f32, rect: &Rect<u16>) {
|
||||
self.main_batch.add_rect(x, y, rect)
|
||||
}
|
||||
|
||||
fn add_rect_flip(&mut self, x: f32, y: f32, flip_x: bool, flip_y: bool, rect: &Rect<u16>) {
|
||||
self.main_batch.add_rect_flip(x, y, flip_x, flip_y, rect)
|
||||
}
|
||||
|
||||
fn add_rect_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8, u8), rect: &Rect<u16>) {
|
||||
self.main_batch.add_rect_tinted(x, y, color, rect)
|
||||
}
|
||||
|
||||
fn add_rect_scaled(&mut self, x: f32, y: f32, scale_x: f32, scale_y: f32, rect: &Rect<u16>) {
|
||||
self.main_batch.add_rect_scaled(x, y, scale_x, scale_y, rect)
|
||||
}
|
||||
|
||||
fn add_rect_scaled_tinted(
|
||||
&mut self,
|
||||
x: f32,
|
||||
y: f32,
|
||||
color: (u8, u8, u8, u8),
|
||||
scale_x: f32,
|
||||
scale_y: f32,
|
||||
rect: &Rect<u16>,
|
||||
) {
|
||||
self.main_batch.add_rect_scaled_tinted(x, y, color, scale_x, scale_y, rect)
|
||||
}
|
||||
|
||||
fn draw(&mut self, ctx: &mut Context) -> GameResult {
|
||||
self.main_batch.draw(ctx)
|
||||
}
|
||||
|
||||
fn draw_filtered(&mut self, filter: FilterMode, ctx: &mut Context) -> GameResult {
|
||||
self.main_batch.draw_filtered(filter, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TextureSet {
|
||||
pub tex_map: HashMap<String, Box<dyn SpriteBatch>>,
|
||||
pub paths: Vec<String>,
|
||||
|
@ -354,15 +451,8 @@ impl TextureSet {
|
|||
create_texture(ctx, width as u16, height as u16, &img)
|
||||
}
|
||||
|
||||
pub fn find_texture(
|
||||
&self,
|
||||
ctx: &mut Context,
|
||||
name: &str,
|
||||
) -> Option<String> {
|
||||
self
|
||||
.paths
|
||||
.iter()
|
||||
.find_map(|s| {
|
||||
pub fn find_texture(&self, ctx: &mut Context, name: &str) -> Option<String> {
|
||||
self.paths.iter().find_map(|s| {
|
||||
FILE_TYPES.iter().map(|ext| [s, name, ext].join("")).find(|path| filesystem::exists(ctx, path))
|
||||
})
|
||||
}
|
||||
|
@ -373,38 +463,41 @@ impl TextureSet {
|
|||
constants: &EngineConstants,
|
||||
name: &str,
|
||||
) -> GameResult<Box<dyn SpriteBatch>> {
|
||||
let path = self.find_texture(ctx, name)
|
||||
let path = self
|
||||
.find_texture(ctx, 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| filesystem::exists(ctx, path))
|
||||
})
|
||||
.is_some();
|
||||
let glow_path = self.find_texture(ctx, [name, ".glow"].join("").as_str());
|
||||
|
||||
info!("Loading texture: {} -> {}", name, path);
|
||||
|
||||
let batch = self.load_image(ctx, &path)?;
|
||||
fn make_batch(name: &str, constants: &EngineConstants, batch: Box<dyn BackendTexture>) -> SubBatch {
|
||||
let size = batch.dimensions();
|
||||
|
||||
let orig_dimensions = constants.tex_sizes.get(name).unwrap_or_else(|| &size);
|
||||
let scale = orig_dimensions.0 as f32 / size.0 as f32;
|
||||
let width = (size.0 as f32 * scale) as usize;
|
||||
let height = (size.1 as f32 * scale) as usize;
|
||||
let width = (size.0 as f32 * scale) as _;
|
||||
let height = (size.1 as f32 * scale) as _;
|
||||
|
||||
Ok(Box::new(SizedBatch {
|
||||
SubBatch {
|
||||
batch,
|
||||
width,
|
||||
height,
|
||||
scale_x: scale,
|
||||
scale_y: scale,
|
||||
real_width: size.0 as usize,
|
||||
real_height: size.1 as usize,
|
||||
has_glow_layer,
|
||||
has_normal_layer: false,
|
||||
}))
|
||||
real_width: size.0 as _,
|
||||
real_height: size.1 as _,
|
||||
}
|
||||
}
|
||||
|
||||
let main_batch = make_batch(name, constants, self.load_image(ctx, &path)?);
|
||||
let glow_batch = if let Some(glow_path) = glow_path {
|
||||
self.load_image(ctx, &glow_path).ok().map(|b| make_batch(name, constants, b))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(Box::new(CombinedBatch { main_batch, glow_batch }))
|
||||
}
|
||||
|
||||
pub fn get_or_load_batch(
|
||||
|
|
Loading…
Reference in a new issue