SDL controller input

This commit is contained in:
Luke Street 2022-02-07 20:48:08 -05:00
parent 938852afd8
commit a1482b4743
19 changed files with 554 additions and 268 deletions

3
.gitmodules vendored
View File

@ -57,3 +57,6 @@
[submodule "extern/imgui"] [submodule "extern/imgui"]
path = extern/imgui path = extern/imgui
url = https://github.com/ocornut/imgui.git url = https://github.com/ocornut/imgui.git
[submodule "extern/SDL"]
path = extern/SDL
url = https://github.com/libsdl-org/SDL.git

View File

@ -481,21 +481,8 @@ target_include_directories(hecl-light PRIVATE ${CMAKE_SOURCE_DIR})
target_link_libraries(hecl-full PRIVATE zeus nod) target_link_libraries(hecl-full PRIVATE zeus nod)
target_link_libraries(hecl-light PRIVATE zeus nod) target_link_libraries(hecl-light PRIVATE zeus nod)
#bintoc(CModelShaders.common.glsl.cpp Shaders/CModelShaders.common.glsl CMODELSHADERS_COMMON_GLSL) add_subdirectory(extern/SDL EXCLUDE_FROM_ALL)
#bintoc(CModelShaders.vert.glsl.cpp Shaders/CModelShaders.vert.glsl CMODELSHADERS_VERT_GLSL) target_compile_options(SDL2-static PRIVATE -Wno-implicit-fallthrough)
#bintoc(CModelShaders.frag.glsl.cpp Shaders/CModelShaders.frag.glsl CMODELSHADERS_FRAG_GLSL)
#bintoc(CModelShaders.common.hlsl.cpp Shaders/CModelShaders.common.hlsl CMODELSHADERS_COMMON_HLSL)
#bintoc(CModelShaders.vert.hlsl.cpp Shaders/CModelShaders.vert.hlsl CMODELSHADERS_VERT_HLSL)
#bintoc(CModelShaders.frag.hlsl.cpp Shaders/CModelShaders.frag.hlsl CMODELSHADERS_FRAG_HLSL)
#bintoc(CModelShaders.common.metal.cpp Shaders/CModelShaders.common.metal CMODELSHADERS_COMMON_METAL)
#bintoc(CModelShaders.vert.metal.cpp Shaders/CModelShaders.vert.metal CMODELSHADERS_VERT_METAL)
#bintoc(CModelShaders.frag.metal.cpp Shaders/CModelShaders.frag.metal CMODELSHADERS_FRAG_METAL)
#add_library(CModelShaders
# CModelShaders.common.glsl.cpp CModelShaders.vert.glsl.cpp CModelShaders.frag.glsl.cpp
# CModelShaders.common.hlsl.cpp CModelShaders.vert.hlsl.cpp CModelShaders.frag.hlsl.cpp
# CModelShaders.common.metal.cpp CModelShaders.vert.metal.cpp CModelShaders.frag.metal.cpp)
#target_link_libraries(CModelShaders PUBLIC zeus)
#target_link_libraries(shader_CModelShaders PUBLIC CModelShaders)
if(NOT TARGET atdna) if(NOT TARGET atdna)
# Import native atdna if cross-compiling # Import native atdna if cross-compiling

28
Graphics/Cargo.lock generated
View File

@ -116,6 +116,7 @@ dependencies = [
"num_enum", "num_enum",
"pollster", "pollster",
"scopeguard", "scopeguard",
"sdl2",
"smallvec", "smallvec",
"twox-hash", "twox-hash",
"wasm-bindgen-futures", "wasm-bindgen-futures",
@ -1439,6 +1440,27 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96311ef4a16462c757bb6a39152c40f58f31cd2602a40fceb937e2bc34e6cbab" checksum = "96311ef4a16462c757bb6a39152c40f58f31cd2602a40fceb937e2bc34e6cbab"
[[package]]
name = "sdl2"
version = "0.35.2"
source = "git+https://github.com/encounter/rust-sdl2.git?rev=e282ef3acd7fcb4b2ba16863a7a0a7a8439f9335#e282ef3acd7fcb4b2ba16863a7a0a7a8439f9335"
dependencies = [
"bitflags",
"lazy_static",
"libc",
"sdl2-sys",
]
[[package]]
name = "sdl2-sys"
version = "0.35.2"
source = "git+https://github.com/encounter/rust-sdl2.git?rev=e282ef3acd7fcb4b2ba16863a7a0a7a8439f9335#e282ef3acd7fcb4b2ba16863a7a0a7a8439f9335"
dependencies = [
"cfg-if 1.0.0",
"libc",
"version-compare",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.132" version = "1.0.132"
@ -1703,6 +1725,12 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version-compare"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73"
[[package]] [[package]]
name = "version_check" name = "version_check"
version = "0.9.3" version = "0.9.3"

View File

@ -29,6 +29,8 @@ smallvec = "1.7.0"
scopeguard = "1.1.0" scopeguard = "1.1.0"
twox-hash = "1.6.2" twox-hash = "1.6.2"
winit = "0.26.1" winit = "0.26.1"
# custom sdl2
sdl2 = { git = "https://github.com/encounter/rust-sdl2.git", rev = "e282ef3acd7fcb4b2ba16863a7a0a7a8439f9335", features = ["no-link", "hidapi"] }
[dependencies.imgui] [dependencies.imgui]
git = "https://github.com/imgui-rs/imgui-rs" git = "https://github.com/imgui-rs/imgui-rs"

View File

@ -1,12 +1,14 @@
#pragma once #pragma once
#include <array> #include <array>
#include <cinttypes>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
#include <cinttypes>
namespace aurora { namespace aurora {
enum class SpecialKey : std::uint8_t; enum class SpecialKey : uint8_t;
enum class ControllerButton : uint8_t;
enum class ControllerAxis : uint8_t;
struct WindowSize; struct WindowSize;
@ -24,14 +26,18 @@ struct AppDelegate {
virtual void onAppDraw() noexcept = 0; virtual void onAppDraw() noexcept = 0;
virtual void onAppPostDraw() noexcept = 0; virtual void onAppPostDraw() noexcept = 0;
virtual void onAppWindowResized(const WindowSize& size) noexcept = 0; virtual void onAppWindowResized(const WindowSize& size) noexcept = 0;
virtual void onAppWindowMoved(std::int32_t x, std::int32_t y) noexcept = 0; virtual void onAppWindowMoved(int32_t x, int32_t y) noexcept = 0;
virtual void onAppExiting() noexcept = 0; virtual void onAppExiting() noexcept = 0;
// Input // Input
virtual void onCharKeyDown(std::uint8_t charCode, bool is_repeat) noexcept = 0; virtual void onCharKeyDown(uint8_t charCode, bool isRepeat) noexcept = 0;
virtual void onCharKeyUp(std::uint8_t charCode) noexcept = 0; virtual void onCharKeyUp(uint8_t charCode) noexcept = 0;
virtual void onSpecialKeyDown(const SpecialKey& key, bool is_repeat) noexcept = 0; virtual void onSpecialKeyDown(SpecialKey key, bool isRepeat) noexcept = 0;
virtual void onSpecialKeyUp(const SpecialKey& key) noexcept = 0; virtual void onSpecialKeyUp(SpecialKey key) noexcept = 0;
// Controller
virtual void onControllerButton(uint32_t idx, ControllerButton button, bool pressed) noexcept = 0;
virtual void onControllerAxis(uint32_t idx, ControllerAxis axis, int16_t value) noexcept = 0;
// virtual void resized([[maybe_unused]] const WindowSize& rect, [[maybe_unused]] bool sync) noexcept {} // virtual void resized([[maybe_unused]] const WindowSize& rect, [[maybe_unused]] bool sync) noexcept {}
// virtual void mouseDown([[maybe_unused]] const SWindowCoord& coord, [[maybe_unused]] EMouseButton button, // virtual void mouseDown([[maybe_unused]] const SWindowCoord& coord, [[maybe_unused]] EMouseButton button,

View File

@ -7,11 +7,14 @@ bool App_onAppIdle(AppDelegate& cb, float dt) noexcept;
void App_onAppDraw(AppDelegate& cb) noexcept; void App_onAppDraw(AppDelegate& cb) noexcept;
void App_onAppPostDraw(AppDelegate& cb) noexcept; void App_onAppPostDraw(AppDelegate& cb) noexcept;
void App_onAppWindowResized(AppDelegate& cb, const WindowSize& size) noexcept; void App_onAppWindowResized(AppDelegate& cb, const WindowSize& size) noexcept;
void App_onAppWindowMoved(AppDelegate& cb, std::int32_t x, std::int32_t y) noexcept; void App_onAppWindowMoved(AppDelegate& cb, int32_t x, int32_t y) noexcept;
void App_onAppExiting(AppDelegate& cb) noexcept; void App_onAppExiting(AppDelegate& cb) noexcept;
// Input // Input
void App_onCharKeyDown(AppDelegate& cb, std::uint8_t code, bool is_repeat) noexcept; void App_onCharKeyDown(AppDelegate& cb, uint8_t code, bool isRepeat) noexcept;
void App_onCharKeyUp(AppDelegate& cb, std::uint8_t code) noexcept; void App_onCharKeyUp(AppDelegate& cb, uint8_t code) noexcept;
void App_onSpecialKeyDown(AppDelegate& cb, const SpecialKey& key, bool is_repeat); void App_onSpecialKeyDown(AppDelegate& cb, SpecialKey key, bool isRepeat) noexcept;
void App_onSpecialKeyUp(AppDelegate& cb, const SpecialKey& key); void App_onSpecialKeyUp(AppDelegate& cb, SpecialKey key) noexcept;
// Controller
void App_onControllerButton(AppDelegate& cb, uint32_t idx, ControllerButton button, bool pressed) noexcept;
void App_onControllerAxis(AppDelegate& cb, uint32_t idx, ControllerAxis axis, int16_t value) noexcept;
} // namespace aurora } // namespace aurora

View File

@ -8,22 +8,30 @@ void App_onAppPostDraw(AppDelegate& cb) noexcept { cb.onAppPostDraw(); }
void App_onAppWindowResized(AppDelegate& cb, const WindowSize& size) noexcept { void App_onAppWindowResized(AppDelegate& cb, const WindowSize& size) noexcept {
cb.onAppWindowResized(size); cb.onAppWindowResized(size);
} }
void App_onAppWindowMoved(AppDelegate& cb, std::int32_t x, std::int32_t y) noexcept { void App_onAppWindowMoved(AppDelegate& cb, int32_t x, int32_t y) noexcept {
cb.onAppWindowMoved(x, y); cb.onAppWindowMoved(x, y);
} }
void App_onAppExiting(AppDelegate& cb) noexcept { cb.onAppExiting(); } void App_onAppExiting(AppDelegate& cb) noexcept { cb.onAppExiting(); }
// Input // Input
void App_onCharKeyDown(AppDelegate& cb, std::uint8_t code, bool is_repeat) noexcept { void App_onCharKeyDown(AppDelegate& cb, uint8_t code, bool isRepeat) noexcept {
cb.onCharKeyDown(code, is_repeat); cb.onCharKeyDown(code, isRepeat);
} }
void App_onCharKeyUp(AppDelegate& cb, std::uint8_t code) noexcept { void App_onCharKeyUp(AppDelegate& cb, uint8_t code) noexcept {
cb.onCharKeyUp(code); cb.onCharKeyUp(code);
} }
void App_onSpecialKeyDown(AppDelegate& cb, const SpecialKey& key, bool is_repeat) { void App_onSpecialKeyDown(AppDelegate& cb, SpecialKey key, bool isRepeat) noexcept {
cb.onSpecialKeyDown(key, is_repeat); cb.onSpecialKeyDown(key, isRepeat);
} }
void App_onSpecialKeyUp(AppDelegate& cb, const SpecialKey& key) { void App_onSpecialKeyUp(AppDelegate& cb, SpecialKey key) noexcept {
cb.onSpecialKeyUp(key); cb.onSpecialKeyUp(key);
} }
// Controller
void App_onControllerButton(AppDelegate& cb, uint32_t idx, ControllerButton button, bool pressed) noexcept {
cb.onControllerButton(idx, button, pressed);
}
void App_onControllerAxis(AppDelegate& cb, uint32_t idx, ControllerAxis axis, int16_t value) noexcept {
cb.onControllerAxis(idx, axis, value);
}
} // namespace aurora } // namespace aurora

View File

@ -3,29 +3,32 @@
#![allow(unused_variables)] #![allow(unused_variables)]
#![allow(unused_unsafe)] #![allow(unused_unsafe)]
use std::{collections::HashMap, time::Instant};
use sdl2::{
controller::{Axis, Button, GameController},
event::Event as SDLEvent,
GameControllerSubsystem, Sdl,
};
use wgpu::Backend; use wgpu::Backend;
use winit::{ use winit::{
event::{ElementState, Event, KeyboardInput, WindowEvent}, event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent},
event_loop::ControlFlow, event_loop::ControlFlow,
}; };
use winit::event::VirtualKeyCode;
use std::{num::NonZeroU8, time::Instant, collections::HashMap};
use crate::{ use crate::{
ffi::WindowSize, ffi::{SpecialKey, WindowSize},
gpu::{create_depth_texture, create_render_texture, DeviceHolder, initialize_gpu}, gpu::{create_depth_texture, create_render_texture, initialize_gpu, DeviceHolder},
imgui::{ImGuiState, initialize_imgui}, imgui::{initialize_imgui, ImGuiState},
shaders::render_into_pass, shaders::render_into_pass,
}; };
use crate::ffi::SpecialKey;
mod gpu; mod gpu;
mod imgui; mod imgui;
mod imgui_backend; mod imgui_backend;
mod shaders; mod shaders;
mod zeus;
mod util; mod util;
mod zeus;
#[cxx::bridge(namespace = "aurora")] #[cxx::bridge(namespace = "aurora")]
mod ffi { mod ffi {
@ -46,8 +49,25 @@ mod ffi {
// Input // Input
pub(crate) fn App_onCharKeyDown(cb: Pin<&mut AppDelegate>, code: u8, is_repeat: bool); pub(crate) fn App_onCharKeyDown(cb: Pin<&mut AppDelegate>, code: u8, is_repeat: bool);
pub(crate) fn App_onCharKeyUp(cb: Pin<&mut AppDelegate>, code: u8); pub(crate) fn App_onCharKeyUp(cb: Pin<&mut AppDelegate>, code: u8);
pub(crate) fn App_onSpecialKeyDown(cb: Pin<&mut AppDelegate>, key: &SpecialKey, is_repeat: bool); pub(crate) fn App_onSpecialKeyDown(
pub(crate) fn App_onSpecialKeyUp(cb: Pin<&mut AppDelegate>, key: &SpecialKey); cb: Pin<&mut AppDelegate>,
key: SpecialKey,
is_repeat: bool,
);
pub(crate) fn App_onSpecialKeyUp(cb: Pin<&mut AppDelegate>, key: SpecialKey);
// Controller
pub(crate) fn App_onControllerButton(
cb: Pin<&mut AppDelegate>,
idx: u32,
button: ControllerButton,
pressed: bool,
);
pub(crate) fn App_onControllerAxis(
cb: Pin<&mut AppDelegate>,
idx: u32,
axis: ControllerAxis,
value: i16,
);
} }
pub struct Window { pub struct Window {
@ -118,6 +138,35 @@ mod ffi {
// pub // pub
} }
pub enum ControllerButton {
A,
B,
X,
Y,
Back,
Guide,
Start,
LeftStick,
RightStick,
LeftShoulder,
RightShoulder,
DPadUp,
DPadDown,
DPadLeft,
DPadRight,
Other,
MAX,
}
pub enum ControllerAxis {
LeftX,
LeftY,
RightX,
RightY,
TriggerLeft,
TriggerRight,
MAX,
}
extern "Rust" { extern "Rust" {
type WindowContext; type WindowContext;
type App; type App;
@ -131,11 +180,50 @@ mod ffi {
fn set_fullscreen(v: bool); fn set_fullscreen(v: bool);
} }
} }
impl From<Button> for ffi::ControllerButton {
fn from(button: Button) -> Self {
match button {
Button::A => ffi::ControllerButton::A,
Button::B => ffi::ControllerButton::B,
Button::X => ffi::ControllerButton::X,
Button::Y => ffi::ControllerButton::Y,
Button::Back => ffi::ControllerButton::Back,
Button::Guide => ffi::ControllerButton::Guide,
Button::Start => ffi::ControllerButton::Start,
Button::LeftStick => ffi::ControllerButton::LeftStick,
Button::RightStick => ffi::ControllerButton::RightStick,
Button::LeftShoulder => ffi::ControllerButton::LeftShoulder,
Button::RightShoulder => ffi::ControllerButton::RightShoulder,
Button::DPadUp => ffi::ControllerButton::DPadUp,
Button::DPadDown => ffi::ControllerButton::DPadDown,
Button::DPadLeft => ffi::ControllerButton::DPadLeft,
Button::DPadRight => ffi::ControllerButton::DPadRight,
_ => ffi::ControllerButton::Other,
}
}
}
impl From<Axis> for ffi::ControllerAxis {
fn from(axis: Axis) -> Self {
match axis {
Axis::LeftX => ffi::ControllerAxis::LeftX,
Axis::LeftY => ffi::ControllerAxis::LeftY,
Axis::RightX => ffi::ControllerAxis::RightX,
Axis::RightY => ffi::ControllerAxis::RightY,
Axis::TriggerLeft => ffi::ControllerAxis::TriggerLeft,
Axis::TriggerRight => ffi::ControllerAxis::TriggerRight,
}
}
}
pub struct App { pub struct App {
window: ffi::Window, window: ffi::Window,
gpu: DeviceHolder, gpu: DeviceHolder,
imgui: ImGuiState, imgui: ImGuiState,
// SDL
sdl: Sdl,
sdl_events: sdl2::EventPump,
sdl_controller_sys: GameControllerSubsystem,
sdl_open_controllers: HashMap<u32, GameController>,
} }
pub struct WindowContext { pub struct WindowContext {
@ -152,11 +240,22 @@ fn app_run(mut delegate: cxx::UniquePtr<ffi::AppDelegate>) {
log::info!("Running app"); log::info!("Running app");
let event_loop = winit::event_loop::EventLoop::new(); let event_loop = winit::event_loop::EventLoop::new();
let window = winit::window::WindowBuilder::new().build(&event_loop).unwrap(); let window = winit::window::WindowBuilder::new().build(&event_loop).unwrap();
let sdl = sdl2::init().unwrap();
let sdl_events = sdl.event_pump().unwrap();
let controller = sdl.game_controller().unwrap();
let gpu = initialize_gpu(&window); let gpu = initialize_gpu(&window);
let imgui = initialize_imgui(&window, &gpu); let imgui = initialize_imgui(&window, &gpu);
let mut special_keys_pressed: [bool; 512] = [false; 512]; let mut special_keys_pressed: [bool; 512] = [false; 512];
shaders::construct_state(gpu.device.clone(), gpu.queue.clone(), &gpu.config); shaders::construct_state(gpu.device.clone(), gpu.queue.clone(), &gpu.config);
let app = App { window: ffi::Window { inner: Box::new(WindowContext { window }) }, gpu, imgui}; let app = App {
window: ffi::Window { inner: Box::new(WindowContext { window }) },
gpu,
imgui,
sdl,
sdl_events,
sdl_controller_sys: controller,
sdl_open_controllers: Default::default(),
};
unsafe { unsafe {
APP.replace(app); APP.replace(app);
ffi::App_onAppLaunched(delegate.as_mut().unwrap()); ffi::App_onAppLaunched(delegate.as_mut().unwrap());
@ -173,9 +272,62 @@ fn app_run(mut delegate: cxx::UniquePtr<ffi::AppDelegate>) {
let window_ctx = get_window_context(); let window_ctx = get_window_context();
let gpu = &mut app.gpu; let gpu = &mut app.gpu;
// SDL event loop
for event in app.sdl_events.poll_iter() {
// log::info!("SDL event: {:?}", event);
match event {
SDLEvent::ControllerDeviceAdded { which, .. } => {
match app.sdl_controller_sys.open(which) {
Ok(controller) => {
log::info!("Opened SDL controller \"{}\"", controller.name());
app.sdl_open_controllers.insert(which, controller);
}
Err(err) => {
log::warn!("Failed to open SDL controller {} ({:?})", which, err);
}
}
// TODO app connected event
}
SDLEvent::ControllerDeviceRemoved { which, .. } => {
app.sdl_open_controllers.remove(&which);
// TODO app disconnected event
}
SDLEvent::ControllerButtonDown { which, button, .. } => unsafe {
ffi::App_onControllerButton(
delegate.as_mut().unwrap_unchecked(),
which,
button.into(),
true,
);
},
SDLEvent::ControllerButtonUp { which, button, .. } => unsafe {
ffi::App_onControllerButton(
delegate.as_mut().unwrap_unchecked(),
which,
button.into(),
false,
);
},
SDLEvent::ControllerAxisMotion { which, axis, value, .. } => unsafe {
ffi::App_onControllerAxis(
delegate.as_mut().unwrap_unchecked(),
which,
axis.into(),
value,
);
},
// SDL overrides exit signals
SDLEvent::Quit { .. } => {
*control_flow = ControlFlow::Exit;
return;
}
_ => {}
}
}
// winit event loop
*control_flow = ControlFlow::Poll; *control_flow = ControlFlow::Poll;
match event { match event {
Event::NewEvents(_) => {}
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
return; return;
@ -192,26 +344,21 @@ fn app_run(mut delegate: cxx::UniquePtr<ffi::AppDelegate>) {
&app.gpu.surface_config, &app.gpu.surface_config,
&app.gpu.config, &app.gpu.config,
); );
let window_size = WindowSize {
width: app.gpu.surface_config.width,
height: app.gpu.surface_config.height,
};
unsafe { unsafe {
let window_size = WindowSize { width: app.gpu.surface_config.width, height: app.gpu.surface_config.height }; ffi::App_onAppWindowResized(delegate.as_mut().unwrap_unchecked(), &window_size);
ffi::App_onAppWindowResized(delegate.as_mut().unwrap(), &window_size);
} }
} }
Event::WindowEvent { event: WindowEvent::Moved(loc), .. } => { Event::WindowEvent { event: WindowEvent::Moved(loc), .. } => unsafe {
unsafe { ffi::App_onAppWindowMoved(delegate.as_mut().unwrap_unchecked(), loc.x, loc.y);
ffi::App_onAppWindowMoved(delegate.as_mut().unwrap(), loc.x, loc.y);
}
}
Event::WindowEvent {
event: WindowEvent::KeyboardInput {
input:
KeyboardInput {
scancode,
virtual_keycode: Some(key),
state,
..
}, },
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input: KeyboardInput { scancode, virtual_keycode: Some(key), state, .. },
.. ..
}, },
.. ..
@ -253,18 +400,20 @@ fn app_run(mut delegate: cxx::UniquePtr<ffi::AppDelegate>) {
unsafe { unsafe {
if pressed { if pressed {
ffi::App_onSpecialKeyDown(delegate.as_mut().unwrap(), &special_key, repeat); ffi::App_onSpecialKeyDown(
delegate.as_mut().unwrap_unchecked(),
special_key,
repeat,
);
} else { } else {
ffi::App_onSpecialKeyUp(delegate.as_mut().unwrap(), &special_key); ffi::App_onSpecialKeyUp(
delegate.as_mut().unwrap_unchecked(),
special_key,
);
} }
} }
} }
} }
Event::WindowEvent { .. } => {}
Event::DeviceEvent { .. } => {}
Event::UserEvent(_) => {}
Event::Suspended => {}
Event::Resumed => {}
Event::MainEventsCleared => { Event::MainEventsCleared => {
log::trace!("Requesting redraw"); log::trace!("Requesting redraw");
window_ctx.window.request_redraw(); window_ctx.window.request_redraw();
@ -301,7 +450,7 @@ fn app_run(mut delegate: cxx::UniquePtr<ffi::AppDelegate>) {
#[allow(unused_unsafe)] // rust bug? #[allow(unused_unsafe)] // rust bug?
unsafe { unsafe {
ffi::App_onAppDraw(delegate.as_mut().unwrap()); ffi::App_onAppDraw(delegate.as_mut().unwrap_unchecked());
} }
let fb_view = let fb_view =
@ -357,15 +506,15 @@ fn app_run(mut delegate: cxx::UniquePtr<ffi::AppDelegate>) {
#[allow(unused_unsafe)] // rust bug? #[allow(unused_unsafe)] // rust bug?
unsafe { unsafe {
ffi::App_onAppPostDraw(delegate.as_mut().unwrap()); ffi::App_onAppPostDraw(delegate.as_mut().unwrap_unchecked());
} }
} }
Event::RedrawEventsCleared => {}
Event::LoopDestroyed => unsafe { Event::LoopDestroyed => unsafe {
ffi::App_onAppExiting(delegate.as_mut().unwrap()); ffi::App_onAppExiting(delegate.as_mut().unwrap_unchecked());
APP.take(); APP.take();
return; return;
}, },
_ => {}
} }
imgui.platform.handle_event(imgui.context.io_mut(), &window_ctx.window, &event); imgui.platform.handle_event(imgui.context.io_mut(), &window_ctx.window, &event);

View File

@ -7,16 +7,15 @@ use crate::{
get_app, get_app,
gpu::GraphicsConfig, gpu::GraphicsConfig,
shaders::{ shaders::{
get_combined_matrix,
bind_pipeline, bind_pipeline,
BuiltBuffers, ffi::{CameraFilterType, TextureRef, ZTest},
ffi::{CameraFilterType, TextureRef, ZTest}, pipeline_ref, PipelineCreateCommand, PipelineHolder, PipelineRef, get_combined_matrix, pipeline_ref, push_draw_command, push_uniform, push_verts,
push_draw_command, push_uniform, push_verts, ShaderDrawCommand, STATE, texture::create_sampler,
BuiltBuffers, PipelineCreateCommand, PipelineHolder, PipelineRef, ShaderDrawCommand, STATE,
}, },
util::{align, Vec2, Vec3},
zeus::{CColor, CMatrix4f, CRectangle, CVector2f, CVector3f, CVector4f}, zeus::{CColor, CMatrix4f, CRectangle, CVector2f, CVector3f, CVector4f},
}; };
use crate::shaders::texture::create_sampler;
use crate::util::{align, Vec2, Vec3};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct DrawData { pub(crate) struct DrawData {
@ -56,10 +55,14 @@ pub(crate) fn construct_state(
) -> State { ) -> State {
let shader = device.create_shader_module(&include_wgsl!("shader.wgsl")); let shader = device.create_shader_module(&include_wgsl!("shader.wgsl"));
let uniform_alignment = device.limits().min_uniform_buffer_offset_alignment; let uniform_alignment = device.limits().min_uniform_buffer_offset_alignment;
let uniform_size = wgpu::BufferSize::new(align(std::mem::size_of::<Uniform>() as u64, uniform_alignment as u64)); let uniform_size = wgpu::BufferSize::new(align(
std::mem::size_of::<Uniform>() as u64,
uniform_alignment as u64,
));
let uniform_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let uniform_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Textured Quad Uniform Bind Group Layout"), label: Some("Textured Quad Uniform Bind Group Layout"),
entries: &[wgpu::BindGroupLayoutEntry { entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0, binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer { ty: wgpu::BindingType::Buffer {
@ -68,28 +71,30 @@ pub(crate) fn construct_state(
min_binding_size: uniform_size, min_binding_size: uniform_size,
}, },
count: None, count: None,
}, wgpu::BindGroupLayoutEntry { },
wgpu::BindGroupLayoutEntry {
binding: 1, binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT, visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None, count: None,
}], },
],
}); });
let sampler = create_sampler(device, wgpu::AddressMode::Repeat, None); let sampler = create_sampler(device, wgpu::AddressMode::Repeat, None);
let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Textured Quad Uniform Bind Group"), label: Some("Textured Quad Uniform Bind Group"),
layout: &uniform_layout, layout: &uniform_layout,
entries: &[wgpu::BindGroupEntry { entries: &[
wgpu::BindGroupEntry {
binding: 0, binding: 0,
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &buffers.uniform_buffer, buffer: &buffers.uniform_buffer,
offset: 0, // dynamic offset: 0, // dynamic
size: uniform_size, size: uniform_size,
}), }),
}, wgpu::BindGroupEntry { },
binding: 1, wgpu::BindGroupEntry { binding: 1, resource: wgpu::BindingResource::Sampler(&sampler) },
resource: wgpu::BindingResource::Sampler(&sampler), ],
}],
}); });
let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let texture_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Textured Quad Texture Bind Group Layout"), label: Some("Textured Quad Texture Bind Group Layout"),
@ -170,7 +175,6 @@ pub(crate) fn construct_pipeline(
), ),
_ => todo!(), _ => todo!(),
}; };
log::warn!("VERT SIZE: {}", std::mem::size_of::<Vert>() as u64);
PipelineHolder { PipelineHolder {
pipeline: device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { pipeline: device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Textured Quad Pipeline"), label: Some("Textured Quad Pipeline"),
@ -271,11 +275,37 @@ pub(crate) fn queue_textured_quad(
push_textured_quad(texture, pipeline, vert_range, uniform_range); push_textured_quad(texture, pipeline, vert_range, uniform_range);
} }
pub(crate) fn queue_textured_quad_verts(
filter_type: CameraFilterType,
texture: TextureRef,
z_test: ZTest,
color: CColor,
pos: &[CVector3f],
uvs: &[CVector2f],
lod: f32,
) {
if pos.len() != 4 || uvs.len() != 4 {
panic!("Invalid pos/uv sizes: {}/{}", pos.len(), uvs.len());
}
let pipeline =
pipeline_ref(&PipelineCreateCommand::TexturedQuad(PipelineConfig { filter_type, z_test }));
let vert_range = push_verts(
&pos.iter()
.zip(uvs)
.map(|(pos, uv)| Vert { pos: pos.into(), uv: uv.into() })
.collect::<Vec<Vert>>(),
);
let uniform_range = push_uniform(&Uniform { xf: get_combined_matrix(), color, lod: 0.0 });
push_textured_quad(texture, pipeline, vert_range, uniform_range);
}
fn push_textured_quad( fn push_textured_quad(
texture: TextureRef, texture: TextureRef,
pipeline: PipelineRef, pipeline: PipelineRef,
vert_range: Range<u64>, vert_range: Range<u64>,
uniform_range: Range<u64> uniform_range: Range<u64>,
) { ) {
// TODO defer bind group creation to draw time or another thread? // TODO defer bind group creation to draw time or another thread?
let state = unsafe { STATE.as_mut().unwrap_unchecked() }; let state = unsafe { STATE.as_mut().unwrap_unchecked() };

View File

@ -189,6 +189,14 @@ impl From<CVector2f> for Vec2<f32> {
} }
} }
} }
impl From<&CVector2f> for Vec2<f32> {
fn from(v: &CVector2f) -> Self {
Self {
x: v.x,
y: v.y,
}
}
}
impl From<Vec3<f32>> for CVector3f { impl From<Vec3<f32>> for CVector3f {
fn from(v: Vec3<f32>) -> Self { fn from(v: Vec3<f32>) -> Self {
@ -209,3 +217,12 @@ impl From<CVector3f> for Vec3<f32> {
} }
} }
} }
impl From<&CVector3f> for Vec3<f32> {
fn from(v: &CVector3f) -> Self {
Self {
x: v.x,
y: v.y,
z: v.z,
}
}
}

View File

@ -437,6 +437,19 @@ public:
void onAppWindowMoved(std::int32_t x, std::int32_t y) noexcept override { void onAppWindowMoved(std::int32_t x, std::int32_t y) noexcept override {
// TODO: implement this // TODO: implement this
} }
void onControllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept override {
if (auto* input = g_InputGenerator) {
input->controllerButton(idx, button, pressed);
}
}
void onControllerAxis(uint32_t idx, aurora::ControllerAxis axis, int16_t value) noexcept override {
if (auto* input = g_InputGenerator) {
input->controllerAxis(idx, axis, value);
}
}
void onAppExiting() noexcept override { void onAppExiting() noexcept override {
m_imGuiConsole.Shutdown(); m_imGuiConsole.Shutdown();
if (g_mainMP1) { if (g_mainMP1) {
@ -451,12 +464,12 @@ public:
CDvdFile::Shutdown(); CDvdFile::Shutdown();
} }
void onCharKeyDown(uint8_t code, bool is_repeat) noexcept override { void onCharKeyDown(uint8_t code, bool isRepeat) noexcept override {
Log.report(logvisor::Info, FMT_STRING("DEBUG CHAR KEYS: '{}', is_repeat {}"), static_cast<char>(code), is_repeat); Log.report(logvisor::Info, FMT_STRING("DEBUG CHAR KEYS: '{}', isRepeat {}"), static_cast<char>(code), isRepeat);
// if (!ImGuiWindowCallback::m_keyboardCaptured && g_mainMP1) { // if (!ImGuiWindowCallback::m_keyboardCaptured && g_mainMP1) {
if (g_mainMP1) { if (g_mainMP1) {
if (MP1::CGameArchitectureSupport* as = g_mainMP1->GetArchSupport()) { if (MP1::CGameArchitectureSupport* as = g_mainMP1->GetArchSupport()) {
as->charKeyDown(code, boo::EModifierKey::None, is_repeat); as->charKeyDown(code, boo::EModifierKey::None, isRepeat);
} }
} }
// } // }
@ -471,12 +484,12 @@ public:
} }
} }
void onSpecialKeyDown(const aurora::SpecialKey& key, bool is_repeat) noexcept override { void onSpecialKeyDown(aurora::SpecialKey key, bool isRepeat) noexcept override {
Log.report(logvisor::Info, FMT_STRING("DEBUG KEYS: SpecialKey {}, is_repeat {}"), key, is_repeat); Log.report(logvisor::Info, FMT_STRING("DEBUG KEYS: SpecialKey {}, isRepeat {}"), key, isRepeat);
/* TODO: Temporarily convert the aurora enum to boo's until we refactor everything */ /* TODO: Temporarily convert the aurora enum to boo's until we refactor everything */
if (g_mainMP1) { if (g_mainMP1) {
if (MP1::CGameArchitectureSupport* as = g_mainMP1->GetArchSupport()) { if (MP1::CGameArchitectureSupport* as = g_mainMP1->GetArchSupport()) {
as->specialKeyDown(boo::ESpecialKey(key), boo::EModifierKey::None, is_repeat); as->specialKeyDown(boo::ESpecialKey(key), boo::EModifierKey::None, isRepeat);
} }
} }
// if (True(mods & boo::EModifierKey::Alt)) { // if (True(mods & boo::EModifierKey::Alt)) {
@ -488,7 +501,7 @@ public:
// } // }
} }
void onSpecialKeyUp(const aurora::SpecialKey& key) noexcept override { void onSpecialKeyUp(aurora::SpecialKey key) noexcept override {
/* TODO: Temporarily convert the aurora enum to boo's until we refactor everything */ /* TODO: Temporarily convert the aurora enum to boo's until we refactor everything */
if (g_mainMP1) { if (g_mainMP1) {
if (MP1::CGameArchitectureSupport* as = g_mainMP1->GetArchSupport()) { if (MP1::CGameArchitectureSupport* as = g_mainMP1->GetArchSupport()) {

View File

@ -136,7 +136,7 @@ endfunction()
set(RUNTIME_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set(RUNTIME_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
set(RUNTIME_LIBRARIES ${HECL_APPLICATION_REPS_TARGETS_LIST} RetroDataSpec AssetNameMapNull NESEmulator set(RUNTIME_LIBRARIES ${HECL_APPLICATION_REPS_TARGETS_LIST} RetroDataSpec AssetNameMapNull NESEmulator
libjpeg-turbo jbus kabufuda discord-rpc logvisor OptickCore imgui aurora) libjpeg-turbo jbus kabufuda discord-rpc logvisor OptickCore imgui aurora SDL2-static)
add_runtime_common_library(RuntimeCommon ${RUNTIME_SOURCES_A}) add_runtime_common_library(RuntimeCommon ${RUNTIME_SOURCES_A})
target_include_directories(RuntimeCommon PUBLIC ${RUNTIME_INCLUDES}) target_include_directories(RuntimeCommon PUBLIC ${RUNTIME_INCLUDES})

View File

@ -14,7 +14,7 @@ zeus::CMatrix4f g_PlatformMatrix;
/* used in the original to look up fixed-point dividends on a /* used in the original to look up fixed-point dividends on a
* MIDI-style volume scale (0-127) -> (n/0x8000) */ * MIDI-style volume scale (0-127) -> (n/0x8000) */
static const u16 StaticVolumeLookup[] = { static const std::array<u16, 128> StaticVolumeLookup = {
0x0000, 0x0002, 0x0008, 0x0012, 0x0020, 0x0032, 0x0049, 0x0063, 0x0082, 0x00A4, 0x00CB, 0x00F5, 0x0124, 0x0000, 0x0002, 0x0008, 0x0012, 0x0020, 0x0032, 0x0049, 0x0063, 0x0082, 0x00A4, 0x00CB, 0x00F5, 0x0124,
0x0157, 0x018E, 0x01C9, 0x0208, 0x024B, 0x0292, 0x02DD, 0x032C, 0x037F, 0x03D7, 0x0432, 0x0492, 0x04F5, 0x0157, 0x018E, 0x01C9, 0x0208, 0x024B, 0x0292, 0x02DD, 0x032C, 0x037F, 0x03D7, 0x0432, 0x0492, 0x04F5,
0x055D, 0x05C9, 0x0638, 0x06AC, 0x0724, 0x07A0, 0x0820, 0x08A4, 0x092C, 0x09B8, 0x0A48, 0x0ADD, 0x0B75, 0x055D, 0x05C9, 0x0638, 0x06AC, 0x0724, 0x07A0, 0x0820, 0x08A4, 0x092C, 0x09B8, 0x0A48, 0x0ADD, 0x0B75,

View File

@ -6,16 +6,61 @@ namespace metaforce {
CFinalInput::CFinalInput() = default; CFinalInput::CFinalInput() = default;
CFinalInput::CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput, //CFinalInput::CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput,
// float leftDiv, float rightDiv)
//: x0_dt(dt)
//, x4_controllerIdx(cIdx)
//, x8_anaLeftX(zeus::clamp(-1.0f, data.m_leftStick[0] / 72.0f / leftDiv, 1.0f))
//, xc_anaLeftY(zeus::clamp(-1.0f, data.m_leftStick[1] / 72.0f / leftDiv, 1.0f))
//, x10_anaRightX(zeus::clamp(-1.0f, data.m_rightStick[0] / 59.0f / rightDiv, 1.0f))
//, x14_anaRightY(zeus::clamp(-1.0f, data.m_rightStick[1] / 59.0f / rightDiv, 1.0f))
//, x18_anaLeftTrigger(data.m_analogTriggers[0] * 0.007f)
//, x1c_anaRightTrigger(data.m_analogTriggers[1] * 0.007f)
//, x20_enableAnaLeftXP(DLARight() && !prevInput.DLARight())
//, x20_enableAnaLeftNegXP(DLALeft() && !prevInput.DLALeft())
//, x21_enableAnaLeftYP(DLAUp() && !prevInput.DLAUp())
//, x21_enableAnaLeftNegYP(DLADown() && !prevInput.DLADown())
//, x22_enableAnaRightXP(DRARight() && !prevInput.DRARight())
//, x22_enableAnaRightNegXP(DRALeft() && !prevInput.DRALeft())
//, x23_enableAnaRightYP(DRAUp() && !prevInput.DRAUp())
//, x23_enableAnaRightNegYP(DRADown() && !prevInput.DRADown())
//, x24_anaLeftTriggerP(DLTrigger() && !prevInput.DLTrigger())
//, x28_anaRightTriggerP(DRTrigger() && !prevInput.DRTrigger())
//, x2c_b24_A(data.m_btns & uint16_t(boo::EDolphinControllerButtons::A))
//, x2c_b25_B(data.m_btns & uint16_t(boo::EDolphinControllerButtons::B))
//, x2c_b26_X(data.m_btns & uint16_t(boo::EDolphinControllerButtons::X))
//, x2c_b27_Y(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Y))
//, x2c_b28_Z(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Z))
//, x2c_b29_L(data.m_btns & uint16_t(boo::EDolphinControllerButtons::L))
//, x2c_b30_R(data.m_btns & uint16_t(boo::EDolphinControllerButtons::R))
//, x2c_b31_DPUp(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Up))
//, x2d_b24_DPRight(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Right))
//, x2d_b25_DPDown(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Down))
//, x2d_b26_DPLeft(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Left))
//, x2d_b27_Start(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Start))
//, x2d_b28_PA(DA() && !prevInput.DA())
//, x2d_b29_PB(DB() && !prevInput.DB())
//, x2d_b30_PX(DX() && !prevInput.DX())
//, x2d_b31_PY(DY() && !prevInput.DY())
//, x2e_b24_PZ(DZ() && !prevInput.DZ())
//, x2e_b25_PL(DL() && !prevInput.DL())
//, x2e_b26_PR(DR() && !prevInput.DR())
//, x2e_b27_PDPUp(DDPUp() && !prevInput.DDPUp())
//, x2e_b28_PDPRight(DDPRight() && !prevInput.DDPRight())
//, x2e_b29_PDPDown(DDPDown() && !prevInput.DDPDown())
//, x2e_b30_PDPLeft(DDPLeft() && !prevInput.DDPLeft())
//, x2e_b31_PStart(DStart() && !prevInput.DStart()) {}
CFinalInput::CFinalInput(int cIdx, float dt, const SAuroraControllerState& data, const CFinalInput& prevInput,
float leftDiv, float rightDiv) float leftDiv, float rightDiv)
: x0_dt(dt) : x0_dt(dt)
, x4_controllerIdx(cIdx) , x4_controllerIdx(cIdx)
, x8_anaLeftX(zeus::clamp(-1.0f, data.m_leftStick[0] / 72.0f / leftDiv, 1.0f)) , x8_anaLeftX(zeus::clamp(-1.0f, data.m_axes[size_t(aurora::ControllerAxis::LeftX)] / 72.0f / leftDiv, 1.0f))
, xc_anaLeftY(zeus::clamp(-1.0f, data.m_leftStick[1] / 72.0f / leftDiv, 1.0f)) , xc_anaLeftY(zeus::clamp(-1.0f, data.m_axes[size_t(aurora::ControllerAxis::LeftY)] / 72.0f / leftDiv, 1.0f))
, x10_anaRightX(zeus::clamp(-1.0f, data.m_rightStick[0] / 59.0f / rightDiv, 1.0f)) , x10_anaRightX(zeus::clamp(-1.0f, data.m_axes[size_t(aurora::ControllerAxis::RightX)] / 59.0f / rightDiv, 1.0f))
, x14_anaRightY(zeus::clamp(-1.0f, data.m_rightStick[1] / 59.0f / rightDiv, 1.0f)) , x14_anaRightY(zeus::clamp(-1.0f, data.m_axes[size_t(aurora::ControllerAxis::RightY)] / 59.0f / rightDiv, 1.0f))
, x18_anaLeftTrigger(data.m_analogTriggers[0] * 0.007f) , x18_anaLeftTrigger(data.m_axes[size_t(aurora::ControllerAxis::TriggerLeft)] * 0.007f)
, x1c_anaRightTrigger(data.m_analogTriggers[1] * 0.007f) , x1c_anaRightTrigger(data.m_axes[size_t(aurora::ControllerAxis::TriggerRight)] * 0.007f)
, x20_enableAnaLeftXP(DLARight() && !prevInput.DLARight()) , x20_enableAnaLeftXP(DLARight() && !prevInput.DLARight())
, x20_enableAnaLeftNegXP(DLALeft() && !prevInput.DLALeft()) , x20_enableAnaLeftNegXP(DLALeft() && !prevInput.DLALeft())
, x21_enableAnaLeftYP(DLAUp() && !prevInput.DLAUp()) , x21_enableAnaLeftYP(DLAUp() && !prevInput.DLAUp())
@ -26,18 +71,18 @@ CFinalInput::CFinalInput(int cIdx, float dt, const boo::DolphinControllerState&
, x23_enableAnaRightNegYP(DRADown() && !prevInput.DRADown()) , x23_enableAnaRightNegYP(DRADown() && !prevInput.DRADown())
, x24_anaLeftTriggerP(DLTrigger() && !prevInput.DLTrigger()) , x24_anaLeftTriggerP(DLTrigger() && !prevInput.DLTrigger())
, x28_anaRightTriggerP(DRTrigger() && !prevInput.DRTrigger()) , x28_anaRightTriggerP(DRTrigger() && !prevInput.DRTrigger())
, x2c_b24_A(data.m_btns & uint16_t(boo::EDolphinControllerButtons::A)) , x2c_b24_A(data.m_btns[size_t(aurora::ControllerButton::A)])
, x2c_b25_B(data.m_btns & uint16_t(boo::EDolphinControllerButtons::B)) , x2c_b25_B(data.m_btns[size_t(aurora::ControllerButton::B)])
, x2c_b26_X(data.m_btns & uint16_t(boo::EDolphinControllerButtons::X)) , x2c_b26_X(data.m_btns[size_t(aurora::ControllerButton::X)])
, x2c_b27_Y(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Y)) , x2c_b27_Y(data.m_btns[size_t(aurora::ControllerButton::Y)])
, x2c_b28_Z(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Z)) , x2c_b28_Z(data.m_btns[size_t(aurora::ControllerButton::RightShoulder)])
, x2c_b29_L(data.m_btns & uint16_t(boo::EDolphinControllerButtons::L)) , x2c_b29_L(data.m_axes[size_t(aurora::ControllerAxis::TriggerLeft)] > 29490)
, x2c_b30_R(data.m_btns & uint16_t(boo::EDolphinControllerButtons::R)) , x2c_b30_R(data.m_axes[size_t(aurora::ControllerAxis::TriggerRight)] > 29490)
, x2c_b31_DPUp(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Up)) , x2c_b31_DPUp(data.m_btns[size_t(aurora::ControllerButton::DPadUp)])
, x2d_b24_DPRight(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Right)) , x2d_b24_DPRight(data.m_btns[size_t(aurora::ControllerButton::DPadRight)])
, x2d_b25_DPDown(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Down)) , x2d_b25_DPDown(data.m_btns[size_t(aurora::ControllerButton::DPadDown)])
, x2d_b26_DPLeft(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Left)) , x2d_b26_DPLeft(data.m_btns[size_t(aurora::ControllerButton::DPadLeft)])
, x2d_b27_Start(data.m_btns & uint16_t(boo::EDolphinControllerButtons::Start)) , x2d_b27_Start(data.m_btns[size_t(aurora::ControllerButton::Start)])
, x2d_b28_PA(DA() && !prevInput.DA()) , x2d_b28_PA(DA() && !prevInput.DA())
, x2d_b29_PB(DB() && !prevInput.DB()) , x2d_b29_PB(DB() && !prevInput.DB())
, x2d_b30_PX(DX() && !prevInput.DX()) , x2d_b30_PX(DX() && !prevInput.DX())

View File

@ -2,13 +2,20 @@
#include <array> #include <array>
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Input/CKeyboardMouseController.hpp" #include "Runtime/Input/CKeyboardMouseController.hpp"
#include "Runtime/RetroTypes.hpp"
#include <boo/inputdev/DolphinSmashAdapter.hpp> #include "aurora.h"
//#include <boo/inputdev/DolphinSmashAdapter.hpp>
namespace metaforce { namespace metaforce {
struct SAuroraControllerState {
std::array<int16_t, size_t(aurora::ControllerAxis::MAX)> m_axes{};
std::bitset<size_t(aurora::ControllerButton::MAX)> m_btns{};
};
struct CFinalInput { struct CFinalInput {
float x0_dt = 0.0f; float x0_dt = 0.0f;
u32 x4_controllerIdx = 0; u32 x4_controllerIdx = 0;
@ -72,7 +79,9 @@ struct CFinalInput {
float m_rightMul = 1.f; float m_rightMul = 1.f;
CFinalInput(); CFinalInput();
CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput, float leftDiv, // CFinalInput(int cIdx, float dt, const boo::DolphinControllerState& data, const CFinalInput& prevInput, float leftDiv,
// float rightDiv);
CFinalInput(int cIdx, float dt, const SAuroraControllerState& data, const CFinalInput& prevInput, float leftDiv,
float rightDiv); float rightDiv);
CFinalInput(int cIdx, float dt, const CKeyboardMouseControllerData& data, const CFinalInput& prevInput); CFinalInput(int cIdx, float dt, const CKeyboardMouseControllerData& data, const CFinalInput& prevInput);

View File

@ -11,33 +11,31 @@ void CInputGenerator::Update(float dt, CArchitectureQueue& queue) {
return; return;
} }
/* Keyboard/Mouse first */ const CFinalInput& kbInput = getFinalInput(0, dt);
CFinalInput kbInput = getFinalInput(0, dt); queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, kbInput));
bool kbUsed = false;
/* Dolphin controllers next */ /* Dolphin controllers next */
for (int i = 0; i < 4; ++i) { // for (int i = 0; i < 4; ++i) {
bool connected; // bool connected;
EStatusChange change = m_dolphinCb.getStatusChange(i, connected); // EStatusChange change = m_dolphinCb.getStatusChange(i, connected);
if (change != EStatusChange::NoChange) // if (change != EStatusChange::NoChange)
queue.Push(MakeMsg::CreateControllerStatus(EArchMsgTarget::Game, i, connected)); // queue.Push(MakeMsg::CreateControllerStatus(EArchMsgTarget::Game, i, connected));
if (connected) { // if (connected) {
CFinalInput input = m_dolphinCb.getFinalInput(i, dt, m_leftDiv, m_rightDiv); // CFinalInput input = m_dolphinCb.getFinalInput(i, dt, m_leftDiv, m_rightDiv);
if (i == 0) /* Merge KB input with first controller */ // if (i == 0) /* Merge KB input with first controller */
{ // {
input |= kbInput; // input |= kbInput;
kbUsed = true; // kbUsed = true;
} // }
m_lastUpdate = input; // m_lastUpdate = input;
queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, input)); // queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, input));
} // }
} // }
/* Send straight keyboard input if no first controller present */ // /* Send straight keyboard input if no first controller present */
if (!kbUsed) { // if (!kbUsed) {
m_lastUpdate = kbInput; // m_lastUpdate = kbInput;
queue.Push(MakeMsg::CreateUserInput(EArchMsgTarget::Game, kbInput)); // }
}
} }
} // namespace metaforce } // namespace metaforce

View File

@ -16,7 +16,7 @@ enum class EIOPort { Zero, One, Two, Three };
enum class EMotorState { Stop, Rumble, StopHard }; enum class EMotorState { Stop, Rumble, StopHard };
class CInputGenerator : public boo::DeviceFinder { class CInputGenerator /*: public boo::DeviceFinder*/ {
enum class EStatusChange { NoChange = 0, Connected = 1, Disconnected = 2 }; enum class EStatusChange { NoChange = 0, Connected = 1, Disconnected = 2 };
/* When the sticks are used as logical (digital) input, /* When the sticks are used as logical (digital) input,
@ -25,10 +25,14 @@ class CInputGenerator : public boo::DeviceFinder {
float m_leftDiv; float m_leftDiv;
float m_rightDiv; float m_rightDiv;
CKeyboardMouseControllerData m_data; CKeyboardMouseControllerData m_data;
SAuroraControllerState m_state;
CFinalInput m_lastUpdate; CFinalInput m_lastUpdate;
const CFinalInput& getFinalInput(unsigned idx, float dt) { const CFinalInput& getFinalInput(unsigned idx, float dt) {
m_lastUpdate = CFinalInput(idx, dt, m_data, m_lastUpdate); auto input = CFinalInput(idx, dt, m_data, m_lastUpdate);
// Merge controller input with kb/m input
input |= CFinalInput(idx, dt, m_state, m_lastUpdate, m_leftDiv, m_rightDiv);
m_lastUpdate = input;
return m_lastUpdate; return m_lastUpdate;
} }
@ -36,13 +40,22 @@ class CInputGenerator : public boo::DeviceFinder {
public: public:
CInputGenerator(float leftDiv, float rightDiv) CInputGenerator(float leftDiv, float rightDiv)
: boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}), m_leftDiv(leftDiv), m_rightDiv(rightDiv) {} : /*boo::DeviceFinder({dev_typeid(DolphinSmashAdapter)}),*/ m_leftDiv(leftDiv), m_rightDiv(rightDiv) {}
~CInputGenerator() override { // ~CInputGenerator() override {
if (smashAdapter) { // if (smashAdapter) {
smashAdapter->setCallback(nullptr); // smashAdapter->setCallback(nullptr);
smashAdapter->closeDevice(); // smashAdapter->closeDevice();
// }
// }
void controllerButton(uint32_t idx, aurora::ControllerButton button, bool pressed) noexcept {
// TODO check idx
m_state.m_btns.set(size_t(button), pressed);
} }
void controllerAxis(uint32_t idx, aurora::ControllerAxis axis, int16_t value) noexcept {
// TODO check idx
m_state.m_axes[size_t(axis)] = value;
} }
/* Keyboard and mouse events are delivered on the main game /* Keyboard and mouse events are delivered on the main game
@ -79,103 +92,77 @@ public:
void reset() { m_data.m_accumScroll.zeroOut(); } void reset() { m_data.m_accumScroll.zeroOut(); }
/* Input via the smash adapter is received asynchronously on a USB // /* Input via the smash adapter is received asynchronously on a USB
* report thread. This class atomically exchanges that data to the // * report thread. This class atomically exchanges that data to the
* game thread as needed */ // * game thread as needed */
struct DolphinSmashAdapterCallback : boo::IDolphinSmashAdapterCallback { // struct DolphinSmashAdapterCallback : boo::IDolphinSmashAdapterCallback {
std::array<std::atomic<EStatusChange>, 4> m_statusChanges; // std::array<std::atomic<EStatusChange>, 4> m_statusChanges;
std::array<bool, 4> m_connected{}; // std::array<bool, 4> m_connected{};
std::array<boo::DolphinControllerState, 4> m_states; // std::array<boo::DolphinControllerState, 4> m_states;
std::mutex m_stateLock; // std::mutex m_stateLock;
void controllerConnected(unsigned idx, boo::EDolphinControllerType) override { // void controllerConnected(unsigned idx, boo::EDolphinControllerType) override {
/* Controller thread */ // /* Controller thread */
m_statusChanges[idx].store(EStatusChange::Connected); // m_statusChanges[idx].store(EStatusChange::Connected);
} // }
void controllerDisconnected(unsigned idx) override { // void controllerDisconnected(unsigned idx) override {
/* Controller thread */ // /* Controller thread */
std::unique_lock lk{m_stateLock}; // std::unique_lock lk{m_stateLock};
m_statusChanges[idx].store(EStatusChange::Disconnected); // m_statusChanges[idx].store(EStatusChange::Disconnected);
m_states[idx].reset(); // m_states[idx].reset();
} // }
void controllerUpdate(unsigned idx, boo::EDolphinControllerType, // void controllerUpdate(unsigned idx, boo::EDolphinControllerType,
const boo::DolphinControllerState& state) override { // const boo::DolphinControllerState& state) override {
/* Controller thread */ // /* Controller thread */
std::unique_lock lk{m_stateLock}; // std::unique_lock lk{m_stateLock};
m_states[idx] = state; // m_states[idx] = state;
} // }
//
// std::array<CFinalInput, 4> m_lastUpdates;
// const CFinalInput& getFinalInput(unsigned idx, float dt, float leftDiv, float rightDiv) {
// /* Game thread */
// std::unique_lock lk{m_stateLock};
// boo::DolphinControllerState state = m_states[idx];
// lk.unlock();
// state.clamp(); /* PADClamp equivalent */
// m_lastUpdates[idx] = CFinalInput(idx, dt, state, m_lastUpdates[idx], leftDiv, rightDiv);
// return m_lastUpdates[idx];
// }
// EStatusChange getStatusChange(unsigned idx, bool& connected) {
// /* Game thread */
// EStatusChange ch = m_statusChanges[idx].exchange(EStatusChange::NoChange);
// if (ch == EStatusChange::Connected)
// m_connected[idx] = true;
// else if (ch == EStatusChange::Disconnected)
// m_connected[idx] = false;
// connected = m_connected[idx];
// return ch;
// }
// } m_dolphinCb;
std::array<CFinalInput, 4> m_lastUpdates; // /* Device connection/disconnection events are handled on a separate thread
const CFinalInput& getFinalInput(unsigned idx, float dt, float leftDiv, float rightDiv) { // * using the relevant OS API. This thread blocks in a loop until an event is
/* Game thread */ // * received. Device pointers should only be manipulated by this thread using
std::unique_lock lk{m_stateLock}; // * the deviceConnected() and deviceDisconnected() callbacks. */
boo::DolphinControllerState state = m_states[idx]; // std::shared_ptr<boo::DolphinSmashAdapter> smashAdapter;
lk.unlock(); // void deviceConnected(boo::DeviceToken& tok) override {
state.clamp(); /* PADClamp equivalent */ // /* Device listener thread */
m_lastUpdates[idx] = CFinalInput(idx, dt, state, m_lastUpdates[idx], leftDiv, rightDiv); // if (!smashAdapter) {
return m_lastUpdates[idx]; // auto dev = tok.openAndGetDevice();
} // if (dev && dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) {
EStatusChange getStatusChange(unsigned idx, bool& connected) { // smashAdapter = std::static_pointer_cast<boo::DolphinSmashAdapter>(tok.openAndGetDevice());
/* Game thread */ // smashAdapter->setCallback(&m_dolphinCb);
EStatusChange ch = m_statusChanges[idx].exchange(EStatusChange::NoChange); // }
if (ch == EStatusChange::Connected) // }
m_connected[idx] = true; // }
else if (ch == EStatusChange::Disconnected) // void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override {
m_connected[idx] = false; // if (smashAdapter.get() == device)
connected = m_connected[idx]; // smashAdapter.reset();
return ch; // }
}
} m_dolphinCb;
/* Device connection/disconnection events are handled on a separate thread
* using the relevant OS API. This thread blocks in a loop until an event is
* received. Device pointers should only be manipulated by this thread using
* the deviceConnected() and deviceDisconnected() callbacks. */
std::shared_ptr<boo::DolphinSmashAdapter> smashAdapter;
void deviceConnected(boo::DeviceToken& tok) override {
/* Device listener thread */
if (!smashAdapter) {
auto dev = tok.openAndGetDevice();
if (dev && dev->getTypeHash() == dev_typeid(DolphinSmashAdapter)) {
smashAdapter = std::static_pointer_cast<boo::DolphinSmashAdapter>(tok.openAndGetDevice());
smashAdapter->setCallback(&m_dolphinCb);
}
}
}
void deviceDisconnected(boo::DeviceToken&, boo::DeviceBase* device) override {
if (smashAdapter.get() == device)
smashAdapter.reset();
}
void SetMotorState(EIOPort port, EMotorState state) { void SetMotorState(EIOPort port, EMotorState state) {
if (smashAdapter) { // TODO aurora
switch (state) {
case EMotorState::Stop:
smashAdapter->stopRumble(unsigned(port));
break;
case EMotorState::Rumble:
smashAdapter->startRumble(unsigned(port));
break;
case EMotorState::StopHard:
smashAdapter->stopRumble(unsigned(port), true);
break;
}
}
} }
void ControlAllMotors(const std::array<EMotorState, 4>& states) { void ControlAllMotors(const std::array<EMotorState, 4>& states) {
if (smashAdapter) { // TODO aurora
for (size_t i = 0; i < states.size(); ++i) {
switch (states[i]) {
case EMotorState::Stop:
smashAdapter->stopRumble(i);
break;
case EMotorState::Rumble:
smashAdapter->startRumble(i);
break;
case EMotorState::StopHard:
smashAdapter->stopRumble(i, true);
break;
}
}
}
} }
/* This is where the game thread enters */ /* This is where the game thread enters */

View File

@ -100,7 +100,7 @@ CGameArchitectureSupport::CGameArchitectureSupport(CMain& parent, boo::IAudioVoi
, x44_guiSys(*g_ResFactory, *g_SimplePool, CGuiSys::EUsageMode::Zero) { , x44_guiSys(*g_ResFactory, *g_SimplePool, CGuiSys::EUsageMode::Zero) {
auto* m = static_cast<CMain*>(g_Main); auto* m = static_cast<CMain*>(g_Main);
x30_inputGenerator.startScanning(); // x30_inputGenerator.startScanning();
g_InputGenerator = &x30_inputGenerator; g_InputGenerator = &x30_inputGenerator;
CAudioSys::SysSetVolume(0x7f); CAudioSys::SysSetVolume(0x7f);

1
extern/SDL vendored Submodule

@ -0,0 +1 @@
Subproject commit 53091e36a3b418e33133bae2f018954c006f86b8