1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2025-11-30 08:08:18 +00:00

ggez is gone

This commit is contained in:
Alula 2021-02-05 23:47:13 +01:00
parent c3887e31c7
commit 318d94d843
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
18 changed files with 509 additions and 244 deletions

View file

@ -25,10 +25,10 @@ install:
- cargo -vV - cargo -vV
cache: cache:
- '%USERPROFILE%\.cache\sccache -> .appveyor.yml' - '%USERPROFILE%\.cache\sccache -> Cargo.toml'
- '%USERPROFILE%\.cargo -> .appveyor.yml' - '%USERPROFILE%\.cargo -> Cargo.toml'
- '%USERPROFILE%\.rustup -> .appveyor.yml' - '%USERPROFILE%\.rustup -> Cargo.toml'
- 'target -> .appveyor.yml' - 'target -> Cargo.toml'
#test_script: #test_script:
# - cargo build --verbose --all # - cargo build --verbose --all

View file

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

View file

@ -78,10 +78,10 @@ Vanilla Cave Story does not work yet because some important data files have been
- [ ] Machine Gun - [ ] Machine Gun
- [ ] Missile Launcher - [ ] Missile Launcher
- [ ] Bubbler - [ ] Bubbler
- [ ] Blade - [x] Blade
- [ ] Super Missile Launcher - [ ] Super Missile Launcher
- [ ] Nemesis - [x] Nemesis
- [ ] Spur - [x] Spur
- [x] Saving and loading game state - [x] Saving and loading game state
- [ ] Support for different game editions - [ ] Support for different game editions
- [ ] Vanilla - [ ] Vanilla

View file

@ -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::context::Context;
use crate::framework::error::GameResult; use crate::framework::error::GameResult;
use crate::Game;
use crate::framework::graphics::BlendMode; use crate::framework::graphics::BlendMode;
use crate::Game;
pub trait Backend { pub trait Backend {
fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>>; fn create_event_loop(&self) -> GameResult<Box<dyn BackendEventLoop>>;
@ -26,12 +28,21 @@ pub trait BackendRenderer {
fn set_blend_mode(&mut self, blend: BlendMode) -> GameResult; fn set_blend_mode(&mut self, blend: BlendMode) -> GameResult;
fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> GameResult; fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> 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 { pub trait BackendTexture {
fn dimensions(&self) -> (u16, u16); fn dimensions(&self) -> (u16, u16);
fn add(&mut self, command: SpriteBatchCommand); fn add(&mut self, command: SpriteBatchCommand);
fn clear(&mut self); fn clear(&mut self);
fn draw(&mut self) -> GameResult; fn draw(&mut self) -> GameResult;
} }

View file

@ -1,20 +1,26 @@
use core::mem; use core::mem;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use imgui::{DrawCmd, DrawData, ImString, TextureId, Ui};
use imgui::internal::RawWrapper;
use sdl2::{EventPump, keyboard, pixels, Sdl}; use sdl2::{EventPump, keyboard, pixels, Sdl};
use sdl2::event::{Event, WindowEvent}; use sdl2::event::{Event, WindowEvent};
use sdl2::gfx::primitives::DrawRenderer;
use sdl2::keyboard::Scancode; use sdl2::keyboard::Scancode;
use sdl2::pixels::PixelFormatEnum; use sdl2::pixels::PixelFormatEnum;
use sdl2::render::{Texture, TextureCreator, WindowCanvas}; use sdl2::render::{Texture, TextureCreator, WindowCanvas};
use sdl2::surface::Surface;
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::graphics::{BlendMode, imgui_context};
use crate::framework::keyboard::ScanCode; use crate::framework::keyboard::ScanCode;
use crate::framework::ui::init_imgui;
use crate::Game; use crate::Game;
pub struct SDL2Backend { pub struct SDL2Backend {
@ -87,14 +93,24 @@ 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 (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())
};
{ {
let (width, height) = self.refs.borrow().canvas.window().size(); let (width, height) = self.refs.borrow().canvas.window().size();
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32); 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); let _ = state.handle_resize(ctx);
} }
loop { loop {
for event in self.event_pump.poll_iter() { for event in self.event_pump.poll_iter() {
imgui_sdl2.handle_event(imgui, &event);
match event { match event {
Event::Quit { .. } => { Event::Quit { .. } => {
state.shutdown(); state.shutdown();
@ -105,6 +121,12 @@ impl BackendEventLoop for SDL2EventLoop {
WindowEvent::Hidden => {} WindowEvent::Hidden => {}
WindowEvent::SizeChanged(width, height) => { WindowEvent::SizeChanged(width, height) => {
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32); 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); state.handle_resize(ctx);
} }
_ => {} _ => {}
@ -145,6 +167,7 @@ impl BackendEventLoop for SDL2EventLoop {
state.frame_time = 0.0; 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(); game.draw(ctx).unwrap();
} }
} }
@ -156,12 +179,62 @@ impl BackendEventLoop for SDL2EventLoop {
struct SDL2Renderer { struct SDL2Renderer {
refs: Rc<RefCell<SDL2Context>>, refs: Rc<RefCell<SDL2Context>>,
imgui: Rc<RefCell<imgui::Context>>,
imgui_event: Rc<RefCell<imgui_sdl2::ImguiSdl2>>,
imgui_textures: HashMap<TextureId, SDL2Texture>,
} }
impl SDL2Renderer { impl SDL2Renderer {
#[allow(clippy::new_ret_no_self)]
pub fn new(refs: Rc<RefCell<SDL2Context>>) -> GameResult<Box<dyn BackendRenderer>> { pub fn new(refs: Rc<RefCell<SDL2Context>>) -> GameResult<Box<dyn BackendRenderer>> {
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 { Ok(Box::new(SDL2Renderer {
refs, 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 { 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();
@ -275,8 +356,137 @@ impl BackendRenderer for SDL2Renderer {
Ok(()) 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 { struct SDL2Texture {
refs: Rc<RefCell<SDL2Context>>, refs: Rc<RefCell<SDL2Context>>,
texture: Option<Texture>, texture: Option<Texture>,

View file

@ -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())) 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()))
}

View file

@ -1,9 +1,10 @@
pub mod backend; pub mod backend;
pub mod backend_sdl2; pub mod backend_sdl2;
pub mod backend_null;
pub mod context; pub mod context;
pub mod error; pub mod error;
pub mod filesystem; pub mod filesystem;
pub mod vfs;
pub mod graphics; pub mod graphics;
pub mod keyboard; pub mod keyboard;
pub mod backend_null; pub mod ui;
pub mod vfs;

136
src/framework/ui.rs Normal file
View file

@ -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<imgui::Context> {
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<Self> {
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<dyn Scene>) -> 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(())
}
}

View file

@ -24,12 +24,12 @@ use crate::framework::error::{GameError, GameResult};
use crate::framework::filesystem::{mount_user_vfs, mount_vfs}; use crate::framework::filesystem::{mount_user_vfs, mount_vfs};
use crate::framework::graphics; use crate::framework::graphics;
use crate::framework::keyboard::ScanCode; use crate::framework::keyboard::ScanCode;
use crate::framework::ui::UI;
use crate::framework::vfs::PhysicalFS; use crate::framework::vfs::PhysicalFS;
use crate::scene::loading_scene::LoadingScene; use crate::scene::loading_scene::LoadingScene;
use crate::scene::Scene; use crate::scene::Scene;
use crate::shared_game_state::{SharedGameState, TimingMode}; use crate::shared_game_state::{SharedGameState, TimingMode};
use crate::texture_set::{G_MAG, I_MAG}; use crate::texture_set::{G_MAG, I_MAG};
use crate::ui::UI;
mod bmfont; mod bmfont;
mod bmfont_renderer; mod bmfont_renderer;
@ -66,7 +66,6 @@ mod stage;
mod sound; mod sound;
mod text_script; mod text_script;
mod texture_set; mod texture_set;
mod ui;
mod weapon; mod weapon;
pub struct Game { pub struct Game {

View file

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

View file

@ -15,6 +15,7 @@ use crate::framework::context::Context;
use crate::framework::error::GameResult; use crate::framework::error::GameResult;
use crate::framework::graphics; use crate::framework::graphics;
use crate::framework::graphics::{BlendMode, FilterMode}; use crate::framework::graphics::{BlendMode, FilterMode};
use crate::framework::ui::Components;
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;
@ -29,7 +30,6 @@ use crate::shared_game_state::{Season, SharedGameState};
use crate::stage::{BackgroundType, Stage}; use crate::stage::{BackgroundType, Stage};
use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptVM}; use crate::text_script::{ConfirmSelection, ScriptMode, TextScriptExecutionState, TextScriptVM};
use crate::texture_set::SizedBatch; use crate::texture_set::SizedBatch;
use crate::ui::Components;
use crate::weapon::WeaponType; use crate::weapon::WeaponType;
pub struct GameScene { pub struct GameScene {
@ -636,7 +636,7 @@ impl GameScene {
} }
graphics::set_blend_mode(ctx, BlendMode::Multiply)?; 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 }; let rect = Rect { left: 0.0, top: 0.0, right: state.screen_size.0, bottom: state.screen_size.1 };
canvas.clear(); canvas.clear();

View file

@ -2,7 +2,7 @@ use crate::framework::context::Context;
use crate::framework::error::GameResult; use crate::framework::error::GameResult;
use crate::shared_game_state::SharedGameState; use crate::shared_game_state::SharedGameState;
use crate::ui::Components; use crate::framework::ui::Components;
pub mod game_scene; pub mod game_scene;
pub mod loading_scene; pub mod loading_scene;

View file

@ -8,7 +8,7 @@ use num_traits::clamp;
use crate::engine_constants::EngineConstants; use crate::engine_constants::EngineConstants;
use crate::framework::context::Context; use crate::framework::context::Context;
use crate::framework::error::GameResult; use crate::framework::error::{GameResult, GameError};
use crate::framework::filesystem; use crate::framework::filesystem;
use crate::sound::organya::Song; use crate::sound::organya::Song;
use crate::sound::pixtone::PixTonePlayback; use crate::sound::pixtone::PixTonePlayback;
@ -16,6 +16,7 @@ use crate::sound::playback::{PlaybackEngine, SavedPlaybackState};
use crate::sound::wave_bank::SoundBank; use crate::sound::wave_bank::SoundBank;
use crate::str; use crate::str;
use crate::framework::error::GameError::{AudioError, ResourceLoadError, InvalidValue}; use crate::framework::error::GameError::{AudioError, ResourceLoadError, InvalidValue};
use std::io::Error;
mod wave_bank; mod wave_bank;
mod organya; mod organya;
@ -128,13 +129,19 @@ impl SoundManager {
.find(|path| filesystem::exists(ctx, path)) .find(|path| filesystem::exists(ctx, path))
.ok_or_else(|| ResourceLoadError(format!("BGM {:?} does not exist.", song_name)))?; .ok_or_else(|| ResourceLoadError(format!("BGM {:?} does not exist.", song_name)))?;
let org = organya::Song::load_from(filesystem::open(ctx, path)?)?; match filesystem::open(ctx, path).map(|f| organya::Song::load_from(f)) {
log::info!("Playing BGM: {}", song_name); Ok(Ok(org)) => {
log::info!("Playing BGM: {} {}", song_id, song_name);
self.prev_song_id = self.current_song_id; self.prev_song_id = self.current_song_id;
self.current_song_id = song_id; self.current_song_id = song_id;
self.tx.send(PlaybackMessage::SaveState)?; self.tx.send(PlaybackMessage::SaveState)?;
self.tx.send(PlaybackMessage::PlaySong(Box::new(org)))?; self.tx.send(PlaybackMessage::PlaySong(Box::new(org)))?;
}
Ok(Err(err)) | Err(err) => {
log::warn!("Failed to load BGM {}: {}", song_id, err);
}
}
} }
Ok(()) Ok(())
} }

View file

@ -1,12 +1,18 @@
use std::io;
use byteorder::{LE, ReadBytesExt};
use crate::framework::error::{GameError, GameResult};
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Version { pub enum Version {
// Can't find any files with this signature, // Can't find any files with this signature,
// But apparently these files had no Pi flag. // But apparently these files had no Pi flag.
Beta = b'1', Beta = b'1',
Main = b'2', Main = b'2',
// OrgMaker 2.05 Extended Drums // OrgMaker 2.05 Extended Drums
Extended = b'3' Extended = b'3',
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -14,19 +20,19 @@ pub struct LoopRange {
// inclusive // inclusive
pub start: i32, pub start: i32,
// exclusive // exclusive
pub end: i32 pub end: i32,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Display { pub struct Display {
pub beats: u8, pub beats: u8,
pub steps: u8 pub steps: u8,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Timing { pub struct Timing {
pub wait: u16, pub wait: u16,
pub loop_range: LoopRange pub loop_range: LoopRange,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -35,12 +41,12 @@ pub struct Instrument {
pub freq: u16, pub freq: u16,
pub inst: u8, pub inst: u8,
pub pipi: u8, pub pipi: u8,
pub notes: u16 pub notes: u16,
} }
pub struct Track { pub struct Track {
pub inst: Instrument, pub inst: Instrument,
pub notes: Vec<Note> pub notes: Vec<Note>,
} }
impl Clone for Track { impl Clone for Track {
@ -65,14 +71,14 @@ pub struct Note {
pub key: u8, pub key: u8,
pub len: u8, pub len: u8,
pub vol: u8, pub vol: u8,
pub pan: u8 pub pan: u8,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Song { pub struct Song {
pub version: Version, pub version: Version,
pub time: Timing, pub time: Timing,
pub tracks: [Track; 16] pub tracks: [Track; 16],
} }
impl Clone for Song { impl Clone for Song {
@ -85,36 +91,33 @@ impl Clone for Song {
} }
} }
use byteorder::{LE, ReadBytesExt};
use std::io;
impl Song { impl Song {
pub fn empty() -> Song { pub fn empty() -> Song {
Song { Song {
version: Version::Main, version: Version::Main,
time: Timing { wait: 8, loop_range: LoopRange { start: 0, end: 1 } }, time: Timing { wait: 8, loop_range: LoopRange { start: 0, end: 1 } },
tracks: [ 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<R: io::Read>(mut f: R) -> io::Result<Song> { pub fn load_from<R: io::Read>(mut f: R) -> GameResult<Song> {
let mut magic = [0; 6]; let mut magic = [0; 6];
f.read_exact(&mut magic)?; f.read_exact(&mut magic)?;
@ -124,14 +127,14 @@ impl Song {
b"Org-01" => Version::Beta, b"Org-01" => Version::Beta,
b"Org-02" => Version::Main, b"Org-02" => Version::Main,
b"Org-03" => Version::Extended, 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::<LE>()?; let wait = f.read_u16::<LE>()?;
let _bpm = f.read_u8()?; let _bpm = f.read_u8()?;
let _spb = f.read_u8()?; let _spb = f.read_u8()?;
let start = f.read_i32::<LE>()?; let start = f.read_i32::<LE>()?;
let end = f.read_i32::<LE>()?; let end = f.read_i32::<LE>()?;
use std::mem::MaybeUninit as Mu; use std::mem::MaybeUninit as Mu;
@ -140,16 +143,16 @@ impl Song {
}; };
for i in insts.iter_mut() { for i in insts.iter_mut() {
let freq = f.read_u16::<LE>()?; let freq = f.read_u16::<LE>()?;
let inst = f.read_u8()?; let inst = f.read_u8()?;
let pipi = f.read_u8()?; let pipi = f.read_u8()?;
let notes = f.read_u16::<LE>()?; let notes = f.read_u16::<LE>()?;
*i = Mu::new(Instrument { *i = Mu::new(Instrument {
freq, freq,
inst, inst,
pipi, pipi,
notes notes,
}); });
} }
@ -171,7 +174,7 @@ impl Song {
key: Mu<u8>, key: Mu<u8>,
len: Mu<u8>, len: Mu<u8>,
vol: Mu<u8>, vol: Mu<u8>,
pan: Mu<u8> pan: Mu<u8>,
} }
let mut notes: Vec<UninitNote> = unsafe { let mut notes: Vec<UninitNote> = unsafe {
@ -200,7 +203,7 @@ impl Song {
*t = Mu::new(Track { *t = Mu::new(Track {
inst: insts[i], inst: insts[i],
notes: unsafe { std::mem::transmute(notes) } notes: unsafe { std::mem::transmute(notes) },
}); });
} }
@ -214,10 +217,10 @@ impl Song {
wait, wait,
loop_range: LoopRange { loop_range: LoopRange {
start, start,
end end,
} },
}, },
tracks tracks,
}; };
Ok(song) Ok(song)

View file

@ -1,6 +1,6 @@
use std::mem::MaybeUninit; 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::stuff::*;
use crate::sound::wav::*; use crate::sound::wav::*;
use crate::sound::wave_bank::SoundBank; 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() { for (idx, (track, buf)) in song.tracks[8..].iter().zip(self.track_buffers[128..].iter_mut()).enumerate() {
*buf = RenderBuffer::new(samples.samples[idx].clone()); 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; self.song = song;

View file

@ -91,12 +91,12 @@ impl SizedBatch {
#[inline(always)] #[inline(always)]
pub fn add_rect(&mut self, x: f32, y: f32, rect: &common::Rect<u16>) { pub fn add_rect(&mut self, x: f32, y: f32, rect: &common::Rect<u16>) {
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)] #[inline(always)]
pub fn add_rect_tinted(&mut self, x: f32, y: f32, color: (u8, u8, u8, u8), rect: &common::Rect<u16>) { 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, 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<u16>) { 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>) {
@ -112,16 +112,16 @@ impl SizedBatch {
self.batch.add(SpriteBatchCommand::DrawRect( self.batch.add(SpriteBatchCommand::DrawRect(
Rect { Rect {
left: rect.left as f32, left: rect.left as f32 / self.scale_x,
top: rect.top as f32, top: rect.top as f32 / self.scale_y,
right: rect.right as f32, right: rect.right as f32 / self.scale_x,
bottom: rect.bottom as f32, bottom: rect.bottom as f32 / self.scale_y,
}, },
Rect { Rect {
left: x * mag * scale_x, left: x * mag,
top: y * mag * scale_y, top: y * mag,
right: (x + rect.width() as f32) * mag * scale_x, right: (x + rect.width() as f32 * scale_x) * mag,
bottom: (y + rect.height() as f32) * mag * scale_y, 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 { 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.draw()?;
self.batch.clear(); self.batch.clear();
Ok(()) Ok(())
@ -241,7 +241,6 @@ impl TextureSet {
let scale = orig_dimensions.0 as f32 / size.0 as f32; let scale = orig_dimensions.0 as f32 / size.0 as f32;
let width = (size.0 as f32 * scale) as usize; let width = (size.0 as f32 * scale) as usize;
let height = (size.1 as f32 * scale) as usize; let height = (size.1 as f32 * scale) as usize;
println!("{} {} {} {}", size.0, size.1, width, height);
Ok(SizedBatch { Ok(SizedBatch {
batch, batch,

130
src/ui.rs
View file

@ -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<Self> {
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<dyn Scene>) -> 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(())
}
}

View file

@ -443,8 +443,8 @@ impl Weapon {
WeaponLevel::None => unreachable!(), WeaponLevel::None => unreachable!(),
} }
const bullets: [u16; 6] = [44, 45, 46, 47, 48, 49]; const BULLETS: [u16; 6] = [44, 45, 46, 47, 48, 49];
if bullet_manager.count_bullets_multi(&bullets, player_id) == 0 if bullet_manager.count_bullets_multi(&BULLETS, player_id) == 0
&& (player.controller.trigger_shoot() || shoot) { && (player.controller.trigger_shoot() || shoot) {
if !self.consume_ammo(1) { if !self.consume_ammo(1) {
state.sound_manager.play_sfx(37); state.sound_manager.play_sfx(37);