mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-11-29 15:56:53 +00:00
ggez is gone
This commit is contained in:
parent
c3887e31c7
commit
318d94d843
|
|
@ -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
|
||||
|
|
|
|||
13
Cargo.toml
13
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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<Box<dyn BackendEventLoop>>;
|
||||
|
|
@ -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<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 {
|
||||
fn dimensions(&self) -> (u16, u16);
|
||||
|
||||
fn add(&mut self, command: SpriteBatchCommand);
|
||||
|
||||
fn clear(&mut self);
|
||||
|
||||
fn draw(&mut self) -> GameResult;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<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();
|
||||
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<RefCell<SDL2Context>>,
|
||||
imgui: Rc<RefCell<imgui::Context>>,
|
||||
imgui_event: Rc<RefCell<imgui_sdl2::ImguiSdl2>>,
|
||||
imgui_textures: HashMap<TextureId, SDL2Texture>,
|
||||
}
|
||||
|
||||
impl SDL2Renderer {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
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 {
|
||||
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<RefCell<SDL2Context>>,
|
||||
texture: Option<Texture>,
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
136
src/framework/ui.rs
Normal file
136
src/framework/ui.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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, || {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Note>
|
||||
pub notes: Vec<Note>,
|
||||
}
|
||||
|
||||
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<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];
|
||||
|
||||
|
||||
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::<LE>()?;
|
||||
let _bpm = f.read_u8()?;
|
||||
let _spb = f.read_u8()?;
|
||||
|
||||
let wait = f.read_u16::<LE>()?;
|
||||
let _bpm = f.read_u8()?;
|
||||
let _spb = f.read_u8()?;
|
||||
let start = f.read_i32::<LE>()?;
|
||||
let end = f.read_i32::<LE>()?;
|
||||
|
||||
let end = f.read_i32::<LE>()?;
|
||||
|
||||
use std::mem::MaybeUninit as Mu;
|
||||
|
||||
|
||||
let mut insts: [Mu<Instrument>; 16] = unsafe {
|
||||
Mu::uninit().assume_init()
|
||||
};
|
||||
|
||||
|
||||
for i in insts.iter_mut() {
|
||||
let freq = f.read_u16::<LE>()?;
|
||||
let inst = f.read_u8()?;
|
||||
let pipi = f.read_u8()?;
|
||||
let freq = f.read_u16::<LE>()?;
|
||||
let inst = f.read_u8()?;
|
||||
let pipi = f.read_u8()?;
|
||||
let notes = f.read_u16::<LE>()?;
|
||||
|
||||
|
||||
*i = Mu::new(Instrument {
|
||||
freq,
|
||||
inst,
|
||||
pipi,
|
||||
notes
|
||||
notes,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
let insts: [Instrument; 16] = unsafe {
|
||||
std::mem::transmute(insts)
|
||||
};
|
||||
|
||||
|
||||
let mut tracks: [Mu<Track>; 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<u8>,
|
||||
len: Mu<u8>,
|
||||
vol: Mu<u8>,
|
||||
pan: Mu<u8>
|
||||
pan: Mu<u8>,
|
||||
}
|
||||
|
||||
|
||||
let mut notes: Vec<UninitNote> = unsafe {
|
||||
vec![Mu::uninit().assume_init(); count]
|
||||
};
|
||||
|
||||
|
||||
for note in notes.iter_mut() {
|
||||
note.pos = Mu::new(f.read_i32::<LE>()?);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -91,12 +91,12 @@ impl SizedBatch {
|
|||
|
||||
#[inline(always)]
|
||||
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)]
|
||||
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>) {
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
130
src/ui.rs
130
src/ui.rs
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue