mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-12-01 00:29:58 +00:00
omg sdl2 port finally fully works?
This commit is contained in:
parent
cc816d0380
commit
c3887e31c7
|
|
@ -41,7 +41,7 @@ opt-level = 1
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["scripting", "backend-sdl"]
|
default = ["scripting", "backend-sdl"]
|
||||||
backend-sdl = ["sdl2"]
|
backend-sdl = ["sdl2", "sdl2-sys"]
|
||||||
backend-gfx = ["winit", "imgui-gfx-renderer", "imgui-winit-support"]
|
backend-gfx = ["winit", "imgui-gfx-renderer", "imgui-winit-support"]
|
||||||
scripting = ["lua-ffi"]
|
scripting = ["lua-ffi"]
|
||||||
editor = []
|
editor = []
|
||||||
|
|
@ -66,7 +66,8 @@ num-derive = "0.3.2"
|
||||||
num-traits = "0.2.12"
|
num-traits = "0.2.12"
|
||||||
paste = "1.0.0"
|
paste = "1.0.0"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
sdl2 = { version = "0.34.3", optional = true, features = ["unsafe_textures", "bundled"] }
|
sdl2 = { version = "0.34.3", optional = true, features = ["unsafe_textures", "bundled", "static-link"] }
|
||||||
|
sdl2-sys = { version = "0.34", optional = true }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_derive = "1"
|
serde_derive = "1"
|
||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::common::{Color, Rect, Point};
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::GameResult;
|
use crate::framework::error::GameResult;
|
||||||
use crate::Game;
|
use crate::Game;
|
||||||
|
use crate::framework::graphics::BlendMode;
|
||||||
|
|
||||||
pub trait Backend {
|
pub trait Backend {
|
||||||
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>>;
|
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>>;
|
||||||
|
|
@ -18,7 +19,13 @@ pub trait BackendRenderer {
|
||||||
|
|
||||||
fn present(&mut self) -> GameResult;
|
fn present(&mut self) -> GameResult;
|
||||||
|
|
||||||
|
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>>;
|
||||||
|
|
||||||
fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>>;
|
fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>>;
|
||||||
|
|
||||||
|
fn set_blend_mode(&mut self, blend: BlendMode) -> GameResult;
|
||||||
|
|
||||||
|
fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> GameResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BackendTexture {
|
pub trait BackendTexture {
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@ use sdl2::{EventPump, keyboard, pixels, Sdl};
|
||||||
use sdl2::event::{Event, WindowEvent};
|
use sdl2::event::{Event, WindowEvent};
|
||||||
use sdl2::keyboard::Scancode;
|
use sdl2::keyboard::Scancode;
|
||||||
use sdl2::pixels::PixelFormatEnum;
|
use sdl2::pixels::PixelFormatEnum;
|
||||||
use sdl2::render::{BlendMode, Texture, TextureCreator, WindowCanvas};
|
use sdl2::render::{Texture, TextureCreator, WindowCanvas};
|
||||||
use sdl2::video::WindowContext;
|
use sdl2::video::WindowContext;
|
||||||
|
|
||||||
use crate::common::Color;
|
use crate::common::Color;
|
||||||
use crate::framework::backend::{Backend, BackendEventLoop, BackendRenderer, BackendTexture, SpriteBatchCommand};
|
use crate::framework::backend::{Backend, BackendEventLoop, BackendRenderer, BackendTexture, SpriteBatchCommand};
|
||||||
use crate::framework::context::Context;
|
use crate::framework::context::Context;
|
||||||
use crate::framework::error::{GameError, GameResult};
|
use crate::framework::error::{GameError, GameResult};
|
||||||
|
use crate::framework::graphics::BlendMode;
|
||||||
use crate::framework::keyboard::ScanCode;
|
use crate::framework::keyboard::ScanCode;
|
||||||
use crate::Game;
|
use crate::Game;
|
||||||
|
|
||||||
|
|
@ -46,10 +47,13 @@ struct SDL2EventLoop {
|
||||||
struct SDL2Context {
|
struct SDL2Context {
|
||||||
canvas: WindowCanvas,
|
canvas: WindowCanvas,
|
||||||
texture_creator: TextureCreator<WindowContext>,
|
texture_creator: TextureCreator<WindowContext>,
|
||||||
|
blend_mode: sdl2::render::BlendMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SDL2EventLoop {
|
impl SDL2EventLoop {
|
||||||
pub fn new(sdl: &Sdl) -> GameResult<Box<dyn BackendEventLoop>> {
|
pub fn new(sdl: &Sdl) -> GameResult<Box<dyn BackendEventLoop>> {
|
||||||
|
sdl2::hint::set("SDL_HINT_RENDER_DRIVER", "opengles2");
|
||||||
|
|
||||||
let event_pump = sdl.event_pump().map_err(|e| GameError::WindowError(e))?;
|
let event_pump = sdl.event_pump().map_err(|e| GameError::WindowError(e))?;
|
||||||
let video = sdl.video().map_err(|e| GameError::WindowError(e))?;
|
let video = sdl.video().map_err(|e| GameError::WindowError(e))?;
|
||||||
let window = video.window("Cave Story (doukutsu-rs)", 640, 480)
|
let window = video.window("Cave Story (doukutsu-rs)", 640, 480)
|
||||||
|
|
@ -71,6 +75,7 @@ impl SDL2EventLoop {
|
||||||
refs: Rc::new(RefCell::new(SDL2Context {
|
refs: Rc::new(RefCell::new(SDL2Context {
|
||||||
canvas,
|
canvas,
|
||||||
texture_creator,
|
texture_creator,
|
||||||
|
blend_mode: sdl2::render::BlendMode::Blend,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -82,6 +87,12 @@ impl BackendEventLoop for SDL2EventLoop {
|
||||||
fn run(&mut self, game: &mut Game, ctx: &mut Context) {
|
fn run(&mut self, game: &mut Game, ctx: &mut Context) {
|
||||||
let state = unsafe { &mut *game.state.get() };
|
let state = unsafe { &mut *game.state.get() };
|
||||||
|
|
||||||
|
{
|
||||||
|
let (width, height) = self.refs.borrow().canvas.window().size();
|
||||||
|
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32);
|
||||||
|
let _ = state.handle_resize(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
for event in self.event_pump.poll_iter() {
|
for event in self.event_pump.poll_iter() {
|
||||||
match event {
|
match event {
|
||||||
|
|
@ -160,6 +171,14 @@ fn to_sdl(color: Color) -> pixels::Color {
|
||||||
pixels::Color::RGBA(r, g, b, a)
|
pixels::Color::RGBA(r, g, b, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn set_raw_target(renderer: *mut sdl2::sys::SDL_Renderer, raw_texture: *mut sdl2::sys::SDL_Texture) -> GameResult {
|
||||||
|
if sdl2::sys::SDL_SetRenderTarget(renderer, raw_texture) == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(GameError::RenderError(sdl2::get_error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BackendRenderer for SDL2Renderer {
|
impl BackendRenderer for SDL2Renderer {
|
||||||
fn clear(&mut self, color: Color) {
|
fn clear(&mut self, color: Color) {
|
||||||
let mut refs = self.refs.borrow_mut();
|
let mut refs = self.refs.borrow_mut();
|
||||||
|
|
@ -176,6 +195,22 @@ impl BackendRenderer for SDL2Renderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
|
||||||
|
let mut refs = self.refs.borrow_mut();
|
||||||
|
|
||||||
|
let mut texture = refs.texture_creator
|
||||||
|
.create_texture_target(PixelFormatEnum::RGBA32, width as u32, height as u32)
|
||||||
|
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(Box::new(SDL2Texture {
|
||||||
|
refs: self.refs.clone(),
|
||||||
|
texture: Some(texture),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
commands: vec![],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
||||||
let mut refs = self.refs.borrow_mut();
|
let mut refs = self.refs.borrow_mut();
|
||||||
|
|
||||||
|
|
@ -183,7 +218,7 @@ impl BackendRenderer for SDL2Renderer {
|
||||||
.create_texture_streaming(PixelFormatEnum::RGBA32, width as u32, height as u32)
|
.create_texture_streaming(PixelFormatEnum::RGBA32, width as u32, height as u32)
|
||||||
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
||||||
|
|
||||||
texture.set_blend_mode(BlendMode::Blend);
|
texture.set_blend_mode(sdl2::render::BlendMode::Blend);
|
||||||
texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
|
texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
|
||||||
for y in 0..(height as usize) {
|
for y in 0..(height as usize) {
|
||||||
for x in 0..(width as usize) {
|
for x in 0..(width as usize) {
|
||||||
|
|
@ -198,13 +233,47 @@ impl BackendRenderer for SDL2Renderer {
|
||||||
}
|
}
|
||||||
}).map_err(|e| GameError::RenderError(e.to_string()))?;
|
}).map_err(|e| GameError::RenderError(e.to_string()))?;
|
||||||
|
|
||||||
return Ok(Box::new(SDL2Texture {
|
Ok(Box::new(SDL2Texture {
|
||||||
refs: self.refs.clone(),
|
refs: self.refs.clone(),
|
||||||
texture: Some(texture),
|
texture: Some(texture),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
commands: vec![],
|
commands: vec![],
|
||||||
}));
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_blend_mode(&mut self, blend: BlendMode) -> GameResult {
|
||||||
|
let mut refs = self.refs.borrow_mut();
|
||||||
|
|
||||||
|
refs.blend_mode = match blend {
|
||||||
|
BlendMode::Add => sdl2::render::BlendMode::Add,
|
||||||
|
BlendMode::Alpha => sdl2::render::BlendMode::Blend,
|
||||||
|
BlendMode::Multiply => sdl2::render::BlendMode::Mod,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
|
||||||
|
let renderer = self.refs.borrow().canvas.raw();
|
||||||
|
|
||||||
|
// todo: horribly unsafe
|
||||||
|
match texture {
|
||||||
|
Some(texture) => unsafe {
|
||||||
|
let sdl2_texture: &Box<SDL2Texture> = std::mem::transmute(texture);
|
||||||
|
|
||||||
|
if let Some(target) = sdl2_texture.texture.as_ref() {
|
||||||
|
set_raw_target(renderer, target.raw());
|
||||||
|
} else {
|
||||||
|
set_raw_target(renderer, std::ptr::null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => unsafe {
|
||||||
|
set_raw_target(renderer, std::ptr::null_mut());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,20 +308,22 @@ impl BackendTexture for SDL2Texture {
|
||||||
SpriteBatchCommand::DrawRect(src, dest) => {
|
SpriteBatchCommand::DrawRect(src, dest) => {
|
||||||
texture.set_color_mod(255, 255, 255);
|
texture.set_color_mod(255, 255, 255);
|
||||||
texture.set_alpha_mod(255);
|
texture.set_alpha_mod(255);
|
||||||
|
texture.set_blend_mode(refs.blend_mode);
|
||||||
|
|
||||||
refs.canvas.copy(texture,
|
refs.canvas.copy(texture,
|
||||||
Some(sdl2::rect::Rect::new(src.left as i32, src.top as i32, src.width() as u32, src.height() as u32)),
|
Some(sdl2::rect::Rect::new(src.left.round() as i32, src.top.round() as i32, src.width().round() as u32, src.height().round() as u32)),
|
||||||
Some(sdl2::rect::Rect::new(dest.left as i32, dest.top as i32, dest.width() as u32, dest.height() as u32)))
|
Some(sdl2::rect::Rect::new(dest.left.round() as i32, dest.top.round() as i32, dest.width().round() as u32, dest.height().round() as u32)))
|
||||||
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
||||||
}
|
}
|
||||||
SpriteBatchCommand::DrawRectTinted(src, dest, color) => {
|
SpriteBatchCommand::DrawRectTinted(src, dest, color) => {
|
||||||
let (r, g, b, a) = color.to_rgba();
|
let (r, g, b, a) = color.to_rgba();
|
||||||
texture.set_color_mod(r, g, b);
|
texture.set_color_mod(r, g, b);
|
||||||
texture.set_alpha_mod(a);
|
texture.set_alpha_mod(a);
|
||||||
|
texture.set_blend_mode(refs.blend_mode);
|
||||||
|
|
||||||
refs.canvas.copy(texture,
|
refs.canvas.copy(texture,
|
||||||
Some(sdl2::rect::Rect::new(src.left as i32, src.top as i32, src.width() as u32, src.height() as u32)),
|
Some(sdl2::rect::Rect::new(src.left.round() as i32, src.top.round() as i32, src.width().round() as u32, src.height().round() as u32)),
|
||||||
Some(sdl2::rect::Rect::new(dest.left as i32, dest.top as i32, dest.width() as u32, dest.height() as u32)))
|
Some(sdl2::rect::Rect::new(dest.left.round() as i32, dest.top.round() as i32, dest.width().round() as u32, dest.height().round() as u32)))
|
||||||
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
.map_err(|e| GameError::RenderError(e.to_string()))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,18 @@ pub enum FilterMode {
|
||||||
Linear,
|
Linear,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Canvas {}
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum BlendMode {
|
||||||
impl Canvas {
|
/// When combining two fragments, add their values together, saturating
|
||||||
|
/// at 1.0
|
||||||
|
Add,
|
||||||
|
/// When combining two fragments, add the value of the source times its
|
||||||
|
/// alpha channel with the value of the destination multiplied by the inverse
|
||||||
|
/// of the source alpha channel. Has the usual transparency effect: mixes the
|
||||||
|
/// two colors using a fraction of each one specified by the alpha of the source.
|
||||||
|
Alpha,
|
||||||
|
/// When combining two fragments, multiply their values together.
|
||||||
|
Multiply,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(ctx: &mut Context, color: Color) {
|
pub fn clear(ctx: &mut Context, color: Color) {
|
||||||
|
|
@ -32,6 +40,14 @@ pub fn renderer_initialized(ctx: &mut Context) -> bool {
|
||||||
ctx.renderer.is_some()
|
ctx.renderer.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_texture_mutable(ctx: &mut Context, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
|
||||||
|
if let Some(renderer) = ctx.renderer.as_mut() {
|
||||||
|
return renderer.create_texture_mutable(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_texture(ctx: &mut Context, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
pub fn create_texture(ctx: &mut Context, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
||||||
if let Some(renderer) = ctx.renderer.as_mut() {
|
if let Some(renderer) = ctx.renderer.as_mut() {
|
||||||
return renderer.create_texture(width, height, data);
|
return renderer.create_texture(width, height, data);
|
||||||
|
|
@ -43,3 +59,19 @@ pub fn create_texture(ctx: &mut Context, width: u16, height: u16, data: &[u8]) -
|
||||||
pub fn screen_size(ctx: &mut Context) -> (f32, f32) {
|
pub fn screen_size(ctx: &mut Context) -> (f32, f32) {
|
||||||
ctx.screen_size
|
ctx.screen_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_render_target(ctx: &mut Context, texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
|
||||||
|
if let Some(renderer) = ctx.renderer.as_mut() {
|
||||||
|
return renderer.set_render_target(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_blend_mode(ctx: &mut Context, blend: BlendMode) -> GameResult {
|
||||||
|
if let Some(renderer) = ctx.renderer.as_mut() {
|
||||||
|
return renderer.set_blend_mode(blend);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string()))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,18 @@ use num_traits::{abs, clamp};
|
||||||
|
|
||||||
use crate::bullet::BulletManager;
|
use crate::bullet::BulletManager;
|
||||||
use crate::caret::CaretType;
|
use crate::caret::CaretType;
|
||||||
use crate::common::{Direction, FadeDirection, FadeState, fix9_scale, interpolate_fix9_scale, Rect, Color};
|
use crate::common::{Color, Direction, FadeDirection, FadeState, fix9_scale, interpolate_fix9_scale, Rect};
|
||||||
use crate::components::boss_life_bar::BossLifeBar;
|
use crate::components::boss_life_bar::BossLifeBar;
|
||||||
use crate::components::draw_common::{Alignment, draw_number};
|
use crate::components::draw_common::{Alignment, draw_number};
|
||||||
use crate::components::hud::HUD;
|
use crate::components::hud::HUD;
|
||||||
use crate::components::stage_select::StageSelect;
|
use crate::components::stage_select::StageSelect;
|
||||||
use crate::entity::GameEntity;
|
use crate::entity::GameEntity;
|
||||||
use crate::frame::{Frame, UpdateTarget};
|
use crate::frame::{Frame, UpdateTarget};
|
||||||
|
use crate::framework::backend::SpriteBatchCommand;
|
||||||
|
use crate::framework::context::Context;
|
||||||
|
use crate::framework::error::GameResult;
|
||||||
|
use crate::framework::graphics;
|
||||||
|
use crate::framework::graphics::{BlendMode, FilterMode};
|
||||||
use crate::input::touch_controls::TouchControlType;
|
use crate::input::touch_controls::TouchControlType;
|
||||||
use crate::inventory::{Inventory, TakeExperienceResult};
|
use crate::inventory::{Inventory, TakeExperienceResult};
|
||||||
use crate::npc::boss::BossNPC;
|
use crate::npc::boss::BossNPC;
|
||||||
|
|
@ -26,10 +31,6 @@ use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState,
|
||||||
use crate::texture_set::SizedBatch;
|
use crate::texture_set::SizedBatch;
|
||||||
use crate::ui::Components;
|
use crate::ui::Components;
|
||||||
use crate::weapon::WeaponType;
|
use crate::weapon::WeaponType;
|
||||||
use crate::framework::context::Context;
|
|
||||||
use crate::framework::error::GameResult;
|
|
||||||
use crate::framework::graphics;
|
|
||||||
use crate::framework::graphics::FilterMode;
|
|
||||||
|
|
||||||
pub struct GameScene {
|
pub struct GameScene {
|
||||||
pub tick: u32,
|
pub tick: u32,
|
||||||
|
|
@ -297,18 +298,18 @@ impl GameScene {
|
||||||
FadeDirection::Left | FadeDirection::Right => {
|
FadeDirection::Left | FadeDirection::Right => {
|
||||||
let mut frame = tick;
|
let mut frame = tick;
|
||||||
|
|
||||||
for x in (0..(state.canvas_size.0 as i32 + 16)).step_by(16) {
|
for x in 0..(state.canvas_size.0 as i32 / 16 + 1) {
|
||||||
if frame >= 15 { frame = 15; } else { frame += 1; }
|
if frame >= 15 { frame = 15; } else { frame += 1; }
|
||||||
|
|
||||||
if frame >= 0 {
|
if frame >= 0 {
|
||||||
rect.left = frame.abs() as u16 * 16;
|
rect.left = frame.abs() as u16 * 16;
|
||||||
rect.right = rect.left + 16;
|
rect.right = rect.left + 16;
|
||||||
|
|
||||||
for y in (0..(state.canvas_size.1 as i32 + 16)).step_by(16) {
|
for y in 0..(state.canvas_size.1 as i32 / 16 + 1) {
|
||||||
if direction == FadeDirection::Left {
|
if direction == FadeDirection::Left {
|
||||||
batch.add_rect(state.canvas_size.0 - x as f32, y as f32, &rect);
|
batch.add_rect(state.canvas_size.0 - x as f32 * 16.0, y as f32 * 16.0, &rect);
|
||||||
} else {
|
} else {
|
||||||
batch.add_rect(x as f32, y as f32, &rect);
|
batch.add_rect(x as f32 * 16.0, y as f32 * 16.0, &rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -317,18 +318,18 @@ impl GameScene {
|
||||||
FadeDirection::Up | FadeDirection::Down => {
|
FadeDirection::Up | FadeDirection::Down => {
|
||||||
let mut frame = tick;
|
let mut frame = tick;
|
||||||
|
|
||||||
for y in (0..(state.canvas_size.1 as i32 + 16)).step_by(16) {
|
for y in 0..(state.canvas_size.1 as i32 / 16 + 1) {
|
||||||
if frame >= 15 { frame = 15; } else { frame += 1; }
|
if frame >= 15 { frame = 15; } else { frame += 1; }
|
||||||
|
|
||||||
if frame >= 0 {
|
if frame >= 0 {
|
||||||
rect.left = frame.abs() as u16 * 16;
|
rect.left = frame.abs() as u16 * 16;
|
||||||
rect.right = rect.left + 16;
|
rect.right = rect.left + 16;
|
||||||
|
|
||||||
for x in (0..(state.canvas_size.0 as i32 + 16)).step_by(16) {
|
for x in 0..(state.canvas_size.0 as i32 / 16 + 1) {
|
||||||
if direction == FadeDirection::Down {
|
if direction == FadeDirection::Down {
|
||||||
batch.add_rect(x as f32, y as f32, &rect);
|
batch.add_rect(x as f32 * 16.0, y as f32 * 16.0, &rect);
|
||||||
} else {
|
} else {
|
||||||
batch.add_rect(x as f32, state.canvas_size.1 - y as f32, &rect);
|
batch.add_rect(x as f32 * 16.0, state.canvas_size.1 - y as f32 * 16.0, &rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -342,7 +343,7 @@ impl GameScene {
|
||||||
for x in 0..(center_x / 16 + 2) {
|
for x in 0..(center_x / 16 + 2) {
|
||||||
let mut frame = start_frame;
|
let mut frame = start_frame;
|
||||||
|
|
||||||
for y in 0..(center_y / 16 + 1) {
|
for y in 0..(center_y / 16 + 2) {
|
||||||
if frame >= 15 { frame = 15; } else { frame += 1; }
|
if frame >= 15 { frame = 15; } else { frame += 1; }
|
||||||
|
|
||||||
if frame >= 0 {
|
if frame >= 0 {
|
||||||
|
|
@ -502,10 +503,17 @@ impl GameScene {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_light_map(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
fn draw_light_map(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
|
||||||
/*graphics::set_canvas(ctx, Some(&state.lightmap_canvas));
|
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::set_blend_mode(ctx, BlendMode::Add)?;
|
||||||
|
|
||||||
graphics::clear(ctx, Color::from_rgb(100, 100, 110));*/
|
graphics::clear(ctx, Color::from_rgb(100, 100, 110));
|
||||||
{
|
{
|
||||||
let scale = state.scale;
|
let scale = state.scale;
|
||||||
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?;
|
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?;
|
||||||
|
|
@ -547,9 +555,9 @@ impl GameScene {
|
||||||
fix9_scale(npc.y - self.frame.y, scale),
|
fix9_scale(npc.y - self.frame.y, scale),
|
||||||
0.4, (255, 255, 0), batch);
|
0.4, (255, 255, 0), batch);
|
||||||
}
|
}
|
||||||
4 | 7 => self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
7 => self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
||||||
fix9_scale(npc.y - self.frame.y, scale),
|
fix9_scale(npc.y - self.frame.y, scale),
|
||||||
1.0, (100, 100, 100), batch),
|
1.0, (100, 100, 100), batch),
|
||||||
17 if npc.anim_num == 0 => {
|
17 if npc.anim_num == 0 => {
|
||||||
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
||||||
fix9_scale(npc.y - self.frame.y, scale),
|
fix9_scale(npc.y - self.frame.y, scale),
|
||||||
|
|
@ -584,13 +592,6 @@ impl GameScene {
|
||||||
fix9_scale(npc.y - self.frame.y, scale),
|
fix9_scale(npc.y - self.frame.y, scale),
|
||||||
3.5, (130 + flicker, 40 + flicker, 0), batch);
|
3.5, (130 + flicker, 40 + flicker, 0), batch);
|
||||||
}
|
}
|
||||||
66 if npc.action_num == 1 && npc.anim_counter % 2 == 0 =>
|
|
||||||
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
|
||||||
fix9_scale(npc.y - self.frame.y, scale),
|
|
||||||
3.0, (0, 100, 255), batch),
|
|
||||||
67 => self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
|
||||||
fix9_scale(npc.y - self.frame.y, scale),
|
|
||||||
2.0, (0, 100, 200), batch),
|
|
||||||
70 => {
|
70 => {
|
||||||
let flicker = 50 + npc.anim_num as u8 * 15;
|
let flicker = 50 + npc.anim_num as u8 * 15;
|
||||||
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
|
||||||
|
|
@ -634,13 +635,15 @@ impl GameScene {
|
||||||
batch.draw_filtered(FilterMode::Linear, ctx)?;
|
batch.draw_filtered(FilterMode::Linear, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*graphics::set_blend_mode(ctx, BlendMode::Multiply)?;
|
graphics::set_blend_mode(ctx, BlendMode::Multiply)?;
|
||||||
graphics::set_canvas(ctx, Some(&state.game_canvas));
|
graphics::set_render_target(ctx, None);
|
||||||
state.lightmap_canvas.set_filter(FilterMode::Linear);
|
|
||||||
state.lightmap_canvas.draw(ctx, DrawParam::new()
|
|
||||||
.scale(Vector2::new(1.0 / state.scale, 1.0 / state.scale)))?;
|
|
||||||
|
|
||||||
graphics::set_blend_mode(ctx, BlendMode::Alpha)?;*/
|
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_blend_mode(ctx, BlendMode::Alpha)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1213,13 +1216,13 @@ impl Scene for GameScene {
|
||||||
//graphics::set_canvas(ctx, Some(&state.game_canvas));
|
//graphics::set_canvas(ctx, Some(&state.game_canvas));
|
||||||
self.draw_background(state, ctx)?;
|
self.draw_background(state, ctx)?;
|
||||||
self.draw_tiles(state, ctx, TileLayer::Background)?;
|
self.draw_tiles(state, ctx, TileLayer::Background)?;
|
||||||
/*if state.settings.shader_effects
|
if state.settings.shader_effects
|
||||||
&& self.stage.data.background_type != BackgroundType::Black
|
&& self.stage.data.background_type != BackgroundType::Black
|
||||||
&& self.stage.data.background_type != BackgroundType::Outside
|
&& self.stage.data.background_type != BackgroundType::Outside
|
||||||
&& self.stage.data.background_type != BackgroundType::OutsideWind
|
&& self.stage.data.background_type != BackgroundType::OutsideWind
|
||||||
&& self.stage.data.background.name() != "bkBlack" {
|
&& self.stage.data.background.name() != "bkBlack" {
|
||||||
self.draw_light_map(state, ctx)?;
|
self.draw_light_map(state, ctx)?;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
self.boss.draw(state, ctx, &self.frame)?;
|
self.boss.draw(state, ctx, &self.frame)?;
|
||||||
for npc in self.npc_list.iter_alive() {
|
for npc in self.npc_list.iter_alive() {
|
||||||
|
|
@ -1242,11 +1245,11 @@ impl Scene for GameScene {
|
||||||
self.draw_tiles(state, ctx, TileLayer::Foreground)?;
|
self.draw_tiles(state, ctx, TileLayer::Foreground)?;
|
||||||
self.draw_tiles(state, ctx, TileLayer::Snack)?;
|
self.draw_tiles(state, ctx, TileLayer::Snack)?;
|
||||||
self.draw_carets(state, ctx)?;
|
self.draw_carets(state, ctx)?;
|
||||||
/*if state.settings.shader_effects
|
if state.settings.shader_effects
|
||||||
&& (self.stage.data.background_type == BackgroundType::Black
|
&& (self.stage.data.background_type == BackgroundType::Black
|
||||||
|| self.stage.data.background.name() == "bkBlack") {
|
|| self.stage.data.background.name() == "bkBlack") {
|
||||||
self.draw_light_map(state, ctx)?;
|
self.draw_light_map(state, ctx)?;
|
||||||
}*/
|
}
|
||||||
|
|
||||||
/*graphics::set_canvas(ctx, None);
|
/*graphics::set_canvas(ctx, None);
|
||||||
state.game_canvas.draw(ctx, DrawParam::new()
|
state.game_canvas.draw(ctx, DrawParam::new()
|
||||||
|
|
|
||||||
19
src/scripting/doukutsu.d.ts
vendored
19
src/scripting/doukutsu.d.ts
vendored
|
|
@ -14,9 +14,24 @@ declare interface DoukutsuScene {
|
||||||
tick(): number;
|
tick(): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns player at specified index.
|
* Returns a list of players connected to current game.
|
||||||
*/
|
*/
|
||||||
player(index: number): DoukutsuPlayer | null;
|
onlinePlayers(): DoukutsuPlayer[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of players on current map.
|
||||||
|
*/
|
||||||
|
mapPlayers(): DoukutsuPlayer[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the id of local player.
|
||||||
|
*/
|
||||||
|
localPlayerId(): number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns player with specified id.
|
||||||
|
*/
|
||||||
|
player(id: number): DoukutsuPlayer | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
declare namespace doukutsu {
|
declare namespace doukutsu {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ use crate::str;
|
||||||
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
|
||||||
use crate::texture_set::TextureSet;
|
use crate::texture_set::TextureSet;
|
||||||
use crate::framework::{filesystem, graphics};
|
use crate::framework::{filesystem, graphics};
|
||||||
|
use crate::framework::backend::BackendTexture;
|
||||||
|
use crate::framework::graphics::{create_texture, set_render_target, create_texture_mutable};
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||||
pub enum TimingMode {
|
pub enum TimingMode {
|
||||||
|
|
@ -106,6 +108,7 @@ pub struct SharedGameState {
|
||||||
pub screen_size: (f32, f32),
|
pub screen_size: (f32, f32),
|
||||||
pub next_scene: Option<Box<dyn Scene>>,
|
pub next_scene: Option<Box<dyn Scene>>,
|
||||||
pub textscript_vm: TextScriptVM,
|
pub textscript_vm: TextScriptVM,
|
||||||
|
pub lightmap_canvas: Option<Box<dyn BackendTexture>>,
|
||||||
pub season: Season,
|
pub season: Season,
|
||||||
pub constants: EngineConstants,
|
pub constants: EngineConstants,
|
||||||
pub font: BMFontRenderer,
|
pub font: BMFontRenderer,
|
||||||
|
|
@ -170,6 +173,7 @@ impl SharedGameState {
|
||||||
canvas_size: (320.0, 240.0),
|
canvas_size: (320.0, 240.0),
|
||||||
next_scene: None,
|
next_scene: None,
|
||||||
textscript_vm: TextScriptVM::new(),
|
textscript_vm: TextScriptVM::new(),
|
||||||
|
lightmap_canvas: None,
|
||||||
season,
|
season,
|
||||||
constants,
|
constants,
|
||||||
font,
|
font,
|
||||||
|
|
@ -279,6 +283,12 @@ impl SharedGameState {
|
||||||
self.scale = self.screen_size.1.div(230.0).floor().max(1.0);
|
self.scale = self.screen_size.1.div(230.0).floor().max(1.0);
|
||||||
self.canvas_size = (self.screen_size.0 / self.scale, self.screen_size.1 / self.scale);
|
self.canvas_size = (self.screen_size.0 / self.scale, self.screen_size.1 / self.scale);
|
||||||
|
|
||||||
|
let (width, height) = (self.screen_size.0 as u16, self.screen_size.1 as u16);
|
||||||
|
|
||||||
|
// ensure no texture is bound before destroying them.
|
||||||
|
set_render_target(ctx, None)?;
|
||||||
|
self.lightmap_canvas = Some(create_texture_mutable(ctx, width, height)?);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,8 @@ impl SizedBatch {
|
||||||
|
|
||||||
pub fn add(&mut self, mut x: f32, mut y: f32) {
|
pub fn add(&mut self, mut x: f32, mut y: f32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
x = (x * G_MAG).floor() / G_MAG;
|
x = (x * G_MAG).round() / G_MAG;
|
||||||
y = (y * G_MAG).floor() / G_MAG;
|
y = (y * G_MAG).round() / G_MAG;
|
||||||
}
|
}
|
||||||
let mag = unsafe { I_MAG };
|
let mag = unsafe { I_MAG };
|
||||||
|
|
||||||
|
|
@ -105,23 +105,23 @@ impl SizedBatch {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
x = (x * G_MAG).floor() / G_MAG;
|
x = (x * G_MAG).round() / G_MAG;
|
||||||
y = (y * G_MAG).floor() / G_MAG;
|
y = (y * G_MAG).round() / G_MAG;
|
||||||
}
|
}
|
||||||
let mag = unsafe { I_MAG };
|
let mag = unsafe { I_MAG };
|
||||||
|
|
||||||
self.batch.add(SpriteBatchCommand::DrawRect(
|
self.batch.add(SpriteBatchCommand::DrawRect(
|
||||||
Rect {
|
Rect {
|
||||||
left: rect.left as f32 / scale_x,
|
left: rect.left as f32,
|
||||||
top: rect.top as f32 / scale_y,
|
top: rect.top as f32,
|
||||||
right: rect.right as f32 / scale_x,
|
right: rect.right as f32,
|
||||||
bottom: rect.bottom as f32 / scale_y,
|
bottom: rect.bottom as f32,
|
||||||
},
|
},
|
||||||
Rect {
|
Rect {
|
||||||
left: x * mag,
|
left: x * mag * scale_x,
|
||||||
top: y * mag,
|
top: y * mag * scale_y,
|
||||||
right: (x + rect.width() as f32) * mag,
|
right: (x + rect.width() as f32) * mag * scale_x,
|
||||||
bottom: (y + rect.height() as f32) * mag,
|
bottom: (y + rect.height() as f32) * mag * scale_y,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
@ -139,16 +139,16 @@ impl SizedBatch {
|
||||||
|
|
||||||
self.batch.add(SpriteBatchCommand::DrawRectTinted(
|
self.batch.add(SpriteBatchCommand::DrawRectTinted(
|
||||||
Rect {
|
Rect {
|
||||||
left: rect.left as f32 / scale_x,
|
left: rect.left as f32,
|
||||||
top: rect.top as f32 / scale_y,
|
top: rect.top as f32,
|
||||||
right: rect.right as f32 / scale_x,
|
right: rect.right as f32,
|
||||||
bottom: rect.bottom as f32 / scale_y,
|
bottom: rect.bottom as f32,
|
||||||
},
|
},
|
||||||
Rect {
|
Rect {
|
||||||
left: x * mag,
|
left: x * mag,
|
||||||
top: y * mag,
|
top: y * mag,
|
||||||
right: (x + rect.width() as f32) * mag,
|
right: (x + rect.width() as f32 * scale_x) * mag,
|
||||||
bottom: (y + rect.height() as f32) * mag,
|
bottom: (y + rect.height() as f32 * scale_y) * mag,
|
||||||
},
|
},
|
||||||
color.into(),
|
color.into(),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue