From 318d94d84345071baeef560b24e0912b1e663828 Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Fri, 5 Feb 2021 23:47:13 +0100 Subject: [PATCH] ggez is gone --- .appveyor.yml | 8 +- Cargo.toml | 13 ++- README.md | 6 +- src/framework/backend.rs | 15 ++- src/framework/backend_sdl2.rs | 212 +++++++++++++++++++++++++++++++++- src/framework/graphics.rs | 24 ++++ src/framework/mod.rs | 5 +- src/framework/ui.rs | 136 ++++++++++++++++++++++ src/lib.rs | 3 +- src/live_debugger.rs | 2 +- src/scene/game_scene.rs | 4 +- src/scene/mod.rs | 2 +- src/sound/mod.rs | 21 ++-- src/sound/organya.rs | 135 +++++++++++----------- src/sound/playback.rs | 10 +- src/texture_set.rs | 23 ++-- src/ui.rs | 130 --------------------- src/weapon.rs | 4 +- 18 files changed, 509 insertions(+), 244 deletions(-) create mode 100644 src/framework/ui.rs delete mode 100644 src/ui.rs diff --git a/.appveyor.yml b/.appveyor.yml index 0bb3b58..c30a923 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,10 +25,10 @@ install: - cargo -vV cache: - - '%USERPROFILE%\.cache\sccache -> .appveyor.yml' - - '%USERPROFILE%\.cargo -> .appveyor.yml' - - '%USERPROFILE%\.rustup -> .appveyor.yml' - - 'target -> .appveyor.yml' + - '%USERPROFILE%\.cache\sccache -> Cargo.toml' + - '%USERPROFILE%\.cargo -> Cargo.toml' + - '%USERPROFILE%\.rustup -> Cargo.toml' + - 'target -> Cargo.toml' #test_script: # - cargo build --verbose --all diff --git a/Cargo.toml b/Cargo.toml index b158cdc..67291ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ opt-level = 1 [features] default = ["scripting", "backend-sdl"] -backend-sdl = ["sdl2", "sdl2-sys"] +backend-sdl = ["sdl2", "sdl2-sys", "imgui-sdl2"] backend-gfx = ["winit", "imgui-gfx-renderer", "imgui-winit-support"] scripting = ["lua-ffi"] editor = [] @@ -53,9 +53,10 @@ case_insensitive_hashmap = "1.0.0" chrono = "0.4" cpal = { git = "https://github.com/doukutsu-rs/cpal.git", branch = "android-support" } directories = "3" -imgui = { git = "https://github.com/Gekkio/imgui-rs.git", rev = "7e2293bde67f869750ab0e649fbfbd842fb0c785" } -imgui-gfx-renderer = { git = "https://github.com/Gekkio/imgui-rs.git", rev = "7e2293bde67f869750ab0e649fbfbd842fb0c785", optional = true } -imgui-winit-support = { git = "https://github.com/Gekkio/imgui-rs.git", default-features = false, features = ["winit-23"], rev = "7e2293bde67f869750ab0e649fbfbd842fb0c785", optional = true } +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 } image = { version = "0.22", default-features = false, features = ["png_codec", "pnm", "bmp"] } itertools = "0.9.0" lazy_static = "1.4.0" @@ -66,8 +67,8 @@ 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", "static-link"] } -sdl2-sys = { version = "0.34", optional = true } +sdl2 = { version = "0.34.3", optional = true, features = ["unsafe_textures", "bundled", "gfx"] } +sdl2-sys = { version = "0.34", optional = true, features = ["bundled", "gfx"] } serde = { version = "1", features = ["derive"] } serde_derive = "1" serde_yaml = "0.8" diff --git a/README.md b/README.md index 1318604..59e46f4 100644 --- a/README.md +++ b/README.md @@ -78,10 +78,10 @@ Vanilla Cave Story does not work yet because some important data files have been - [ ] Machine Gun - [ ] Missile Launcher - [ ] Bubbler - - [ ] Blade + - [x] Blade - [ ] Super Missile Launcher - - [ ] Nemesis - - [ ] Spur + - [x] Nemesis + - [x] Spur - [x] Saving and loading game state - [ ] Support for different game editions - [ ] Vanilla diff --git a/src/framework/backend.rs b/src/framework/backend.rs index c224faf..be95261 100644 --- a/src/framework/backend.rs +++ b/src/framework/backend.rs @@ -1,8 +1,10 @@ -use crate::common::{Color, Rect, Point}; +use imgui::DrawData; + +use crate::common::{Color, Point, Rect}; use crate::framework::context::Context; use crate::framework::error::GameResult; -use crate::Game; use crate::framework::graphics::BlendMode; +use crate::Game; pub trait Backend { fn create_event_loop(&self) -> GameResult>; @@ -26,12 +28,21 @@ pub trait BackendRenderer { fn set_blend_mode(&mut self, blend: BlendMode) -> GameResult; fn set_render_target(&mut self, texture: Option<&Box>) -> GameResult; + + fn imgui(&self) -> GameResult<&mut imgui::Context>; + + fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult; + + fn prepare_frame(&self, ui: &imgui::Ui) -> GameResult; } pub trait BackendTexture { fn dimensions(&self) -> (u16, u16); + fn add(&mut self, command: SpriteBatchCommand); + fn clear(&mut self); + fn draw(&mut self) -> GameResult; } diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs index ab954cd..168db77 100644 --- a/src/framework/backend_sdl2.rs +++ b/src/framework/backend_sdl2.rs @@ -1,20 +1,26 @@ use core::mem; 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 sdl2::event::{Event, WindowEvent}; +use sdl2::gfx::primitives::DrawRenderer; use sdl2::keyboard::Scancode; use sdl2::pixels::PixelFormatEnum; use sdl2::render::{Texture, TextureCreator, WindowCanvas}; +use sdl2::surface::Surface; use sdl2::video::WindowContext; use crate::common::Color; 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; +use crate::framework::graphics::{BlendMode, imgui_context}; use crate::framework::keyboard::ScanCode; +use crate::framework::ui::init_imgui; use crate::Game; pub struct SDL2Backend { @@ -87,14 +93,24 @@ impl BackendEventLoop for SDL2EventLoop { fn run(&mut self, game: &mut Game, ctx: &mut Context) { let state = unsafe { &mut *game.state.get() }; + let (imgui, imgui_sdl2) = unsafe { + let renderer: &Box = std::mem::transmute(ctx.renderer.as_ref().unwrap()); + + (&mut *renderer.imgui.as_ptr(), &mut *renderer.imgui_event.as_ptr()) + }; + { let (width, height) = self.refs.borrow().canvas.window().size(); ctx.screen_size = (width.max(1) as f32, height.max(1) as f32); + + imgui.io_mut().display_size = [ctx.screen_size.0, ctx.screen_size.1]; let _ = state.handle_resize(ctx); } loop { for event in self.event_pump.poll_iter() { + imgui_sdl2.handle_event(imgui, &event); + match event { Event::Quit { .. } => { state.shutdown(); @@ -105,6 +121,12 @@ impl BackendEventLoop for SDL2EventLoop { 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]; + } + } state.handle_resize(ctx); } _ => {} @@ -145,6 +167,7 @@ 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()); game.draw(ctx).unwrap(); } } @@ -156,12 +179,62 @@ impl BackendEventLoop for SDL2EventLoop { struct SDL2Renderer { refs: Rc>, + imgui: Rc>, + imgui_event: Rc>, + imgui_textures: HashMap, } impl SDL2Renderer { + #[allow(clippy::new_ret_no_self)] pub fn new(refs: Rc>) -> GameResult> { + let mut imgui = init_imgui()?; + let mut imgui_textures = HashMap::new(); + + imgui.set_renderer_name(ImString::new("SDL2Renderer")); + { + let mut 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 + .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; + + 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()))?; + + 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()) + }; + Ok(Box::new(SDL2Renderer { refs, + imgui: Rc::new(RefCell::new(imgui)), + imgui_event: Rc::new(RefCell::new(imgui_sdl2)), + imgui_textures, })) } } @@ -179,6 +252,14 @@ 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 } +} + +fn max3(x: f32, y: f32, z: f32) -> f32 { + if x > y && x > z { x } else if y > z { y } else { z } +} + impl BackendRenderer for SDL2Renderer { fn clear(&mut self, color: Color) { let mut refs = self.refs.borrow_mut(); @@ -275,8 +356,137 @@ impl BackendRenderer for SDL2Renderer { Ok(()) } + + fn imgui(&self) -> GameResult<&mut imgui::Context> { + unsafe { + Ok(&mut *self.imgui.as_ptr()) + } + } + + fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult { + let mut refs = self.refs.borrow_mut(); + + for draw_list in draw_data.draw_lists() { + for cmd in draw_list.commands() { + match cmd { + DrawCmd::Elements { count, cmd_params } => { + refs.canvas.set_clip_rect(Some(sdl2::rect::Rect::new( + cmd_params.clip_rect[0] as i32, + cmd_params.clip_rect[1] as i32, + (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as u32, + (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as u32, + ))); + + let idx_buffer = draw_list.idx_buffer(); + let mut vert_x = [0i16; 6]; + let mut vert_y = [0i16; 6]; + let mut min = [0f32; 2]; + let mut max = [0f32; 2]; + let mut tex_pos = [0f32; 4]; + let mut is_rect = false; + + for i in (0..count).step_by(3) { + if is_rect { + is_rect = false; + 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]; + + vert_x[0] = (v1.pos[0] - 0.5) as i16; + vert_y[0] = (v1.pos[1] - 0.5) as i16; + vert_x[1] = (v2.pos[0] - 0.5) as i16; + vert_y[1] = (v2.pos[1] - 0.5) as i16; + vert_x[2] = (v3.pos[0] - 0.5) as i16; + vert_y[2] = (v3.pos[1] - 0.5) as i16; + + #[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]; + + 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]); + + if is_rect { + tex_pos[0] = min3(v1.uv[0], v2.uv[0], v3.uv[0]); + tex_pos[1] = min3(v1.uv[1], v2.uv[1], v3.uv[1]); + tex_pos[2] = max3(v1.uv[0], v2.uv[0], v3.uv[0]); + tex_pos[3] = max3(v1.uv[1], v2.uv[1], v3.uv[1]); + } + } + + 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); + + 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.set_clip_rect(None); + } + DrawCmd::ResetRenderState => {} + DrawCmd::RawCallback { callback, raw_cmd } => unsafe { + callback(draw_list.raw(), raw_cmd) + } + } + } + } + + Ok(()) + } + + fn prepare_frame<'ui>(&self, ui: &Ui<'ui>) -> GameResult { + Ok(()) + } } +impl SDL2Renderer {} + struct SDL2Texture { refs: Rc>, texture: Option, diff --git a/src/framework/graphics.rs b/src/framework/graphics.rs index 583c9bd..57f3070 100644 --- a/src/framework/graphics.rs +++ b/src/framework/graphics.rs @@ -75,3 +75,27 @@ pub fn set_blend_mode(ctx: &mut Context, blend: BlendMode) -> GameResult { Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string())) } + +pub fn imgui_context(ctx: &Context) -> GameResult<&mut imgui::Context> { + if let Some(renderer) = ctx.renderer.as_ref() { + return renderer.imgui(); + } + + Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string())) +} + +pub fn render_imgui(ctx: &mut Context, draw_data: &imgui::DrawData) -> GameResult { + if let Some(renderer) = ctx.renderer.as_mut() { + return renderer.render_imgui(draw_data); + } + + Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string())) +} + +pub fn imgui_prepare_frame(ctx: &Context, ui: &imgui::Ui) -> GameResult { + if let Some(renderer) = ctx.renderer.as_ref() { + return renderer.prepare_frame(ui); + } + + Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string())) +} diff --git a/src/framework/mod.rs b/src/framework/mod.rs index af03421..3c0ee4f 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -1,9 +1,10 @@ pub mod backend; pub mod backend_sdl2; +pub mod backend_null; pub mod context; pub mod error; pub mod filesystem; -pub mod vfs; pub mod graphics; pub mod keyboard; -pub mod backend_null; +pub mod ui; +pub mod vfs; diff --git a/src/framework/ui.rs b/src/framework/ui.rs new file mode 100644 index 0000000..09b501e --- /dev/null +++ b/src/framework/ui.rs @@ -0,0 +1,136 @@ +use std::time::Instant; + +use imgui::{FontConfig, FontSource}; +use imgui::sys::*; + +use crate::framework::context::Context; +use crate::framework::error::GameResult; +use crate::framework::graphics::{imgui_context, render_imgui}; +use crate::live_debugger::LiveDebugger; +use crate::scene::Scene; +use crate::shared_game_state::SharedGameState; + +pub struct UI { + pub components: Components, + last_frame: Instant, +} + +pub struct Components { + pub live_debugger: LiveDebugger, +} + +pub fn init_imgui() -> GameResult { + let mut imgui = imgui::Context::create(); + imgui.set_ini_filename(None); + imgui.fonts().add_font(&[ + FontSource::DefaultFontData { + config: Some(FontConfig::default()), + }, + ]); + + imgui.style_mut().window_padding = [4.0, 6.0]; + imgui.style_mut().frame_padding = [8.0, 6.0]; + imgui.style_mut().item_spacing = [8.0, 6.0]; + imgui.style_mut().item_inner_spacing = [8.0, 6.0]; + imgui.style_mut().indent_spacing = 20.0; + + imgui.style_mut().scrollbar_size = 20.0; + imgui.style_mut().grab_min_size = 8.0; + imgui.style_mut().window_border_size = 0.0; + imgui.style_mut().child_border_size = 0.0; + imgui.style_mut().popup_border_size = 0.0; + imgui.style_mut().frame_border_size = 0.0; + imgui.style_mut().tab_border_size = 0.0; + + imgui.style_mut().window_rounding = 0.0; + imgui.style_mut().child_rounding = 0.0; + imgui.style_mut().frame_rounding = 0.0; + imgui.style_mut().popup_rounding = 0.0; + imgui.style_mut().scrollbar_rounding = 0.0; + imgui.style_mut().grab_rounding = 0.0; + imgui.style_mut().tab_rounding = 0.0; + + imgui.style_mut().window_title_align = [0.50, 0.50]; + imgui.style_mut().window_rounding = 0.0; + + let colors = &mut imgui.style_mut().colors; + colors[ImGuiCol_Text as usize] = [0.90, 0.90, 0.90, 1.00]; + colors[ImGuiCol_TextDisabled as usize] = [0.50, 0.50, 0.50, 1.00]; + colors[ImGuiCol_WindowBg as usize] = [0.05, 0.05, 0.05, 0.60]; + colors[ImGuiCol_ChildBg as usize] = [0.05, 0.05, 0.05, 0.60]; + colors[ImGuiCol_PopupBg as usize] = [0.00, 0.00, 0.00, 0.60]; + colors[ImGuiCol_Border as usize] = [0.40, 0.40, 0.40, 1.00]; + colors[ImGuiCol_BorderShadow as usize] = [1.00, 1.00, 1.00, 0.00]; + colors[ImGuiCol_FrameBg as usize] = [0.00, 0.00, 0.00, 0.60]; + colors[ImGuiCol_FrameBgHovered as usize] = [0.84, 0.37, 0.00, 0.20]; + colors[ImGuiCol_FrameBgActive as usize] = [0.84, 0.37, 0.00, 1.00]; + colors[ImGuiCol_TitleBg as usize] = [0.06, 0.06, 0.06, 1.00]; + colors[ImGuiCol_TitleBgActive as usize] = [0.00, 0.00, 0.00, 1.00]; + colors[ImGuiCol_TitleBgCollapsed as usize] = [0.06, 0.06, 0.06, 0.40]; + colors[ImGuiCol_MenuBarBg as usize] = [0.14, 0.14, 0.14, 1.00]; + colors[ImGuiCol_ScrollbarBg as usize] = [0.14, 0.14, 0.14, 0.40]; + colors[ImGuiCol_ScrollbarGrab as usize] = [0.31, 0.31, 0.31, 0.30]; + colors[ImGuiCol_ScrollbarGrabHovered as usize] = [1.00, 1.00, 1.00, 0.30]; + colors[ImGuiCol_ScrollbarGrabActive as usize] = [1.00, 1.00, 1.00, 0.50]; + colors[ImGuiCol_CheckMark as usize] = [0.90, 0.90, 0.90, 1.00]; + colors[ImGuiCol_SliderGrab as usize] = [0.31, 0.31, 0.31, 1.00]; + colors[ImGuiCol_SliderGrabActive as usize] = [1.00, 1.00, 1.00, 0.50]; + colors[ImGuiCol_Button as usize] = [0.14, 0.14, 0.14, 1.00]; + colors[ImGuiCol_ButtonHovered as usize] = [0.84, 0.37, 0.00, 0.20]; + colors[ImGuiCol_ButtonActive as usize] = [0.84, 0.37, 0.00, 1.00]; + colors[ImGuiCol_Header as usize] = [0.14, 0.14, 0.14, 1.00]; + colors[ImGuiCol_HeaderHovered as usize] = [0.84, 0.37, 0.00, 0.20]; + colors[ImGuiCol_HeaderActive as usize] = [0.84, 0.37, 0.00, 1.00]; + colors[ImGuiCol_Separator as usize] = [0.50, 0.50, 0.43, 0.50]; + colors[ImGuiCol_SeparatorHovered as usize] = [0.75, 0.45, 0.10, 0.78]; + colors[ImGuiCol_SeparatorActive as usize] = [0.75, 0.45, 0.10, 1.00]; + colors[ImGuiCol_ResizeGrip as usize] = [0.98, 0.65, 0.26, 0.25]; + colors[ImGuiCol_ResizeGripHovered as usize] = [0.98, 0.65, 0.26, 0.67]; + colors[ImGuiCol_ResizeGripActive as usize] = [0.98, 0.65, 0.26, 0.95]; + colors[ImGuiCol_Tab as usize] = [0.17, 0.10, 0.04, 0.94]; + colors[ImGuiCol_TabHovered as usize] = [0.84, 0.37, 0.00, 0.60]; + colors[ImGuiCol_TabActive as usize] = [0.67, 0.30, 0.00, 0.68]; + colors[ImGuiCol_TabUnfocused as usize] = [0.06, 0.05, 0.05, 0.69]; + colors[ImGuiCol_TabUnfocusedActive as usize] = [0.36, 0.17, 0.03, 0.64]; + colors[ImGuiCol_PlotLines as usize] = [0.39, 0.39, 0.39, 1.00]; + colors[ImGuiCol_PlotLinesHovered as usize] = [0.35, 0.92, 1.00, 1.00]; + colors[ImGuiCol_PlotHistogram as usize] = [0.00, 0.20, 0.90, 1.00]; + colors[ImGuiCol_PlotHistogramHovered as usize] = [0.00, 0.40, 1.00, 1.00]; + colors[ImGuiCol_TextSelectedBg as usize] = [0.98, 0.65, 0.26, 0.35]; + colors[ImGuiCol_DragDropTarget as usize] = [0.00, 0.00, 1.00, 0.90]; + colors[ImGuiCol_NavHighlight as usize] = [0.98, 0.65, 0.26, 1.00]; + colors[ImGuiCol_NavWindowingHighlight as usize] = [0.00, 0.00, 0.00, 0.70]; + colors[ImGuiCol_NavWindowingDimBg as usize] = [0.20, 0.20, 0.20, 0.20]; + colors[ImGuiCol_ModalWindowDimBg as usize] = [0.20, 0.20, 0.20, 0.35]; + + Ok(imgui) +} + +impl UI { + pub fn new(ctx: &mut Context) -> GameResult { + Ok(Self { + components: Components { + live_debugger: LiveDebugger::new(), + }, + last_frame: Instant::now(), + }) + } + + pub fn draw(&mut self, state: &mut SharedGameState, ctx: &mut Context, scene: &mut Box) -> GameResult { + let ctx2 = unsafe { &mut *(ctx as *const Context as *mut Context)}; + let imgui = imgui_context(ctx)?; + let io = imgui.io_mut(); + let now = Instant::now(); + io.update_delta_time(now - self.last_frame); + self.last_frame = now; + + let mut ui = imgui.frame(); + + scene.debug_overlay_draw(&mut self.components, state, ctx2, &mut ui)?; + + let draw_data = ui.render(); + render_imgui(ctx2, draw_data)?; + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 8e6246c..b46ddbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,12 @@ use crate::framework::error::{GameError, GameResult}; use crate::framework::filesystem::{mount_user_vfs, mount_vfs}; use crate::framework::graphics; use crate::framework::keyboard::ScanCode; +use crate::framework::ui::UI; use crate::framework::vfs::PhysicalFS; use crate::scene::loading_scene::LoadingScene; use crate::scene::Scene; use crate::shared_game_state::{SharedGameState, TimingMode}; use crate::texture_set::{G_MAG, I_MAG}; -use crate::ui::UI; mod bmfont; mod bmfont_renderer; @@ -66,7 +66,6 @@ mod stage; mod sound; mod text_script; mod texture_set; -mod ui; mod weapon; pub struct Game { diff --git a/src/live_debugger.rs b/src/live_debugger.rs index f9ee7b0..ac20093 100644 --- a/src/live_debugger.rs +++ b/src/live_debugger.rs @@ -59,7 +59,7 @@ impl LiveDebugger { Window::new(im_str!("Debugger")) .resizable(false) - .collapsed(true, Condition::FirstUseEver) + .collapsed(false, Condition::FirstUseEver) .position([5.0, 5.0], Condition::FirstUseEver) .size([400.0, 170.0], Condition::FirstUseEver) .build(ui, || { diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 254038a..77aa954 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -15,6 +15,7 @@ use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::framework::graphics; use crate::framework::graphics::{BlendMode, FilterMode}; +use crate::framework::ui::Components; use crate::input::touch_controls::TouchControlType; use crate::inventory::{Inventory, TakeExperienceResult}; use crate::npc::boss::BossNPC; @@ -29,7 +30,6 @@ use crate::shared_game_state::{Season, SharedGameState}; use crate::stage::{BackgroundType, Stage}; use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptVM}; use crate::texture_set::SizedBatch; -use crate::ui::Components; use crate::weapon::WeaponType; pub struct GameScene { @@ -636,7 +636,7 @@ impl GameScene { } graphics::set_blend_mode(ctx, BlendMode::Multiply)?; - graphics::set_render_target(ctx, None); + graphics::set_render_target(ctx, None)?; let rect = Rect { left: 0.0, top: 0.0, right: state.screen_size.0, bottom: state.screen_size.1 }; canvas.clear(); diff --git a/src/scene/mod.rs b/src/scene/mod.rs index d692e04..5534c1d 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -2,7 +2,7 @@ use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::shared_game_state::SharedGameState; -use crate::ui::Components; +use crate::framework::ui::Components; pub mod game_scene; pub mod loading_scene; diff --git a/src/sound/mod.rs b/src/sound/mod.rs index e87d091..4ce7c7d 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -8,7 +8,7 @@ use num_traits::clamp; use crate::engine_constants::EngineConstants; use crate::framework::context::Context; -use crate::framework::error::GameResult; +use crate::framework::error::{GameResult, GameError}; use crate::framework::filesystem; use crate::sound::organya::Song; use crate::sound::pixtone::PixTonePlayback; @@ -16,6 +16,7 @@ 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; @@ -128,13 +129,19 @@ impl SoundManager { .find(|path| filesystem::exists(ctx, path)) .ok_or_else(|| ResourceLoadError(format!("BGM {:?} does not exist.", song_name)))?; - let org = organya::Song::load_from(filesystem::open(ctx, path)?)?; - log::info!("Playing BGM: {}", song_name); + match filesystem::open(ctx, path).map(|f| organya::Song::load_from(f)) { + Ok(Ok(org)) => { + log::info!("Playing BGM: {} {}", song_id, song_name); - self.prev_song_id = self.current_song_id; - self.current_song_id = song_id; - self.tx.send(PlaybackMessage::SaveState)?; - self.tx.send(PlaybackMessage::PlaySong(Box::new(org)))?; + self.prev_song_id = self.current_song_id; + self.current_song_id = song_id; + self.tx.send(PlaybackMessage::SaveState)?; + self.tx.send(PlaybackMessage::PlaySong(Box::new(org)))?; + } + Ok(Err(err)) | Err(err) => { + log::warn!("Failed to load BGM {}: {}", song_id, err); + } + } } Ok(()) } diff --git a/src/sound/organya.rs b/src/sound/organya.rs index bb90c6b..3c1733a 100644 --- a/src/sound/organya.rs +++ b/src/sound/organya.rs @@ -1,12 +1,18 @@ +use std::io; + +use byteorder::{LE, ReadBytesExt}; + +use crate::framework::error::{GameError, GameResult}; + #[repr(u8)] -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Version { // Can't find any files with this signature, // But apparently these files had no Pi flag. Beta = b'1', Main = b'2', // OrgMaker 2.05 Extended Drums - Extended = b'3' + Extended = b'3', } #[derive(Debug, Copy, Clone)] @@ -14,19 +20,19 @@ pub struct LoopRange { // inclusive pub start: i32, // exclusive - pub end: i32 + pub end: i32, } #[derive(Debug, Copy, Clone)] pub struct Display { pub beats: u8, - pub steps: u8 + pub steps: u8, } #[derive(Debug, Copy, Clone)] pub struct Timing { pub wait: u16, - pub loop_range: LoopRange + pub loop_range: LoopRange, } #[derive(Copy, Clone)] @@ -35,12 +41,12 @@ pub struct Instrument { pub freq: u16, pub inst: u8, pub pipi: u8, - pub notes: u16 + pub notes: u16, } pub struct Track { pub inst: Instrument, - pub notes: Vec + pub notes: Vec, } impl Clone for Track { @@ -65,14 +71,14 @@ pub struct Note { pub key: u8, pub len: u8, pub vol: u8, - pub pan: u8 + pub pan: u8, } #[derive(Debug)] pub struct Song { pub version: Version, pub time: Timing, - pub tracks: [Track; 16] + pub tracks: [Track; 16], } impl Clone for Song { @@ -85,85 +91,82 @@ impl Clone for Song { } } -use byteorder::{LE, ReadBytesExt}; -use std::io; - impl Song { pub fn empty() -> Song { Song { version: Version::Main, time: Timing { wait: 8, loop_range: LoopRange { start: 0, end: 1 } }, tracks: [ - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - Track { inst: Instrument {freq: 1000, inst: 0, pipi: 0, notes: 0}, notes: vec![] }, - ] + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + Track { inst: Instrument { freq: 1000, inst: 0, pipi: 0, notes: 0 }, notes: vec![] }, + ], } } - pub fn load_from(mut f: R) -> io::Result { + pub fn load_from(mut f: R) -> GameResult { let mut magic = [0; 6]; - + f.read_exact(&mut magic)?; - - let version = + + let version = match &magic { b"Org-01" => Version::Beta, b"Org-02" => Version::Main, b"Org-03" => Version::Extended, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid magic number")) + _ => return Err(GameError::ResourceLoadError("Invalid magic number".to_string())) }; - - let wait = f.read_u16::()?; - let _bpm = f.read_u8()?; - let _spb = f.read_u8()?; + + let wait = f.read_u16::()?; + let _bpm = f.read_u8()?; + let _spb = f.read_u8()?; let start = f.read_i32::()?; - let end = f.read_i32::()?; - + let end = f.read_i32::()?; + use std::mem::MaybeUninit as Mu; - + let mut insts: [Mu; 16] = unsafe { Mu::uninit().assume_init() }; - + for i in insts.iter_mut() { - let freq = f.read_u16::()?; - let inst = f.read_u8()?; - let pipi = f.read_u8()?; + let freq = f.read_u16::()?; + let inst = f.read_u8()?; + let pipi = f.read_u8()?; let notes = f.read_u16::()?; - + *i = Mu::new(Instrument { freq, inst, pipi, - notes + notes, }); } - + let insts: [Instrument; 16] = unsafe { std::mem::transmute(insts) }; - + let mut tracks: [Mu; 16] = unsafe { Mu::uninit().assume_init() }; - + for (i, t) in tracks.iter_mut().enumerate() { let count = insts[i].notes as usize; - + #[repr(C)] #[derive(Copy, Clone)] struct UninitNote { @@ -171,55 +174,55 @@ impl Song { key: Mu, len: Mu, vol: Mu, - pan: Mu + pan: Mu, } - + let mut notes: Vec = unsafe { vec![Mu::uninit().assume_init(); count] }; - + for note in notes.iter_mut() { note.pos = Mu::new(f.read_i32::()?); } - + for note in notes.iter_mut() { note.key = Mu::new(f.read_u8()?); } - + for note in notes.iter_mut() { note.len = Mu::new(f.read_u8()?); } - + for note in notes.iter_mut() { note.vol = Mu::new(f.read_u8()?); } - + for note in notes.iter_mut() { note.pan = Mu::new(f.read_u8()?); } - + *t = Mu::new(Track { inst: insts[i], - notes: unsafe { std::mem::transmute(notes) } + notes: unsafe { std::mem::transmute(notes) }, }); } - + let tracks = unsafe { std::mem::transmute(tracks) }; - + let song = Song { version, time: Timing { wait, loop_range: LoopRange { start, - end - } + end, + }, }, - tracks + tracks, }; - + Ok(song) } } diff --git a/src/sound/playback.rs b/src/sound/playback.rs index 82b5997..e5cde85 100644 --- a/src/sound/playback.rs +++ b/src/sound/playback.rs @@ -1,6 +1,6 @@ use std::mem::MaybeUninit; -use crate::sound::organya::Song as Organya; +use crate::sound::organya::{Song as Organya, Version}; use crate::sound::stuff::*; use crate::sound::wav::*; use crate::sound::wave_bank::SoundBank; @@ -144,8 +144,12 @@ impl PlaybackEngine { } } - for (idx, (_track, buf)) in song.tracks[8..].iter().zip(self.track_buffers[128..].iter_mut()).enumerate() { - *buf = RenderBuffer::new(samples.samples[idx].clone()); + for (idx, (track, buf)) in song.tracks[8..].iter().zip(self.track_buffers[128..].iter_mut()).enumerate() { + if self.song.version == Version::Extended { + *buf = RenderBuffer::new(samples.samples[track.inst.inst as usize].clone()); + } else { + *buf = RenderBuffer::new(samples.samples[idx].clone()); + } } self.song = song; diff --git a/src/texture_set.rs b/src/texture_set.rs index 1e91128..61a70d6 100644 --- a/src/texture_set.rs +++ b/src/texture_set.rs @@ -91,12 +91,12 @@ impl SizedBatch { #[inline(always)] pub fn add_rect(&mut self, x: f32, y: f32, rect: &common::Rect) { - self.add_rect_scaled(x, y, self.scale_x, self.scale_y, rect) + self.add_rect_scaled(x, y, 1.0, 1.0, rect) } #[inline(always)] pub fn add_rect_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8, u8), rect: &common::Rect) { - self.add_rect_scaled_tinted(x, y, color, self.scale_x, self.scale_y, rect) + 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) { @@ -112,16 +112,16 @@ impl SizedBatch { self.batch.add(SpriteBatchCommand::DrawRect( Rect { - left: rect.left as f32, - top: rect.top as f32, - right: rect.right as f32, - bottom: rect.bottom as f32, + 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 * scale_x, - top: y * mag * scale_y, - right: (x + rect.width() as f32) * mag * scale_x, - bottom: (y + rect.height() as f32) * mag * scale_y, + left: x * mag, + top: y * mag, + right: (x + rect.width() as f32 * scale_x) * mag, + bottom: (y + rect.height() as f32 * scale_y) * mag, }, )); } @@ -160,7 +160,7 @@ impl SizedBatch { } pub fn draw_filtered(&mut self, filter: FilterMode, ctx: &mut Context) -> GameResult { - ///self.batch.set_filter(filter); + //self.batch.set_filter(filter); self.batch.draw()?; self.batch.clear(); Ok(()) @@ -241,7 +241,6 @@ impl TextureSet { 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; - println!("{} {} {} {}", size.0, size.1, width, height); Ok(SizedBatch { batch, diff --git a/src/ui.rs b/src/ui.rs deleted file mode 100644 index 0322907..0000000 --- a/src/ui.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::time::Instant; - -use imgui::{FontConfig, FontSource}; -use imgui::sys::*; - -use crate::framework::context::Context; -use crate::framework::error::GameResult; -use crate::live_debugger::LiveDebugger; -use crate::scene::Scene; -use crate::shared_game_state::SharedGameState; - -pub struct UI { - pub imgui: imgui::Context, - pub components: Components, - last_frame: Instant, -} - -pub struct Components { - pub live_debugger: LiveDebugger, -} - -impl UI { - pub fn new(ctx: &mut Context) -> GameResult { - let mut imgui = imgui::Context::create(); - imgui.set_ini_filename(None); - imgui.fonts().add_font(&[ - FontSource::DefaultFontData { - config: Some(FontConfig::default()), - }, - ]); - - imgui.style_mut().window_padding = [4.0, 6.0]; - imgui.style_mut().frame_padding = [8.0, 6.0]; - imgui.style_mut().item_spacing = [8.0, 6.0]; - imgui.style_mut().item_inner_spacing = [8.0, 6.0]; - imgui.style_mut().indent_spacing = 20.0; - - imgui.style_mut().scrollbar_size = 20.0; - imgui.style_mut().grab_min_size = 5.0; - imgui.style_mut().window_border_size = 0.0; - imgui.style_mut().child_border_size = 1.0; - imgui.style_mut().popup_border_size = 1.0; - imgui.style_mut().frame_border_size = 1.0; - imgui.style_mut().tab_border_size = 0.0; - - imgui.style_mut().window_rounding = 0.0; - imgui.style_mut().child_rounding = 0.0; - imgui.style_mut().frame_rounding = 0.0; - imgui.style_mut().popup_rounding = 0.0; - imgui.style_mut().scrollbar_rounding = 0.0; - imgui.style_mut().grab_rounding = 0.0; - imgui.style_mut().tab_rounding = 0.0; - - imgui.style_mut().window_title_align = [0.50, 0.50]; - imgui.style_mut().window_rounding = 0.0; - - let colors = &mut imgui.style_mut().colors; - colors[ImGuiCol_Text as usize] = [0.90, 0.90, 0.90, 1.00]; - colors[ImGuiCol_TextDisabled as usize] = [0.50, 0.50, 0.50, 1.00]; - colors[ImGuiCol_WindowBg as usize] = [0.05, 0.05, 0.05, 0.60]; - colors[ImGuiCol_ChildBg as usize] = [0.05, 0.05, 0.05, 0.60]; - colors[ImGuiCol_PopupBg as usize] = [0.00, 0.00, 0.00, 0.60]; - colors[ImGuiCol_Border as usize] = [0.40, 0.40, 0.40, 1.00]; - colors[ImGuiCol_BorderShadow as usize] = [1.00, 1.00, 1.00, 0.00]; - colors[ImGuiCol_FrameBg as usize] = [0.00, 0.00, 0.00, 0.60]; - colors[ImGuiCol_FrameBgHovered as usize] = [0.84, 0.37, 0.00, 0.20]; - colors[ImGuiCol_FrameBgActive as usize] = [0.84, 0.37, 0.00, 1.00]; - colors[ImGuiCol_TitleBg as usize] = [0.06, 0.06, 0.06, 1.00]; - colors[ImGuiCol_TitleBgActive as usize] = [0.00, 0.00, 0.00, 1.00]; - colors[ImGuiCol_TitleBgCollapsed as usize] = [0.06, 0.06, 0.06, 0.40]; - colors[ImGuiCol_MenuBarBg as usize] = [0.14, 0.14, 0.14, 1.00]; - colors[ImGuiCol_ScrollbarBg as usize] = [0.14, 0.14, 0.14, 0.40]; - colors[ImGuiCol_ScrollbarGrab as usize] = [0.31, 0.31, 0.31, 0.30]; - colors[ImGuiCol_ScrollbarGrabHovered as usize] = [1.00, 1.00, 1.00, 0.30]; - colors[ImGuiCol_ScrollbarGrabActive as usize] = [1.00, 1.00, 1.00, 0.50]; - colors[ImGuiCol_CheckMark as usize] = [0.90, 0.90, 0.90, 1.00]; - colors[ImGuiCol_SliderGrab as usize] = [0.31, 0.31, 0.31, 1.00]; - colors[ImGuiCol_SliderGrabActive as usize] = [1.00, 1.00, 1.00, 0.50]; - colors[ImGuiCol_Button as usize] = [0.14, 0.14, 0.14, 1.00]; - colors[ImGuiCol_ButtonHovered as usize] = [0.84, 0.37, 0.00, 0.20]; - colors[ImGuiCol_ButtonActive as usize] = [0.84, 0.37, 0.00, 1.00]; - colors[ImGuiCol_Header as usize] = [0.14, 0.14, 0.14, 1.00]; - colors[ImGuiCol_HeaderHovered as usize] = [0.84, 0.37, 0.00, 0.20]; - colors[ImGuiCol_HeaderActive as usize] = [0.84, 0.37, 0.00, 1.00]; - colors[ImGuiCol_Separator as usize] = [0.50, 0.50, 0.43, 0.50]; - colors[ImGuiCol_SeparatorHovered as usize] = [0.75, 0.45, 0.10, 0.78]; - colors[ImGuiCol_SeparatorActive as usize] = [0.75, 0.45, 0.10, 1.00]; - colors[ImGuiCol_ResizeGrip as usize] = [0.98, 0.65, 0.26, 0.25]; - colors[ImGuiCol_ResizeGripHovered as usize] = [0.98, 0.65, 0.26, 0.67]; - colors[ImGuiCol_ResizeGripActive as usize] = [0.98, 0.65, 0.26, 0.95]; - colors[ImGuiCol_Tab as usize] = [0.17, 0.10, 0.04, 0.94]; - colors[ImGuiCol_TabHovered as usize] = [0.84, 0.37, 0.00, 0.60]; - colors[ImGuiCol_TabActive as usize] = [0.67, 0.30, 0.00, 0.68]; - colors[ImGuiCol_TabUnfocused as usize] = [0.06, 0.05, 0.05, 0.69]; - colors[ImGuiCol_TabUnfocusedActive as usize] = [0.36, 0.17, 0.03, 0.64]; - colors[ImGuiCol_PlotLines as usize] = [0.39, 0.39, 0.39, 1.00]; - colors[ImGuiCol_PlotLinesHovered as usize] = [0.35, 0.92, 1.00, 1.00]; - colors[ImGuiCol_PlotHistogram as usize] = [0.00, 0.20, 0.90, 1.00]; - colors[ImGuiCol_PlotHistogramHovered as usize] = [0.00, 0.40, 1.00, 1.00]; - colors[ImGuiCol_TextSelectedBg as usize] = [0.98, 0.65, 0.26, 0.35]; - colors[ImGuiCol_DragDropTarget as usize] = [0.00, 0.00, 1.00, 0.90]; - colors[ImGuiCol_NavHighlight as usize] = [0.98, 0.65, 0.26, 1.00]; - colors[ImGuiCol_NavWindowingHighlight as usize] = [0.00, 0.00, 0.00, 0.70]; - colors[ImGuiCol_NavWindowingDimBg as usize] = [0.20, 0.20, 0.20, 0.20]; - colors[ImGuiCol_ModalWindowDimBg as usize] = [0.20, 0.20, 0.20, 0.35]; - - Ok(Self { - imgui, - components: Components { - live_debugger: LiveDebugger::new(), - }, - last_frame: Instant::now(), - }) - } - - pub fn draw(&mut self, state: &mut SharedGameState, ctx: &mut Context, scene: &mut Box) -> GameResult { - /*{ - let io = self.imgui.io_mut(); - let now = Instant::now(); - io.update_delta_time(now - self.last_frame); - self.last_frame = now; - } - let mut ui = self.imgui.frame(); - - scene.debug_overlay_draw(&mut self.components, state, ctx, &mut ui)?; - - ui.render();*/ - Ok(()) - } -} diff --git a/src/weapon.rs b/src/weapon.rs index 1920770..d2b2687 100644 --- a/src/weapon.rs +++ b/src/weapon.rs @@ -443,8 +443,8 @@ impl Weapon { WeaponLevel::None => unreachable!(), } - const bullets: [u16; 6] = [44, 45, 46, 47, 48, 49]; - if bullet_manager.count_bullets_multi(&bullets, player_id) == 0 + const BULLETS: [u16; 6] = [44, 45, 46, 47, 48, 49]; + if bullet_manager.count_bullets_multi(&BULLETS, player_id) == 0 && (player.controller.trigger_shoot() || shoot) { if !self.consume_ammo(1) { state.sound_manager.play_sfx(37);