1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-03-23 10:29:18 +00:00

fix a bunch of warnings, bugs and compilation

This commit is contained in:
Alula 2021-02-10 12:53:49 +01:00
parent 318d94d843
commit a8a9c6316d
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
23 changed files with 548 additions and 232 deletions

View file

@ -41,7 +41,7 @@ opt-level = 1
[features]
default = ["scripting", "backend-sdl"]
backend-sdl = ["sdl2", "sdl2-sys", "imgui-sdl2"]
backend-sdl = ["sdl2"]
backend-gfx = ["winit", "imgui-gfx-renderer", "imgui-winit-support"]
scripting = ["lua-ffi"]
editor = []
@ -53,10 +53,9 @@ case_insensitive_hashmap = "1.0.0"
chrono = "0.4"
cpal = { git = "https://github.com/doukutsu-rs/cpal.git", branch = "android-support" }
directories = "3"
imgui = "0.6.0"
imgui-gfx-renderer = { version = "0.6.0", optional = true }
imgui-winit-support = { version = "0.6.0", default-features = false, features = ["winit-23"], optional = true }
imgui-sdl2 = { version = "0.13.0", optional = true }
imgui = "0.7.0"
imgui-gfx-renderer = { version = "0.7.0", optional = true }
imgui-winit-support = { version = "0.7.0", default-features = false, features = ["winit-23"], optional = true }
image = { version = "0.22", default-features = false, features = ["png_codec", "pnm", "bmp"] }
itertools = "0.9.0"
lazy_static = "1.4.0"
@ -67,8 +66,7 @@ num-derive = "0.3.2"
num-traits = "0.2.12"
paste = "1.0.0"
pretty_env_logger = "0.4.0"
sdl2 = { version = "0.34.3", optional = true, features = ["unsafe_textures", "bundled", "gfx"] }
sdl2-sys = { version = "0.34", optional = true, features = ["bundled", "gfx"] }
sdl2 = { version = "0.34", optional = true, features = ["unsafe_textures", "bundled", "gfx", "static-link"] }
serde = { version = "1", features = ["derive"] }
serde_derive = "1"
serde_yaml = "0.8"

View file

@ -388,22 +388,6 @@ pub struct Color {
pub a: f32,
}
/// White
pub const WHITE: Color = Color {
r: 1.0,
g: 1.0,
b: 1.0,
a: 1.0,
};
/// Black
pub const BLACK: Color = Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
};
impl Color {
/// Create a new `Color` from four `f32`'s in the range `[0.0-1.0]`
pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {

View file

@ -52,5 +52,6 @@ pub fn init_backend() -> GameResult<Box<dyn Backend>> {
pub enum SpriteBatchCommand {
DrawRect(Rect<f32>, Rect<f32>),
DrawRectFlip(Rect<f32>, Rect<f32>, bool, bool),
DrawRectTinted(Rect<f32>, Rect<f32>, Color),
}

View file

@ -3,22 +3,23 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use imgui::{DrawCmd, DrawData, ImString, TextureId, Ui};
use imgui::internal::RawWrapper;
use sdl2::{EventPump, keyboard, pixels, Sdl};
use imgui::{ConfigFlags, DrawCmd, DrawData, ImString, Key, MouseCursor, TextureId, Ui};
use sdl2::event::{Event, WindowEvent};
use sdl2::gfx::primitives::DrawRenderer;
use sdl2::keyboard::Scancode;
use sdl2::mouse::{Cursor, SystemCursor};
use sdl2::pixels::PixelFormatEnum;
use sdl2::render::{Texture, TextureCreator, WindowCanvas};
use sdl2::surface::Surface;
use sdl2::video::WindowContext;
use sdl2::{keyboard, pixels, EventPump, Sdl};
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::error::{GameError, GameResult};
use crate::framework::graphics::{BlendMode, imgui_context};
use crate::framework::graphics::{imgui_context, BlendMode};
use crate::framework::keyboard::ScanCode;
use crate::framework::ui::init_imgui;
use crate::Game;
@ -31,9 +32,7 @@ impl SDL2Backend {
pub fn new() -> GameResult<Box<dyn Backend>> {
let context = sdl2::init().map_err(|e| GameError::WindowError(e))?;
let backend = SDL2Backend {
context,
};
let backend = SDL2Backend { context };
Ok(Box::new(backend))
}
@ -62,13 +61,15 @@ impl SDL2EventLoop {
let event_pump = sdl.event_pump().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)
.position_centered()
.resizable()
.build()
.map_err(|e| GameError::WindowError(e.to_string()))?;
let canvas = window.into_canvas()
let canvas = window
.into_canvas()
.accelerated()
.present_vsync()
.build()
@ -96,7 +97,10 @@ impl BackendEventLoop for SDL2EventLoop {
let (imgui, imgui_sdl2) = unsafe {
let renderer: &Box<SDL2Renderer> = std::mem::transmute(ctx.renderer.as_ref().unwrap());
(&mut *renderer.imgui.as_ptr(), &mut *renderer.imgui_event.as_ptr())
(
&mut *renderer.imgui.as_ptr(),
&mut *renderer.imgui_event.as_ptr(),
)
};
{
@ -115,27 +119,30 @@ impl BackendEventLoop for SDL2EventLoop {
Event::Quit { .. } => {
state.shutdown();
}
Event::Window { win_event, .. } => {
match win_event {
WindowEvent::Shown => {}
WindowEvent::Hidden => {}
WindowEvent::SizeChanged(width, height) => {
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32);
Event::Window { win_event, .. } => match win_event {
WindowEvent::Shown => {}
WindowEvent::Hidden => {}
WindowEvent::SizeChanged(width, height) => {
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32);
if let Some(renderer) = ctx.renderer.as_ref() {
if let Ok(imgui) = renderer.imgui() {
imgui.io_mut().display_size = [ctx.screen_size.0, ctx.screen_size.1];
}
if let Some(renderer) = ctx.renderer.as_ref() {
if let Ok(imgui) = renderer.imgui() {
imgui.io_mut().display_size =
[ctx.screen_size.0, ctx.screen_size.1];
}
state.handle_resize(ctx);
}
_ => {}
state.handle_resize(ctx);
}
}
Event::KeyDown { scancode, repeat, .. } => {
_ => {}
},
Event::KeyDown {
scancode, repeat, ..
} => {
if let Some(scancode) = scancode {
if let Some(drs_scan) = conv_scancode(scancode) {
game.key_down_event(drs_scan, repeat);
if !repeat {
state.process_debug_keys(drs_scan);
}
ctx.keyboard_context.set_key(drs_scan, true);
}
}
@ -167,7 +174,11 @@ impl BackendEventLoop for SDL2EventLoop {
state.frame_time = 0.0;
}
imgui_sdl2.prepare_frame(imgui.io_mut(), self.refs.borrow().canvas.window(), &self.event_pump.mouse_state());
imgui_sdl2.prepare_frame(
imgui.io_mut(),
self.refs.borrow().canvas.window(),
&self.event_pump.mouse_state(),
);
game.draw(ctx).unwrap();
}
}
@ -180,7 +191,7 @@ impl BackendEventLoop for SDL2EventLoop {
struct SDL2Renderer {
refs: Rc<RefCell<SDL2Context>>,
imgui: Rc<RefCell<imgui::Context>>,
imgui_event: Rc<RefCell<imgui_sdl2::ImguiSdl2>>,
imgui_event: Rc<RefCell<ImguiSdl2>>,
imgui_textures: HashMap<TextureId, SDL2Texture>,
}
@ -192,42 +203,49 @@ impl SDL2Renderer {
imgui.set_renderer_name(ImString::new("SDL2Renderer"));
{
let mut refs = refs.clone();
let refs = refs.clone();
let mut fonts = imgui.fonts();
let id = fonts.tex_id;
let font_tex = fonts.build_rgba32_texture();
let mut texture = refs.borrow_mut().texture_creator
let mut texture = refs
.borrow_mut()
.texture_creator
.create_texture_streaming(PixelFormatEnum::RGBA32, font_tex.width, font_tex.height)
.map_err(|e| GameError::RenderError(e.to_string()))?;
texture.set_blend_mode(sdl2::render::BlendMode::Blend);
texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
for y in 0..(font_tex.height as usize) {
for x in 0..(font_tex.width as usize) {
let offset = y * pitch + x * 4;
let data_offset = (y * font_tex.width as usize + x) * 4;
texture
.with_lock(None, |buffer: &mut [u8], pitch: usize| {
for y in 0..(font_tex.height as usize) {
for x in 0..(font_tex.width as usize) {
let offset = y * pitch + x * 4;
let data_offset = (y * font_tex.width as usize + x) * 4;
buffer[offset] = font_tex.data[data_offset];
buffer[offset + 1] = font_tex.data[data_offset + 1];
buffer[offset + 2] = font_tex.data[data_offset + 2];
buffer[offset + 3] = font_tex.data[data_offset + 3];
buffer[offset] = font_tex.data[data_offset];
buffer[offset + 1] = font_tex.data[data_offset + 1];
buffer[offset + 2] = font_tex.data[data_offset + 2];
buffer[offset + 3] = font_tex.data[data_offset + 3];
}
}
}
}).map_err(|e| GameError::RenderError(e.to_string()))?;
})
.map_err(|e| GameError::RenderError(e.to_string()))?;
imgui_textures.insert(id, SDL2Texture {
refs: refs.clone(),
texture: Some(texture),
width: font_tex.width as u16,
height: font_tex.height as u16,
commands: vec![],
});
imgui_textures.insert(
id,
SDL2Texture {
refs: refs.clone(),
texture: Some(texture),
width: font_tex.width as u16,
height: font_tex.height as u16,
commands: vec![],
},
);
}
let imgui_sdl2 = unsafe {
let refs = &mut *refs.as_ptr();
imgui_sdl2::ImguiSdl2::new(&mut imgui, refs.canvas.window())
ImguiSdl2::new(&mut imgui, refs.canvas.window())
};
Ok(Box::new(SDL2Renderer {
@ -244,7 +262,10 @@ fn to_sdl(color: Color) -> pixels::Color {
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 {
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 {
@ -253,11 +274,23 @@ unsafe fn set_raw_target(renderer: *mut sdl2::sys::SDL_Renderer, raw_texture: *m
}
fn min3(x: f32, y: f32, z: f32) -> f32 {
if x < y && x < z { x } else if y < z { y } else { z }
if x < y && x < z {
x
} else if y < z {
y
} else {
z
}
}
fn max3(x: f32, y: f32, z: f32) -> f32 {
if x > y && x > z { x } else if y > z { y } else { z }
if x > y && x > z {
x
} else if y > z {
y
} else {
z
}
}
impl BackendRenderer for SDL2Renderer {
@ -276,10 +309,15 @@ impl BackendRenderer for SDL2Renderer {
Ok(())
}
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
let mut refs = self.refs.borrow_mut();
fn create_texture_mutable(
&mut self,
width: u16,
height: u16,
) -> GameResult<Box<dyn BackendTexture>> {
let refs = self.refs.borrow_mut();
let mut texture = refs.texture_creator
let texture = refs
.texture_creator
.create_texture_target(PixelFormatEnum::RGBA32, width as u32, height as u32)
.map_err(|e| GameError::RenderError(e.to_string()))?;
@ -292,27 +330,35 @@ impl BackendRenderer for SDL2Renderer {
}))
}
fn create_texture(&mut self, width: u16, height: u16, data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
let mut refs = self.refs.borrow_mut();
fn create_texture(
&mut self,
width: u16,
height: u16,
data: &[u8],
) -> GameResult<Box<dyn BackendTexture>> {
let refs = self.refs.borrow_mut();
let mut texture = refs.texture_creator
let mut texture = refs
.texture_creator
.create_texture_streaming(PixelFormatEnum::RGBA32, width as u32, height as u32)
.map_err(|e| GameError::RenderError(e.to_string()))?;
texture.set_blend_mode(sdl2::render::BlendMode::Blend);
texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
for y in 0..(height as usize) {
for x in 0..(width as usize) {
let offset = y * pitch + x * 4;
let data_offset = (y * width as usize + x) * 4;
texture
.with_lock(None, |buffer: &mut [u8], pitch: usize| {
for y in 0..(height as usize) {
for x in 0..(width as usize) {
let offset = y * pitch + x * 4;
let data_offset = (y * width as usize + x) * 4;
buffer[offset] = data[data_offset];
buffer[offset + 1] = data[data_offset + 1];
buffer[offset + 2] = data[data_offset + 2];
buffer[offset + 3] = data[data_offset + 3];
buffer[offset] = data[data_offset];
buffer[offset + 1] = data[data_offset + 1];
buffer[offset + 2] = data[data_offset + 2];
buffer[offset + 3] = data[data_offset + 3];
}
}
}
}).map_err(|e| GameError::RenderError(e.to_string()))?;
})
.map_err(|e| GameError::RenderError(e.to_string()))?;
Ok(Box::new(SDL2Texture {
refs: self.refs.clone(),
@ -344,23 +390,21 @@ impl BackendRenderer for SDL2Renderer {
let sdl2_texture: &Box<SDL2Texture> = std::mem::transmute(texture);
if let Some(target) = sdl2_texture.texture.as_ref() {
set_raw_target(renderer, target.raw());
set_raw_target(renderer, target.raw())?;
} else {
set_raw_target(renderer, std::ptr::null_mut());
set_raw_target(renderer, std::ptr::null_mut())?;
}
}
},
None => unsafe {
set_raw_target(renderer, std::ptr::null_mut());
}
set_raw_target(renderer, std::ptr::null_mut())?;
},
}
Ok(())
}
fn imgui(&self) -> GameResult<&mut imgui::Context> {
unsafe {
Ok(&mut *self.imgui.as_ptr())
}
unsafe { Ok(&mut *self.imgui.as_ptr()) }
}
fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult {
@ -391,9 +435,12 @@ impl BackendRenderer for SDL2Renderer {
continue;
}
let v1 = draw_list.vtx_buffer()[cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i] as usize];
let v2 = draw_list.vtx_buffer()[cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 1] as usize];
let v3 = draw_list.vtx_buffer()[cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 2] as usize];
let v1 = draw_list.vtx_buffer()[cmd_params.vtx_offset
+ idx_buffer[cmd_params.idx_offset + i] as usize];
let v2 = draw_list.vtx_buffer()[cmd_params.vtx_offset
+ idx_buffer[cmd_params.idx_offset + i + 1] as usize];
let v3 = draw_list.vtx_buffer()[cmd_params.vtx_offset
+ idx_buffer[cmd_params.idx_offset + i + 2] as usize];
vert_x[0] = (v1.pos[0] - 0.5) as i16;
vert_y[0] = (v1.pos[1] - 0.5) as i16;
@ -404,27 +451,30 @@ impl BackendRenderer for SDL2Renderer {
#[allow(clippy::float_cmp)]
if i < count - 3 {
let v4 = draw_list.vtx_buffer()[cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 3] as usize];
let v5 = draw_list.vtx_buffer()[cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 4] as usize];
let v6 = draw_list.vtx_buffer()[cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 5] as usize];
let v4 = draw_list.vtx_buffer()[cmd_params.vtx_offset
+ idx_buffer[cmd_params.idx_offset + i + 3] as usize];
let v5 = draw_list.vtx_buffer()[cmd_params.vtx_offset
+ idx_buffer[cmd_params.idx_offset + i + 4] as usize];
let v6 = draw_list.vtx_buffer()[cmd_params.vtx_offset
+ idx_buffer[cmd_params.idx_offset + i + 5] as usize];
min[0] = min3(v1.pos[0], v2.pos[0], v3.pos[0]);
min[1] = min3(v1.pos[1], v2.pos[1], v3.pos[1]);
max[0] = max3(v1.pos[0], v2.pos[0], v3.pos[0]);
max[1] = max3(v1.pos[1], v2.pos[1], v3.pos[1]);
is_rect = (v1.pos[0] == min[0] || v1.pos[0] == max[0]) &&
(v1.pos[1] == min[1] || v1.pos[1] == max[1]) &&
(v2.pos[0] == min[0] || v2.pos[0] == max[0]) &&
(v2.pos[1] == min[1] || v2.pos[1] == max[1]) &&
(v3.pos[0] == min[0] || v3.pos[0] == max[0]) &&
(v3.pos[1] == min[1] || v3.pos[1] == max[1]) &&
(v4.pos[0] == min[0] || v4.pos[0] == max[0]) &&
(v4.pos[1] == min[1] || v4.pos[1] == max[1]) &&
(v5.pos[0] == min[0] || v5.pos[0] == max[0]) &&
(v5.pos[1] == min[1] || v5.pos[1] == max[1]) &&
(v6.pos[0] == min[0] || v6.pos[0] == max[0]) &&
(v6.pos[1] == min[1] || v6.pos[1] == max[1]);
is_rect = (v1.pos[0] == min[0] || v1.pos[0] == max[0])
&& (v1.pos[1] == min[1] || v1.pos[1] == max[1])
&& (v2.pos[0] == min[0] || v2.pos[0] == max[0])
&& (v2.pos[1] == min[1] || v2.pos[1] == max[1])
&& (v3.pos[0] == min[0] || v3.pos[0] == max[0])
&& (v3.pos[1] == min[1] || v3.pos[1] == max[1])
&& (v4.pos[0] == min[0] || v4.pos[0] == max[0])
&& (v4.pos[1] == min[1] || v4.pos[1] == max[1])
&& (v5.pos[0] == min[0] || v5.pos[0] == max[0])
&& (v5.pos[1] == min[1] || v5.pos[1] == max[1])
&& (v6.pos[0] == min[0] || v6.pos[0] == max[0])
&& (v6.pos[1] == min[1] || v6.pos[1] == max[1]);
if is_rect {
tex_pos[0] = min3(v1.uv[0], v2.uv[0], v3.uv[0]);
@ -434,35 +484,40 @@ impl BackendRenderer for SDL2Renderer {
}
}
if let Some(surf) = self.imgui_textures.get_mut(&cmd_params.texture_id) {
unsafe {
if is_rect {
let src = sdl2::rect::Rect::new((tex_pos[0] * surf.width as f32) as i32,
(tex_pos[1] * surf.height as f32) as i32,
((tex_pos[2] - tex_pos[0]) * surf.width as f32) as u32,
((tex_pos[3] - tex_pos[1]) * surf.height as f32) as u32);
let dest = sdl2::rect::Rect::new(min[0] as i32,
min[1] as i32,
(max[0] - min[0]) as u32,
(max[1] - min[1]) as u32);
if let Some(surf) = self.imgui_textures.get_mut(&cmd_params.texture_id)
{
if is_rect {
let src = sdl2::rect::Rect::new(
(tex_pos[0] * surf.width as f32) as i32,
(tex_pos[1] * surf.height as f32) as i32,
((tex_pos[2] - tex_pos[0]) * surf.width as f32) as u32,
((tex_pos[3] - tex_pos[1]) * surf.height as f32) as u32,
);
let dest = sdl2::rect::Rect::new(
min[0] as i32,
min[1] as i32,
(max[0] - min[0]) as u32,
(max[1] - min[1]) as u32,
);
let tex = surf.texture.as_mut().unwrap();
tex.set_color_mod(v1.col[0], v1.col[1], v1.col[2]);
tex.set_alpha_mod(v1.col[3]);
let tex = surf.texture.as_mut().unwrap();
tex.set_color_mod(v1.col[0], v1.col[1], v1.col[2]);
tex.set_alpha_mod(v1.col[3]);
refs.canvas.copy(tex, src, dest);
} else {
sdl2::sys::gfx::primitives::filledPolygonRGBA(
refs.canvas.raw(),
vert_x.as_ptr(),
vert_y.as_ptr(),
3,
v1.col[0],
v1.col[1],
v1.col[2],
v1.col[3],
);
}
refs.canvas
.copy(tex, src, dest)
.map_err(|e| GameError::RenderError(e.to_string()))?;
} else {
/*sdl2::sys::gfx::primitives::filledPolygonRGBA(
refs.canvas.raw(),
vert_x.as_ptr(),
vert_y.as_ptr(),
3,
v1.col[0],
v1.col[1],
v1.col[2],
v1.col[3],
);*/
}
}
}
@ -472,7 +527,7 @@ impl BackendRenderer for SDL2Renderer {
DrawCmd::ResetRenderState => {}
DrawCmd::RawCallback { callback, raw_cmd } => unsafe {
callback(draw_list.raw(), raw_cmd)
}
},
}
}
}
@ -480,7 +535,7 @@ impl BackendRenderer for SDL2Renderer {
Ok(())
}
fn prepare_frame<'ui>(&self, ui: &Ui<'ui>) -> GameResult {
fn prepare_frame<'ui>(&self, _ui: &Ui<'ui>) -> GameResult {
Ok(())
}
}
@ -520,9 +575,22 @@ impl BackendTexture for SDL2Texture {
texture.set_alpha_mod(255);
texture.set_blend_mode(refs.blend_mode);
refs.canvas.copy(texture,
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.round() as i32, dest.top.round() as i32, dest.width().round() as u32, dest.height().round() as u32)))
refs.canvas
.copy(
texture,
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.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()))?;
}
SpriteBatchCommand::DrawRectTinted(src, dest, color) => {
@ -531,9 +599,49 @@ impl BackendTexture for SDL2Texture {
texture.set_alpha_mod(a);
texture.set_blend_mode(refs.blend_mode);
refs.canvas.copy(texture,
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.round() as i32, dest.top.round() as i32, dest.width().round() as u32, dest.height().round() as u32)))
refs.canvas
.copy(
texture,
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.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()))?;
}
SpriteBatchCommand::DrawRectFlip(src, dest, flip_x, flip_y) => {
texture.set_color_mod(255, 255, 255);
texture.set_alpha_mod(255);
texture.set_blend_mode(refs.blend_mode);
refs.canvas
.copy_ex(
texture,
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.round() as i32,
dest.top.round() as i32,
dest.width().round() as u32,
dest.height().round() as u32,
)),
0.0,
None,
*flip_x,
*flip_y,
)
.map_err(|e| GameError::RenderError(e.to_string()))?;
}
}
@ -551,7 +659,9 @@ impl Drop for SDL2Texture {
mem::swap(&mut self.texture, &mut texture_opt);
if let Some(texture) = texture_opt {
unsafe { texture.destroy(); }
unsafe {
texture.destroy();
}
}
}
}
@ -699,3 +809,219 @@ fn conv_scancode(code: keyboard::Scancode) -> Option<ScanCode> {
_ => None,
}
}
// based on imgui-sdl2 crate
pub struct ImguiSdl2 {
mouse_press: [bool; 5],
ignore_mouse: bool,
ignore_keyboard: bool,
cursor: Option<MouseCursor>,
sdl_cursor: Option<Cursor>,
}
struct Sdl2ClipboardBackend(sdl2::clipboard::ClipboardUtil);
impl imgui::ClipboardBackend for Sdl2ClipboardBackend {
fn get(&mut self) -> Option<imgui::ImString> {
if !self.0.has_clipboard_text() {
return None;
}
self.0.clipboard_text().ok().map(imgui::ImString::new)
}
fn set(&mut self, value: &imgui::ImStr) {
let _ = self.0.set_clipboard_text(value.to_str());
}
}
impl ImguiSdl2 {
pub fn new(imgui: &mut imgui::Context, window: &sdl2::video::Window) -> Self {
let clipboard_util = window.subsystem().clipboard();
imgui.set_clipboard_backend(Box::new(Sdl2ClipboardBackend(clipboard_util)));
imgui.io_mut().key_map[Key::Tab as usize] = Scancode::Tab as u32;
imgui.io_mut().key_map[Key::LeftArrow as usize] = Scancode::Left as u32;
imgui.io_mut().key_map[Key::RightArrow as usize] = Scancode::Right as u32;
imgui.io_mut().key_map[Key::UpArrow as usize] = Scancode::Up as u32;
imgui.io_mut().key_map[Key::DownArrow as usize] = Scancode::Down as u32;
imgui.io_mut().key_map[Key::PageUp as usize] = Scancode::PageUp as u32;
imgui.io_mut().key_map[Key::PageDown as usize] = Scancode::PageDown as u32;
imgui.io_mut().key_map[Key::Home as usize] = Scancode::Home as u32;
imgui.io_mut().key_map[Key::End as usize] = Scancode::End as u32;
imgui.io_mut().key_map[Key::Delete as usize] = Scancode::Delete as u32;
imgui.io_mut().key_map[Key::Backspace as usize] = Scancode::Backspace as u32;
imgui.io_mut().key_map[Key::Enter as usize] = Scancode::Return as u32;
imgui.io_mut().key_map[Key::Escape as usize] = Scancode::Escape as u32;
imgui.io_mut().key_map[Key::Space as usize] = Scancode::Space as u32;
imgui.io_mut().key_map[Key::A as usize] = Scancode::A as u32;
imgui.io_mut().key_map[Key::C as usize] = Scancode::C as u32;
imgui.io_mut().key_map[Key::V as usize] = Scancode::V as u32;
imgui.io_mut().key_map[Key::X as usize] = Scancode::X as u32;
imgui.io_mut().key_map[Key::Y as usize] = Scancode::Y as u32;
imgui.io_mut().key_map[Key::Z as usize] = Scancode::Z as u32;
Self {
mouse_press: [false; 5],
ignore_keyboard: false,
ignore_mouse: false,
cursor: None,
sdl_cursor: None,
}
}
pub fn ignore_event(&self, event: &Event) -> bool {
match *event {
Event::KeyDown { .. }
| Event::KeyUp { .. }
| Event::TextEditing { .. }
| Event::TextInput { .. } => self.ignore_keyboard,
Event::MouseMotion { .. }
| Event::MouseButtonDown { .. }
| Event::MouseButtonUp { .. }
| Event::MouseWheel { .. }
| Event::FingerDown { .. }
| Event::FingerUp { .. }
| Event::FingerMotion { .. }
| Event::DollarGesture { .. }
| Event::DollarRecord { .. }
| Event::MultiGesture { .. } => self.ignore_mouse,
_ => false,
}
}
pub fn handle_event(&mut self, imgui: &mut imgui::Context, event: &Event) {
use sdl2::keyboard;
use sdl2::mouse::MouseButton;
fn set_mod(imgui: &mut imgui::Context, keymod: keyboard::Mod) {
let ctrl = keymod.intersects(keyboard::Mod::RCTRLMOD | keyboard::Mod::LCTRLMOD);
let alt = keymod.intersects(keyboard::Mod::RALTMOD | keyboard::Mod::LALTMOD);
let shift = keymod.intersects(keyboard::Mod::RSHIFTMOD | keyboard::Mod::LSHIFTMOD);
let super_ = keymod.intersects(keyboard::Mod::RGUIMOD | keyboard::Mod::LGUIMOD);
imgui.io_mut().key_ctrl = ctrl;
imgui.io_mut().key_alt = alt;
imgui.io_mut().key_shift = shift;
imgui.io_mut().key_super = super_;
}
match *event {
Event::MouseWheel { y, .. } => {
imgui.io_mut().mouse_wheel = y as f32;
}
Event::MouseButtonDown { mouse_btn, .. } => {
if mouse_btn != MouseButton::Unknown {
let index = match mouse_btn {
MouseButton::Left => 0,
MouseButton::Right => 1,
MouseButton::Middle => 2,
MouseButton::X1 => 3,
MouseButton::X2 => 4,
MouseButton::Unknown => unreachable!(),
};
self.mouse_press[index] = true;
}
}
Event::TextInput { ref text, .. } => {
for chr in text.chars() {
imgui.io_mut().add_input_character(chr);
}
}
Event::KeyDown {
scancode, keymod, ..
} => {
set_mod(imgui, keymod);
if let Some(scancode) = scancode {
imgui.io_mut().keys_down[scancode as usize] = true;
}
}
Event::KeyUp {
scancode, keymod, ..
} => {
set_mod(imgui, keymod);
if let Some(scancode) = scancode {
imgui.io_mut().keys_down[scancode as usize] = false;
}
}
_ => {}
}
}
pub fn prepare_frame(
&mut self,
io: &mut imgui::Io,
window: &sdl2::video::Window,
mouse_state: &sdl2::mouse::MouseState,
) {
let mouse_util = window.subsystem().sdl().mouse();
let (win_w, win_h) = window.size();
let (draw_w, draw_h) = window.drawable_size();
io.display_size = [win_w as f32, win_h as f32];
io.display_framebuffer_scale = [
(draw_w as f32) / (win_w as f32),
(draw_h as f32) / (win_h as f32),
];
// Merging the mousedown events we received into the current state prevents us from missing
// clicks that happen faster than a frame
io.mouse_down = [
self.mouse_press[0] || mouse_state.left(),
self.mouse_press[1] || mouse_state.right(),
self.mouse_press[2] || mouse_state.middle(),
self.mouse_press[3] || mouse_state.x1(),
self.mouse_press[4] || mouse_state.x2(),
];
self.mouse_press = [false; 5];
let any_mouse_down = io.mouse_down.iter().any(|&b| b);
mouse_util.capture(any_mouse_down);
io.mouse_pos = [mouse_state.x() as f32, mouse_state.y() as f32];
self.ignore_keyboard = io.want_capture_keyboard;
self.ignore_mouse = io.want_capture_mouse;
}
pub fn prepare_render(&mut self, ui: &imgui::Ui, window: &sdl2::video::Window) {
let io = ui.io();
if !io
.config_flags
.contains(ConfigFlags::NO_MOUSE_CURSOR_CHANGE)
{
let mouse_util = window.subsystem().sdl().mouse();
match ui.mouse_cursor() {
Some(mouse_cursor) if !io.mouse_draw_cursor => {
mouse_util.show_cursor(true);
let sdl_cursor = match mouse_cursor {
MouseCursor::Arrow => SystemCursor::Arrow,
MouseCursor::TextInput => SystemCursor::IBeam,
MouseCursor::ResizeAll => SystemCursor::SizeAll,
MouseCursor::ResizeNS => SystemCursor::SizeNS,
MouseCursor::ResizeEW => SystemCursor::SizeWE,
MouseCursor::ResizeNESW => SystemCursor::SizeNESW,
MouseCursor::ResizeNWSE => SystemCursor::SizeNWSE,
MouseCursor::Hand => SystemCursor::Hand,
MouseCursor::NotAllowed => SystemCursor::No,
};
if self.cursor != Some(mouse_cursor) {
let sdl_cursor = Cursor::from_system(sdl_cursor).unwrap();
sdl_cursor.set();
self.cursor = Some(mouse_cursor);
self.sdl_cursor = Some(sdl_cursor);
}
}
_ => {
self.cursor = None;
self.sdl_cursor = None;
mouse_util.show_cursor(false);
}
}
}
}
}

View file

@ -1,4 +1,4 @@
use crate::framework::backend::{Backend, init_backend, BackendRenderer};
use crate::framework::backend::{init_backend, BackendRenderer};
use crate::framework::error::GameResult;
use crate::framework::filesystem::Filesystem;
use crate::Game;

View file

@ -71,7 +71,7 @@ impl Filesystem {
// Set up VFS to merge resource path, root path, and zip path.
let overlay = vfs::OverlayFS::new();
// User data VFS.
let mut user_overlay = vfs::OverlayFS::new();
let user_overlay = vfs::OverlayFS::new();
Filesystem {
vfs: overlay,

View file

@ -138,7 +138,7 @@ impl Game {
let state_ref = unsafe { &mut *self.state.get() };
if state_ref.timing_mode != TimingMode::FrameSynchronized {
let mut elapsed = self.start_time.elapsed().as_nanos();
let elapsed = self.start_time.elapsed().as_nanos();
#[cfg(target_os = "windows")]
{
// Even with the non-monotonic Instant mitigation at the start of the event loop, there's still a chance of it not working.
@ -177,31 +177,6 @@ impl Game {
graphics::present(ctx)?;
Ok(())
}
fn key_down_event(&mut self, key_code: ScanCode, repeat: bool) {
if repeat { return; }
let state = unsafe { &mut *self.state.get() };
match key_code {
ScanCode::F5 => { state.settings.subpixel_coords = !state.settings.subpixel_coords }
ScanCode::F6 => { state.settings.motion_interpolation = !state.settings.motion_interpolation }
ScanCode::F7 => { state.set_speed(1.0) }
ScanCode::F8 => {
if state.settings.speed > 0.2 {
state.set_speed(state.settings.speed - 0.1);
}
}
ScanCode::F9 => {
if state.settings.speed < 3.0 {
state.set_speed(state.settings.speed + 0.1);
}
}
ScanCode::F10 => { state.settings.debug_outlines = !state.settings.debug_outlines }
ScanCode::F11 => { state.settings.god_mode = !state.settings.god_mode }
ScanCode::F12 => { state.settings.infinite_booster = !state.settings.infinite_booster }
_ => {}
}
}
}
#[cfg(target_os = "android")]
@ -321,28 +296,7 @@ pub fn init() -> GameResult {
}
state_ref.next_scene = Some(Box::new(LoadingScene::new()));
context.run(&mut game);
/* loop {
game.update(&mut context)?;
if state_ref.shutdown {
log::info!("Shutting down...");
break;
}
if state_ref.next_scene.is_some() {
mem::swap(&mut game.scene, &mut state_ref.next_scene);
state_ref.next_scene = None;
game.scene.as_mut().unwrap().init(state_ref, &mut context).unwrap();
game.loops = 0;
state_ref.frame_time = 0.0;
}
std::thread::sleep(std::time::Duration::from_millis(10));
game.draw(&mut context)?;
}*/
context.run(&mut game)?;
Ok(())
}

View file

@ -59,7 +59,7 @@ impl LiveDebugger {
Window::new(im_str!("Debugger"))
.resizable(false)
.collapsed(false, Condition::FirstUseEver)
.collapsed(true, Condition::FirstUseEver)
.position([5.0, 5.0], Condition::FirstUseEver)
.size([400.0, 170.0], Condition::FirstUseEver)
.build(ui, || {

View file

@ -1587,7 +1587,7 @@ impl NPC {
npc.y = self.y - 0x1800;
npc.tsc_direction = 10 * self.anim_num + 40;
npc_list.spawn(0, npc);
let _ = npc_list.spawn(0, npc);
self.cond.set_explode_die(true);
}
}
@ -1630,7 +1630,7 @@ impl NPC {
npc.direction = Direction::Right;
npc.parent_id = self.id;
npc_list.spawn(0x100, npc);
let _ = npc_list.spawn(0x100, npc);
}
}

View file

@ -289,7 +289,7 @@ impl NPC {
}
pub(crate) fn tick_n049_skullhead(&mut self, state: &mut SharedGameState, players: [&mut Player; 2], npc_list: &NPCList) -> GameResult {
let mut parent = self.get_parent_ref_mut(npc_list);
let parent = self.get_parent_ref_mut(npc_list);
if self.action_num > 9 && parent.as_ref().map(|n| n.npc_type == 3).unwrap_or(false) {
self.action_num = 3;

View file

@ -284,6 +284,8 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager)> for NP
216 => self.tick_n216_debug_cat(state),
222 => self.tick_n222_prison_bars(state),
227 => self.tick_n227_bucket(state),
229 => self.tick_n229_red_flowers_sprouts(state),
230 => self.tick_n230_red_flowers_blooming(state),
234 => self.tick_n234_red_flowers_picked(state),
239 => self.tick_n239_cage_bars(state),
241 => self.tick_n241_critter_red(state, players),

View file

@ -73,7 +73,7 @@ impl Xoroshiro32PlusPlus {
pub fn next_u16(&self) -> u16 {
let mut state = self.0.get();
let mut result = (state.0.wrapping_add(state.1)).rotate_left(9).wrapping_add(state.0);
let result = (state.0.wrapping_add(state.1)).rotate_left(9).wrapping_add(state.0);
state.1 ^= state.0;
state.0 = state.0.rotate_left(13) ^ state.1 ^ (state.1 << 5);

View file

@ -434,13 +434,14 @@ impl GameScene {
};
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, tex_name)?;
// switch version uses +1000 face offset to display a flipped version
// switch version uses 1xxx flag to show a flipped version of face
let flip = state.textscript_vm.face > 1000;
// x1xx flag shows a talking animation
let talking = (state.textscript_vm.face % 1000) > 100;
let face_num = state.textscript_vm.face % 100;
let (scale_x, scale_y) = batch.scale();
batch.add_rect_scaled(left_pos + 14.0 + if flip { 48.0 } else { 0.0 }, top_pos + 8.0,
scale_x * if flip { -1.0 } else { 1.0 }, scale_y,
batch.add_rect_flip(left_pos + 14.0, top_pos + 8.0,
flip, false,
&Rect::new_size(
(face_num as u16 % 6) * 48,
(face_num as u16 / 6) * 48,

View file

@ -19,6 +19,7 @@ impl NoDataScene {
}
}
#[cfg(target_os = "android")]
static REL_URL: &str = "https://github.com/doukutsu-rs/game-data/releases";
impl Scene for NoDataScene {

View file

@ -1,14 +1,13 @@
use lua_ffi::ffi::luaL_Reg;
use lua_ffi::{LuaObject, State, c_int};
use crate::scene::game_scene::GameScene;
use crate::scripting::LuaScriptingState;
use crate::shared_game_state::SharedGameState;
pub struct Doukutsu {
pub ptr: *mut LuaScriptingState,
}
#[allow(unused)]
impl Doukutsu {
pub fn new(ptr: *mut LuaScriptingState) -> Doukutsu {
Doukutsu {

View file

@ -1,4 +1,4 @@
use std::io::{Read, Seek};
use std::io::Read;
use std::ptr::null_mut;
@ -6,8 +6,7 @@ use crate::framework::context::Context;
use crate::framework::error::{GameResult, GameError};
use lua_ffi::{c_int, LuaFunction, LuaObject, State, ThreadStatus};
use lua_ffi::ffi::lua_pushcfunction;
use lua_ffi::{c_int, State, ThreadStatus};
use crate::scene::game_scene::GameScene;
use crate::scripting::doukutsu::Doukutsu;
@ -117,7 +116,7 @@ impl LuaScriptingState {
if filesystem::exists(ctx, "/scripts/") {
let mut script_count = 0;
let mut files = filesystem::read_dir(ctx, "/scripts/")?
let files = filesystem::read_dir(ctx, "/scripts/")?
.filter(|f| f.to_string_lossy().to_lowercase().ends_with(".lua"));
for file in files {

View file

@ -12,6 +12,7 @@ pub struct LuaPlayer {
inv_ptr: *mut Inventory,
}
#[allow(unused)]
impl LuaPlayer {
fn check_ref(&self, state: &mut State) -> bool {
if !self.valid_reference {

View file

@ -28,7 +28,8 @@ use crate::text_script::{ScriptMode, TextScriptExecutionState, TextScriptVM};
use crate::texture_set::TextureSet;
use crate::framework::{filesystem, graphics};
use crate::framework::backend::BackendTexture;
use crate::framework::graphics::{create_texture, set_render_target, create_texture_mutable};
use crate::framework::graphics::{set_render_target, create_texture_mutable};
use crate::framework::keyboard::ScanCode;
#[derive(PartialEq, Eq, Copy, Clone)]
pub enum TimingMode {
@ -103,6 +104,7 @@ pub struct SharedGameState {
pub npc_super_pos: (i32, i32),
pub stages: Vec<StageData>,
pub frame_time: f64,
pub debugger: bool,
pub scale: f32,
pub canvas_size: (f32, f32),
pub screen_size: (f32, f32),
@ -117,7 +119,7 @@ pub struct SharedGameState {
pub lua: LuaScriptingState,
pub sound_manager: SoundManager,
pub settings: Settings,
pub shutdown: bool,
pub shutdown: bool
}
impl SharedGameState {
@ -168,6 +170,7 @@ impl SharedGameState {
npc_super_pos: (0, 0),
stages: Vec::with_capacity(96),
frame_time: 0.0,
debugger: false,
scale: 2.0,
screen_size: (640.0, 480.0),
canvas_size: (320.0, 240.0),
@ -186,6 +189,28 @@ impl SharedGameState {
})
}
pub fn process_debug_keys(&mut self, key_code: ScanCode) {
match key_code {
ScanCode::F3 => { self.settings.god_mode = !self.settings.god_mode }
ScanCode::F4 => { self.settings.infinite_booster = !self.settings.infinite_booster }
ScanCode::F5 => { self.settings.subpixel_coords = !self.settings.subpixel_coords }
ScanCode::F6 => { self.settings.motion_interpolation = !self.settings.motion_interpolation }
ScanCode::F7 => { self.set_speed(1.0) }
ScanCode::F8 => {
if self.settings.speed > 0.2 {
self.set_speed(self.settings.speed - 0.1);
}
}
ScanCode::F9 => {
if self.settings.speed < 3.0 {
self.set_speed(self.settings.speed + 0.1);
}
}
ScanCode::F10 => { self.settings.debug_outlines = !self.settings.debug_outlines }
_ => {}
}
}
pub fn reload_textures(&mut self) {
let mut texture_set = TextureSet::new(self.base_path.as_str());
@ -307,10 +332,6 @@ impl SharedGameState {
pub fn set_speed(&mut self, value: f64) {
self.settings.speed = clamp(value, 0.1, 3.0);
self.frame_time = 0.0;
if let Err(err) = self.sound_manager.set_speed(value as f32) {
log::error!("Error while sending a message to sound manager: {}", err);
}
}
pub fn current_tps(&self) -> f64 {

View file

@ -8,7 +8,7 @@ use num_traits::clamp;
use crate::engine_constants::EngineConstants;
use crate::framework::context::Context;
use crate::framework::error::{GameResult, GameError};
use crate::framework::error::{GameResult};
use crate::framework::filesystem;
use crate::sound::organya::Song;
use crate::sound::pixtone::PixTonePlayback;
@ -16,7 +16,6 @@ use crate::sound::playback::{PlaybackEngine, SavedPlaybackState};
use crate::sound::wave_bank::SoundBank;
use crate::str;
use crate::framework::error::GameError::{AudioError, ResourceLoadError, InvalidValue};
use std::io::Error;
mod wave_bank;
mod organya;

View file

@ -166,6 +166,7 @@ impl PlaybackEngine {
self.play_pos = position;
}
#[allow(unused)]
pub fn get_total_samples(&self) -> u32 {
let ticks_intro = self.song.time.loop_range.start;
let ticks_loop = self.song.time.loop_range.end - self.song.time.loop_range.start;

View file

@ -1751,6 +1751,7 @@ impl TextScript {
}
}
#[allow(unused)]
fn read_varint<I: Iterator<Item=u8>>(iter: &mut I) -> GameResult<i32> {
let mut result = 0u32;

View file

@ -6,7 +6,7 @@ use itertools::Itertools;
use log::info;
use crate::common;
use crate::common::{FILE_TYPES, Point, Rect};
use crate::common::{FILE_TYPES, Rect};
use crate::engine_constants::EngineConstants;
use crate::framework::backend::{BackendTexture, SpriteBatchCommand};
use crate::framework::context::Context;
@ -94,12 +94,40 @@ impl SizedBatch {
self.add_rect_scaled(x, y, 1.0, 1.0, rect)
}
pub fn add_rect_flip(&mut self, mut x: f32, mut y: f32, flip_x: bool, flip_y: bool, rect: &common::Rect<u16>) {
if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 {
return;
}
unsafe {
x = (x * G_MAG).round() / G_MAG;
y = (y * G_MAG).round() / G_MAG;
}
let mag = unsafe { I_MAG };
self.batch.add(SpriteBatchCommand::DrawRectFlip(
Rect {
left: rect.left as f32 / self.scale_x,
top: rect.top as f32 / self.scale_y,
right: rect.right as f32 / self.scale_x,
bottom: rect.bottom as f32 / self.scale_y,
},
Rect {
left: x * mag,
top: y * mag,
right: (x + rect.width() as f32) * mag,
bottom: (y + rect.height() as f32) * mag,
},
flip_x, flip_y
));
}
#[inline(always)]
pub fn add_rect_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8, u8), rect: &common::Rect<u16>) {
self.add_rect_scaled_tinted(x, y, color, 1.0, 1.0, rect)
}
pub fn add_rect_scaled(&mut self, mut x: f32, mut y: f32, mut scale_x: f32, mut scale_y: f32, rect: &common::Rect<u16>) {
pub fn add_rect_scaled(&mut self, mut x: f32, mut y: f32, scale_x: f32, scale_y: f32, rect: &common::Rect<u16>) {
if (rect.right - rect.left) == 0 || (rect.bottom - rect.top) == 0 {
return;
}
@ -126,7 +154,7 @@ impl SizedBatch {
));
}
pub fn add_rect_scaled_tinted(&mut self, mut x: f32, mut y: f32, color: (u8, u8, u8, u8), mut scale_x: f32, mut 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;
}

View file

@ -384,7 +384,7 @@ impl Weapon {
fn tick_spur(&mut self, player: &mut Player, player_id: TargetPlayer, inventory: &mut Inventory, bullet_manager: &mut BulletManager, state: &mut SharedGameState) {
let mut shoot = false;
let mut btype = 0;
let mut btype;
if player.controller.shoot() {
inventory.add_xp(if player.equip.has_turbocharge() { 3 } else { 2 }, player, state);