mirror of
https://github.com/JanNeuendorf/SVC16.git
synced 2025-06-03 01:50:18 +00:00
Macroquad port (#10)
I ported the gui to the macroquad crate. This has the following advantages: We can easily draw text. This means we can show the number of instructions on screen. The filter mode can be set to linear for a different look. The dependencies are a lot cleaner now. Just depending on the latest stable version of macroquad makes it a lot more likely that the app builds properly on different platforms (and will continue to do so in the future). I also use the gilrs crate directly for the gamepad input.
This commit is contained in:
parent
24c192f129
commit
6abfcbc811
2288
Cargo.lock
generated
2288
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "svc16"
|
||||
version = "0.7.3"
|
||||
version = "0.8.0"
|
||||
edition = "2021"
|
||||
authors = ["Jan Neuendorf"]
|
||||
description = "An emulator for a simple virtual computer"
|
||||
@ -11,13 +11,9 @@ anyhow = "1.0.93"
|
||||
clap = { version = "4.5.21", features = ["derive"] }
|
||||
flate2 = "1.0.35"
|
||||
gilrs = { version = "0.11.0",optional=true}
|
||||
# There seems to be some incompatibility with the latest crates.io version of pixels?
|
||||
pixels = { git = "https://github.com/parasyte/pixels.git", rev = "d4df286"}
|
||||
macroquad = "0.4.13"
|
||||
thiserror = "2.0.3"
|
||||
winit = "0.29.15"
|
||||
winit-input-map = {version="0.4.1",optional=true}
|
||||
winit_input_helper = "0.16.0"
|
||||
|
||||
[features]
|
||||
default=[]
|
||||
gamepad = ["gilrs","winit-input-map"]
|
||||
gamepad = ["gilrs"]
|
||||
|
12
src/cli.rs
12
src/cli.rs
@ -7,7 +7,7 @@ pub struct Cli {
|
||||
pub program: String,
|
||||
|
||||
#[arg(short, long, default_value = "1", help = "Set initial window scaling")]
|
||||
pub scaling: u32,
|
||||
pub scaling: i32,
|
||||
|
||||
#[arg(
|
||||
short,
|
||||
@ -27,14 +27,14 @@ pub struct Cli {
|
||||
short,
|
||||
long,
|
||||
default_value_t = false,
|
||||
help = "Output performance metrics"
|
||||
help = "Show performance metrics"
|
||||
)]
|
||||
pub verbose: bool,
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
default_value = "3000000",
|
||||
help = "Change the maximum instructions per frame"
|
||||
short,
|
||||
default_value_t = false,
|
||||
help = "Use linear filtering (instead of pixel-perfect) this enables fractional scaling"
|
||||
)]
|
||||
pub max_ipf: usize,
|
||||
pub linear_filtering: bool,
|
||||
}
|
||||
|
232
src/main.rs
232
src/main.rs
@ -1,138 +1,148 @@
|
||||
mod cli;
|
||||
mod engine;
|
||||
mod ui;
|
||||
mod utils;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
#[allow(unused)]
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use clap::Parser;
|
||||
use cli::Cli;
|
||||
use engine::Engine;
|
||||
#[cfg(feature = "gamepad")]
|
||||
use gilrs::Gilrs;
|
||||
use pixels::{Pixels, SurfaceTexture};
|
||||
use macroquad::prelude::*;
|
||||
use std::time::{Duration, Instant};
|
||||
use ui::Layout;
|
||||
use utils::*;
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event_loop::EventLoop;
|
||||
use winit::keyboard::{Key, KeyCode};
|
||||
use winit::window::WindowBuilder;
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
const RES: usize = 256;
|
||||
const MAX_IPF: usize = 3000000;
|
||||
const FRAMETIME: Duration = Duration::from_nanos((1000000000. / 30.) as u64);
|
||||
|
||||
fn main() -> Result<()> {
|
||||
fn window_conf() -> Conf {
|
||||
let cli = Cli::parse();
|
||||
#[cfg(feature = "gamepad")]
|
||||
let mut girls = Gilrs::new().expect("Could not read gamepad inputs.");
|
||||
if cli.fullscreen {}
|
||||
|
||||
Conf {
|
||||
window_title: "SVC16".to_owned(),
|
||||
window_width: 256 * cli.scaling,
|
||||
window_height: 256 * cli.scaling,
|
||||
fullscreen: cli.fullscreen,
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
#[macroquad::main(window_conf)]
|
||||
async fn main() -> Result<()> {
|
||||
let mut cli = Cli::parse();
|
||||
|
||||
let mut buffer = [Color::from_rgba(255, 255, 255, 255); 256 * 256];
|
||||
let mut image = Image::gen_image_color(256, 256, Color::from_rgba(0, 0, 0, 255));
|
||||
let texture = Texture2D::from_image(&image);
|
||||
if cli.linear_filtering {
|
||||
texture.set_filter(FilterMode::Linear);
|
||||
} else {
|
||||
texture.set_filter(FilterMode::Nearest);
|
||||
}
|
||||
|
||||
let mut raw_buffer = [0 as u16; 256 * 256];
|
||||
let initial_state = read_u16s_from_file(&cli.program)?;
|
||||
// The initial state is cloned, so we keep it around for a restart.
|
||||
let mut engine = Engine::new(initial_state.clone());
|
||||
|
||||
let event_loop = EventLoop::new()?;
|
||||
let mut input = WinitInputHelper::new();
|
||||
#[cfg(feature = "gamepad")]
|
||||
let mut gamepad = build_gamepad_map();
|
||||
if cli.scaling < 1 {
|
||||
return Err(anyhow!("The minimal scaling factor is 1"));
|
||||
}
|
||||
let window = {
|
||||
let size = LogicalSize::new(
|
||||
(RES as u32 * cli.scaling) as f64,
|
||||
(RES as u32 * cli.scaling) as f64,
|
||||
);
|
||||
let min_size = LogicalSize::new((RES) as f64, (RES) as f64);
|
||||
WindowBuilder::new()
|
||||
.with_title("SVC16")
|
||||
.with_inner_size(size)
|
||||
.with_min_inner_size(min_size)
|
||||
.build(&event_loop)?
|
||||
};
|
||||
window.set_cursor_visible(cli.cursor);
|
||||
if cli.fullscreen {
|
||||
window.set_fullscreen(Some(winit::window::Fullscreen::Borderless(None)));
|
||||
}
|
||||
let mut pixels = {
|
||||
let window_size = window.inner_size();
|
||||
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
|
||||
Pixels::new(RES as u32, RES as u32, surface_texture)?
|
||||
};
|
||||
|
||||
let mut raw_buffer = [0 as u16; engine::MEMSIZE];
|
||||
let mut paused = false;
|
||||
let mut ipf = 0;
|
||||
|
||||
event_loop.run(|event, elwt| {
|
||||
#[cfg(feature = "gamepad")]
|
||||
let mut gilrs = match Gilrs::new() {
|
||||
Ok(g) => g,
|
||||
_ => return Err(anyhow!("Gamepad could not be loaded")),
|
||||
};
|
||||
|
||||
loop {
|
||||
let start_time = Instant::now();
|
||||
if input.update(&event) {
|
||||
if input.key_pressed(KeyCode::Escape) || input.close_requested() {
|
||||
elwt.exit();
|
||||
return;
|
||||
}
|
||||
if input.key_pressed_logical(Key::Character("p")) {
|
||||
paused = !paused;
|
||||
if paused {
|
||||
window.set_title("SVC16 (paused)");
|
||||
} else {
|
||||
window.set_title("SVC16");
|
||||
}
|
||||
}
|
||||
if input.key_pressed_logical(Key::Character("r")) {
|
||||
engine = Engine::new(initial_state.clone());
|
||||
paused = false;
|
||||
}
|
||||
if is_key_pressed(KeyCode::Escape) {
|
||||
break;
|
||||
}
|
||||
if is_key_pressed(KeyCode::P) {
|
||||
paused = !paused;
|
||||
}
|
||||
if is_key_pressed(KeyCode::R) {
|
||||
engine = Engine::new(initial_state.clone());
|
||||
paused = false;
|
||||
}
|
||||
if is_key_pressed(KeyCode::V) {
|
||||
cli.verbose = !cli.verbose;
|
||||
}
|
||||
if is_key_pressed(KeyCode::C) {
|
||||
cli.cursor = !cli.cursor;
|
||||
}
|
||||
|
||||
if let Some(size) = input.window_resized() {
|
||||
if let Err(_) = pixels.resize_surface(size.width, size.height) {
|
||||
handle_event_loop_error(&elwt, "Resize error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let mut ipf = 0;
|
||||
let engine_start = Instant::now();
|
||||
while !engine.wants_to_sync() && ipf <= cli.max_ipf && !paused {
|
||||
match engine.step() {
|
||||
Err(e) => {
|
||||
handle_event_loop_error(
|
||||
&elwt,
|
||||
format!("{} (after {} instructions)", e, ipf),
|
||||
);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let layout = Layout::generate(cli.linear_filtering);
|
||||
if !paused {
|
||||
ipf = 0;
|
||||
while !engine.wants_to_sync() && ipf <= MAX_IPF {
|
||||
engine.step()?;
|
||||
ipf += 1;
|
||||
}
|
||||
let engine_elapsed = engine_start.elapsed();
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
while let Some(event) = gilrs.next_event() {
|
||||
gilrs.update(&event);
|
||||
}
|
||||
#[cfg(not(feature = "gamepad"))]
|
||||
let (c1, c2) = get_input_code(&input, &pixels);
|
||||
#[cfg(feature = "gamepad")]
|
||||
gamepad.update_with_gilrs(&mut girls);
|
||||
#[cfg(feature = "gamepad")]
|
||||
let (c1, c2) = get_input_code_gamepad(&input, &gamepad, &pixels);
|
||||
engine.perform_sync(c1, c2, &mut raw_buffer);
|
||||
update_image_buffer(pixels.frame_mut(), &raw_buffer);
|
||||
let (mpos, keycode) = get_input_code_no_gamepad(&layout);
|
||||
|
||||
let elapsed = start_time.elapsed();
|
||||
if cli.verbose {
|
||||
println!(
|
||||
"Instructions: {} Frametime: {}ms (Engine only: {}ms)",
|
||||
ipf,
|
||||
elapsed.as_millis(),
|
||||
engine_elapsed.as_millis()
|
||||
);
|
||||
}
|
||||
if elapsed < FRAMETIME {
|
||||
std::thread::sleep(FRAMETIME - elapsed);
|
||||
}
|
||||
window.request_redraw();
|
||||
match pixels.render() {
|
||||
Err(_) => {
|
||||
handle_event_loop_error(&elwt, "Rendering error");
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
#[cfg(feature = "gamepad")]
|
||||
let (mpos, keycode) = get_input_code_gamepad(&layout, &gilrs);
|
||||
|
||||
engine.perform_sync(mpos, keycode, &mut raw_buffer);
|
||||
update_image_buffer(&mut buffer, &raw_buffer);
|
||||
image.update(&buffer);
|
||||
texture.update(&image);
|
||||
}
|
||||
})?;
|
||||
clear_background(BLACK);
|
||||
|
||||
if layout.cursor_in_window() {
|
||||
show_mouse(cli.cursor);
|
||||
} else {
|
||||
show_mouse(true);
|
||||
}
|
||||
|
||||
draw_texture_ex(
|
||||
&texture,
|
||||
layout.x,
|
||||
layout.y,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(layout.size, layout.size)),
|
||||
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
if cli.verbose {
|
||||
draw_rectangle(
|
||||
layout.rect_x,
|
||||
layout.rect_y,
|
||||
0.25 * layout.size,
|
||||
layout.font_size,
|
||||
Color::from_rgba(0, 0, 0, 200),
|
||||
);
|
||||
|
||||
draw_text(
|
||||
&format!("{}", ipf),
|
||||
layout.font_x,
|
||||
layout.font_y,
|
||||
layout.font_size,
|
||||
LIME,
|
||||
);
|
||||
}
|
||||
|
||||
// Wait for the next frame
|
||||
let elapsed = start_time.elapsed();
|
||||
if elapsed < FRAMETIME {
|
||||
std::thread::sleep(FRAMETIME - elapsed);
|
||||
} else {
|
||||
if cli.verbose {
|
||||
println!("Frame was not processed in time");
|
||||
}
|
||||
}
|
||||
next_frame().await;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
47
src/ui.rs
Normal file
47
src/ui.rs
Normal file
@ -0,0 +1,47 @@
|
||||
use macroquad::prelude::*;
|
||||
pub struct Layout {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub size: f32,
|
||||
pub font_y: f32,
|
||||
pub font_x: f32,
|
||||
pub rect_x: f32,
|
||||
pub rect_y: f32,
|
||||
pub font_size: f32,
|
||||
}
|
||||
impl Layout {
|
||||
pub fn generate(linear: bool) -> Self {
|
||||
let (width, height) = (screen_width(), screen_height());
|
||||
let minsize = width.min(height);
|
||||
let image_size = match linear {
|
||||
false => ((minsize / 256.).floor() * 256.).max(256.),
|
||||
true => minsize.max(256.),
|
||||
};
|
||||
let x = (0. as f32).max((width - image_size) / 2.);
|
||||
let y = (0. as f32).max((height - image_size) / 2.);
|
||||
let font_y = y + image_size / 15.;
|
||||
Self {
|
||||
x,
|
||||
y,
|
||||
size: image_size,
|
||||
font_y,
|
||||
font_x: x + 0.01 * image_size,
|
||||
rect_x: x + 0.005 * image_size,
|
||||
rect_y: y + 0.01 * image_size,
|
||||
font_size: image_size / 15.,
|
||||
}
|
||||
}
|
||||
pub fn clamp_mouse(&self) -> (f32, f32) {
|
||||
let (raw_x, raw_y) = mouse_position();
|
||||
let clamped_x = (raw_x.clamp(self.x, self.x + self.size) - self.x) / self.size * 255.;
|
||||
let clamped_y = (raw_y.clamp(self.y, self.y + self.size) - self.y) / self.size * 255.;
|
||||
(clamped_x, clamped_y)
|
||||
}
|
||||
pub fn cursor_in_window(&self) -> bool {
|
||||
let mp = mouse_position();
|
||||
mp.0 >= self.x
|
||||
&& mp.0 < (self.x + self.size)
|
||||
&& mp.1 >= self.y
|
||||
&& mp.1 < (self.y + self.size)
|
||||
}
|
||||
}
|
201
src/utils.rs
201
src/utils.rs
@ -1,61 +1,14 @@
|
||||
use std::io::Read;
|
||||
|
||||
use crate::RES;
|
||||
#[allow(unused)]
|
||||
use crate::ui::Layout;
|
||||
use anyhow::Result;
|
||||
use flate2::read::GzDecoder;
|
||||
use pixels::Pixels;
|
||||
use macroquad::color::Color;
|
||||
use macroquad::prelude::*;
|
||||
use std::fs::File;
|
||||
use winit::{
|
||||
event::MouseButton,
|
||||
event_loop::EventLoopWindowTarget,
|
||||
keyboard::{Key, KeyCode},
|
||||
};
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
use std::io::Read;
|
||||
const RES: usize = 256;
|
||||
#[cfg(feature = "gamepad")]
|
||||
use winit_input_map::{input_map, GamepadAxis, GamepadButton, InputCode, InputMap};
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
#[derive(Debug, std::hash::Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum NesInput {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
A,
|
||||
B,
|
||||
Start,
|
||||
Select,
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub fn build_gamepad_map() -> InputMap<NesInput> {
|
||||
input_map!(
|
||||
(NesInput::A, GamepadButton::East),
|
||||
(NesInput::B, GamepadButton::South),
|
||||
(NesInput::Select, GamepadButton::Select),
|
||||
(NesInput::Start, GamepadButton::Start),
|
||||
(
|
||||
NesInput::Up,
|
||||
GamepadButton::DPadUp,
|
||||
InputCode::gamepad_axis_pos(GamepadAxis::LeftStickY)
|
||||
),
|
||||
(
|
||||
NesInput::Down,
|
||||
GamepadButton::DPadDown,
|
||||
InputCode::gamepad_axis_neg(GamepadAxis::LeftStickY)
|
||||
),
|
||||
(
|
||||
NesInput::Left,
|
||||
GamepadButton::DPadLeft,
|
||||
InputCode::gamepad_axis_neg(GamepadAxis::LeftStickX)
|
||||
),
|
||||
(
|
||||
NesInput::Right,
|
||||
GamepadButton::DPadRight,
|
||||
InputCode::gamepad_axis_pos(GamepadAxis::LeftStickX)
|
||||
)
|
||||
)
|
||||
}
|
||||
use gilrs::{Axis, Button, Gilrs};
|
||||
|
||||
pub fn read_u16s_from_file(file_path: &str) -> Result<Vec<u16>> {
|
||||
let mut file = File::open(file_path)?;
|
||||
@ -86,110 +39,116 @@ fn rgb565_to_argb(rgb565: u16) -> (u8, u8, u8) {
|
||||
(r, g, b)
|
||||
}
|
||||
|
||||
pub fn update_image_buffer(imbuff: &mut [u8], screen: &[u16; RES * RES]) {
|
||||
pub fn update_image_buffer(imbuff: &mut [Color; RES * RES], screen: &[u16; RES * RES]) {
|
||||
for i in 0..RES * RES {
|
||||
let col = rgb565_to_argb(screen[i]);
|
||||
*imbuff.get_mut(4 * i).expect("Error with image buffer") = col.0;
|
||||
*imbuff.get_mut(4 * i + 1).expect("Error with image buffer") = col.1;
|
||||
*imbuff.get_mut(4 * i + 2).expect("Error with image buffer") = col.2;
|
||||
*imbuff.get_mut(4 * i + 3).expect("Error with image buffer") = 255;
|
||||
imbuff[i] = Color {
|
||||
r: col.0 as f32 / 255.,
|
||||
g: col.1 as f32 / 255.,
|
||||
b: col.2 as f32 / 255.,
|
||||
a: 1.,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gamepad")]
|
||||
pub fn get_input_code_gamepad(
|
||||
input: &WinitInputHelper,
|
||||
gamepad: &InputMap<NesInput>,
|
||||
pxls: &Pixels,
|
||||
) -> (u16, u16) {
|
||||
let raw_mp = input.cursor().unwrap_or((0., 0.));
|
||||
let mp = match pxls.window_pos_to_pixel(raw_mp) {
|
||||
Ok(p) => p,
|
||||
Err(ev) => pxls.clamp_pixel_pos(ev),
|
||||
};
|
||||
let pos_code = (mp.1 as u16 * 256) + mp.0 as u16;
|
||||
pub fn get_input_code_gamepad(layout: &Layout, gilrs: &Gilrs) -> (u16, u16) {
|
||||
#[cfg(not(feature = "gamepad"))]
|
||||
return get_input_code_no_gamepad();
|
||||
let mut key_code = 0_u16;
|
||||
if input.key_held(KeyCode::Space)
|
||||
|| input.mouse_held(MouseButton::Left)
|
||||
|| gamepad.pressing(NesInput::A)
|
||||
let mp = layout.clamp_mouse();
|
||||
let pos_code = (mp.1 as u16 * 256) + mp.0 as u16;
|
||||
let Some(gamepad) = gilrs.gamepads().next().map(|t| t.1) else {
|
||||
return get_input_code_no_gamepad(layout);
|
||||
};
|
||||
let tol = 0.5;
|
||||
let axis_horizontal = gamepad
|
||||
.axis_data(Axis::LeftStickX)
|
||||
.map(|a| a.value())
|
||||
.unwrap_or(0.);
|
||||
let axis_vertical = gamepad
|
||||
.axis_data(Axis::LeftStickY)
|
||||
.map(|a| a.value())
|
||||
.unwrap_or(0.);
|
||||
if is_key_down(KeyCode::Space)
|
||||
|| is_mouse_button_down(MouseButton::Left)
|
||||
|| gamepad.is_pressed(Button::East)
|
||||
{
|
||||
key_code += 1;
|
||||
}
|
||||
if input.key_held_logical(Key::Character("b"))
|
||||
|| input.mouse_held(MouseButton::Right)
|
||||
|| gamepad.pressing(NesInput::B)
|
||||
if is_key_down(KeyCode::B)
|
||||
|| is_mouse_button_down(MouseButton::Right)
|
||||
|| gamepad.is_pressed(Button::South)
|
||||
{
|
||||
key_code += 2;
|
||||
}
|
||||
if input.key_held_logical(Key::Character("w"))
|
||||
|| input.key_held(KeyCode::ArrowUp)
|
||||
|| gamepad.pressing(NesInput::Up)
|
||||
if is_key_down(KeyCode::W)
|
||||
|| is_key_down(KeyCode::Up)
|
||||
|| gamepad.is_pressed(Button::DPadUp)
|
||||
|| axis_vertical > tol
|
||||
{
|
||||
key_code += 4;
|
||||
key_code += 4
|
||||
}
|
||||
if input.key_held_logical(Key::Character("s"))
|
||||
|| input.key_held(KeyCode::ArrowDown)
|
||||
|| gamepad.pressing(NesInput::Down)
|
||||
if is_key_down(KeyCode::S)
|
||||
|| is_key_down(KeyCode::Down)
|
||||
|| gamepad.is_pressed(Button::DPadDown)
|
||||
|| axis_vertical < -tol
|
||||
{
|
||||
key_code += 8;
|
||||
key_code += 8
|
||||
}
|
||||
if input.key_held_logical(Key::Character("a"))
|
||||
|| input.key_held(KeyCode::ArrowLeft)
|
||||
|| gamepad.pressing(NesInput::Left)
|
||||
if is_key_down(KeyCode::A)
|
||||
|| is_key_down(KeyCode::Left)
|
||||
|| gamepad.is_pressed(Button::DPadLeft)
|
||||
|| axis_horizontal < -tol
|
||||
{
|
||||
key_code += 16;
|
||||
key_code += 16
|
||||
}
|
||||
if input.key_held_logical(Key::Character("d"))
|
||||
|| input.key_held(KeyCode::ArrowRight)
|
||||
|| gamepad.pressing(NesInput::Right)
|
||||
if is_key_down(KeyCode::D)
|
||||
|| is_key_down(KeyCode::Right)
|
||||
|| gamepad.is_pressed(Button::DPadRight)
|
||||
|| axis_horizontal > tol
|
||||
{
|
||||
key_code += 32;
|
||||
key_code += 32
|
||||
}
|
||||
if input.key_held_logical(Key::Character("n")) || gamepad.pressing(NesInput::Select) {
|
||||
key_code += 64;
|
||||
if is_key_down(KeyCode::N) || gamepad.is_pressed(Button::Select) {
|
||||
key_code += 64
|
||||
}
|
||||
if input.key_held_logical(Key::Character("m")) || gamepad.pressing(NesInput::Start) {
|
||||
key_code += 128;
|
||||
if is_key_down(KeyCode::M) || gamepad.is_pressed(Button::Start) {
|
||||
key_code += 128
|
||||
}
|
||||
|
||||
(pos_code, key_code)
|
||||
}
|
||||
|
||||
pub fn handle_event_loop_error(handle: &EventLoopWindowTarget<()>, msg: impl AsRef<str>) {
|
||||
eprintln!("{}", msg.as_ref());
|
||||
handle.exit();
|
||||
}
|
||||
pub fn get_input_code_no_gamepad(layout: &Layout) -> (u16, u16) {
|
||||
let mp = layout.clamp_mouse();
|
||||
|
||||
#[cfg(not(feature = "gamepad"))]
|
||||
pub fn get_input_code(input: &WinitInputHelper, pxls: &Pixels) -> (u16, u16) {
|
||||
let raw_mp = input.cursor().unwrap_or((0., 0.));
|
||||
let mp = match pxls.window_pos_to_pixel(raw_mp) {
|
||||
Ok(p) => p,
|
||||
Err(ev) => pxls.clamp_pixel_pos(ev),
|
||||
};
|
||||
let pos_code = (mp.1 as u16 * 256) + mp.0 as u16;
|
||||
let mut key_code = 0_u16;
|
||||
if input.key_held(KeyCode::Space) || input.mouse_held(MouseButton::Left) {
|
||||
if is_key_down(KeyCode::Space) || is_mouse_button_down(MouseButton::Left) {
|
||||
key_code += 1;
|
||||
}
|
||||
if input.key_held_logical(Key::Character("b")) || input.mouse_held(MouseButton::Right) {
|
||||
if is_key_down(KeyCode::B) || is_mouse_button_down(MouseButton::Right) {
|
||||
key_code += 2;
|
||||
}
|
||||
if input.key_held_logical(Key::Character("w")) || input.key_held(KeyCode::ArrowUp) {
|
||||
key_code += 4;
|
||||
if is_key_down(KeyCode::W) || is_key_down(KeyCode::Up) {
|
||||
key_code += 4
|
||||
}
|
||||
if input.key_held_logical(Key::Character("s")) || input.key_held(KeyCode::ArrowDown) {
|
||||
key_code += 8;
|
||||
if is_key_down(KeyCode::S) || is_key_down(KeyCode::Down) {
|
||||
key_code += 8
|
||||
}
|
||||
if input.key_held_logical(Key::Character("a")) || input.key_held(KeyCode::ArrowLeft) {
|
||||
key_code += 16;
|
||||
if is_key_down(KeyCode::A) || is_key_down(KeyCode::Left) {
|
||||
key_code += 16
|
||||
}
|
||||
if input.key_held_logical(Key::Character("d")) || input.key_held(KeyCode::ArrowRight) {
|
||||
key_code += 32;
|
||||
if is_key_down(KeyCode::D) || is_key_down(KeyCode::Right) {
|
||||
key_code += 32
|
||||
}
|
||||
if input.key_held_logical(Key::Character("n")) {
|
||||
key_code += 64;
|
||||
if is_key_down(KeyCode::N) {
|
||||
key_code += 64
|
||||
}
|
||||
if input.key_held_logical(Key::Character("m")) {
|
||||
key_code += 128;
|
||||
if is_key_down(KeyCode::M) {
|
||||
key_code += 128
|
||||
}
|
||||
|
||||
(pos_code, key_code)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user