Initial Commit

This commit is contained in:
2025-11-30 03:04:45 -06:00
commit b23796fc77
18 changed files with 5349 additions and 0 deletions

216
src/bin/main.rs Normal file
View File

@@ -0,0 +1,216 @@
#![no_std]
#![no_main]
use embedded_graphics::framebuffer::{buffer_size, Framebuffer};
use embedded_graphics::pixelcolor::raw::LittleEndian;
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::draw_target::DrawTarget;
use embedded_graphics::image::ImageDrawable;
use esp_backtrace as _;
use esp_hal::clock::CpuClock;
use esp_hal::gpio::{self, InputConfig, OutputConfig};
use esp_hal::rtc_cntl::sleep::{GpioWakeupSource, RtcSleepConfig};
use esp_hal::rtc_cntl::Rtc;
use esp_hal::main;
use esp_println::println;
extern crate alloc;
use mtgcount_rs::{self, TP_GESTURE, TP_X, TP_Y};
#[main]
fn main() -> ! {
// generator version: 0.3.1
println!("Startup init");
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
let pins = mtgcount_rs::init::UsedPins::init(peripherals);
let mut buffer = [0_u8;256];
//set clocks;
let mut iic = pins.init_iic();
let mut display = pins.init_display(&mut buffer);
let mut framebuf: Framebuffer<Rgb565, _, LittleEndian, 240, 240, {buffer_size::<Rgb565>(240, 240)}> = Framebuffer::new();
//let mut bgbuf: Framebuffer<Rgb565, _, LittleEndian, 240, 240, {buffer_size::<Rgb565>(240, 240)}> = Framebuffer::new();
//start bl
println!("Begin backlight setup");
println!("Start Low Power backlight config");
let low_power = unsafe {esp_hal::peripherals::LPWR::steal()};
low_power.register_block().clk_conf().modify(|_,w| w.ck8m_force_pd().clear_bit());
low_power.register_block().clk_conf().modify(|_,w| w.ck8m_force_pu().set_bit());
low_power.register_block().clk_conf().modify(|_,w| w.enb_ck8m().clear_bit());
low_power.register_block().clk_conf().modify(|_,w| w.dig_clk8m_en().set_bit());
println!("Init Backlight peripherals");
let (led, bl, rtcio) = pins.init_backlight();
let mux = unsafe{esp_hal::peripherals::IO_MUX::steal()};
mux.register_block().gpio32().modify(|_,w| w.mcu_oe().set_bit());
rtcio.register_block().enable().modify(|_,w| unsafe{w.enable().bits(0x80_00_00)});
rtcio.register_block().xtal_32k_pad().modify(|_,w| w.x32n_hold().clear_bit());
rtcio.register_block().xtal_32k_pad().modify(|_,w| unsafe{w.x32n_fun_sel().bits(0)});
rtcio.register_block().xtal_32k_pad().modify(|_,w| w.x32n_slp_oe().set_bit());
let _ledc = esp_hal::ledc::Ledc::new(led);
//ledc.set_global_slow_clock(esp_hal::ledc::LSGlobalClkSource::APBClk);
println!("Set apb_clk_sel");
let test = unsafe {esp_hal::peripherals::LEDC::steal()};
test.register_block().conf().write(|w| w.apb_clk_sel().clear_bit());
test.register_block().lstimer(0).conf().modify(|_,w| w.para_up().set_bit());
//let mut lstimer0 = ledc.timer::<LowSpeed>(esp_hal::ledc::timer::Number::Timer0);
//lstimer0.configure(esp_hal::ledc::timer::config::Config {
// duty: esp_hal::ledc::timer::config::Duty::Duty5Bit,
// clock_source: esp_hal::ledc::timer::LSClockSource::APBClk,
// frequency: Rate::from_khz(2),
//}).unwrap();
let precision = 1 << 8u64;
let divisor = ((8_000_000u64) << 8) / 1_000 / precision;
println!("Set up lstimer0");
println!("Lstimer divisor is:{}", divisor);
test.register_block().lstimer(0).conf().modify(|_,w| unsafe {
w.tick_sel().bit(true);
w.rst().clear_bit();
w.pause().clear_bit();
w.div_num().bits(divisor as u32);
w.duty_res().bits(8)
});
test.register_block().lstimer(0).conf().modify(|_,w| w.para_up().set_bit());
//let mut channel0 = ledc.channel(esp_hal::ledc::channel::Number::Channel0, bl);
//channel0.configure(esp_hal::ledc::channel::config::Config {
// timer: &lstimer0,
// duty_pct: 50,
// pin_config: esp_hal::ledc::channel::config::PinConfig::PushPull,
//}).unwrap();
let mut duty_percent = 100;
let duty_range = 2u32.pow(8);
let mut duty_value = (duty_range * duty_percent) / 100;
println!("Setup channel0");
test.register_block().lsch(0).duty().write(|w| unsafe {
w.duty().bits(duty_value<<4)
});
test.register_block().lsch(0).conf1().write(|w| unsafe {
w.duty_start().set_bit();
w.duty_inc().set_bit();
w.duty_num().bits(0x1);
w.duty_cycle().bits(0x1);
w.duty_scale().bits(0x0)
});
test.register_block().lsch(0).conf0().modify(|_,w| w.para_up().set_bit());
println!("Configure output signal");
let newbl: esp_hal::gpio::interconnect::OutputSignal = bl.into();
println!("line1");
newbl.apply_output_config(&OutputConfig::default().with_drive_mode(gpio::DriveMode::PushPull));
println!("line2");
newbl.set_output_enable(true);
println!("Completed output signal config");
test.register_block().lsch(0).hpoint().write(|w| unsafe {
w.hpoint().bits(0x0)
});
println!("Completed hpoint set");
test.register_block().lsch(0).conf0().modify(|_,w| unsafe {
w.sig_out_en().set_bit().timer_sel().bits(0)
});
println!("Completed signal output enable");
test.register_block().lsch(0).conf1().write(|w| unsafe {
w.duty_start().set_bit();
w.duty_inc().set_bit();
w.duty_num().bits(0x1);
w.duty_cycle().bits(0x1);
w.duty_scale().bits(0x0)
});
test.register_block().lsch(0).conf0().modify(|_,w| w.para_up().set_bit());
println!("Completed channel0 reupdate");
let signal = esp_hal::gpio::OutputSignal::LEDC_LS_SIG0;
signal.connect_to(&newbl);
println!("End Backlight setup");
//end bl
let mut read_buffer = [0_u8;1];
esp_alloc::heap_allocator!(size: 16 * 1024);
let pinconf = InputConfig::default();
let irq = pins.irq();
let _wake_pin = esp_hal::gpio::Input::new(irq, pinconf).wakeup_enable(true,esp_hal::gpio::WakeEvent::LowLevel).unwrap();
let waker = GpioWakeupSource::new();
println!("Start Sleep Config setup");
let mut rtc_control = Rtc::new(low_power);
println!("line1");
let mut rtc_config: RtcSleepConfig = RtcSleepConfig::default();
println!("line2");
rtc_config.set_int_8m_pd_en(false);
println!("Finish Sleep Config setup");
//let loop_delay = esp_hal::delay::Delay::new();
let mut gesture;
let mut x;
let mut y;
println!("Systemstate init");
let mut state = mtgcount_rs::state::SystemState::new();
println!("screen: {:?}", state.screen);
framebuf.clear(state.settings.color_scheme.get_color(&mtgcount_rs::display::ColorType::Background)).unwrap();
display.clear(state.settings.color_scheme.get_color(&mtgcount_rs::display::ColorType::Background)).unwrap();
mtgcount_rs::display::draw_screen(&state, &mut framebuf);
framebuf.as_image().draw(&mut display).unwrap();
loop {
//println!("Enterd Loop");
iic.write_read(0x15, &[TP_GESTURE], &mut read_buffer).expect("Failed to do iic");
gesture = read_buffer[0];
iic.write_read(0x15, &[TP_X], &mut read_buffer).expect("Failed to do iic");
x = read_buffer[0];
iic.write_read(0x15, &[TP_Y], &mut read_buffer).expect("Failed to do iic");
y = read_buffer[0];
mtgcount_rs::touch::get_touch_action(x as f32, y as f32, gesture, &mut state);
duty_percent = state.settings.brightness as u32;
duty_value = (duty_range * duty_percent) / 100;
//println!("Duty Percent: {}%", duty_percent);
test.register_block().lsch(0).duty().write(|w| unsafe {w.duty().bits(duty_value<<4)});
test.register_block().lsch(0).conf1().write(|w| unsafe {
w.duty_start().set_bit();
w.duty_inc().set_bit();
w.duty_num().bits(0x1);
w.duty_cycle().bits(0x1);
w.duty_scale().bits(0x0)
});
test.register_block().lsch(0).conf0().modify(|_,w| w.para_up().set_bit());
mtgcount_rs::display::draw_screen(&state, &mut framebuf);
framebuf.as_image().draw(&mut display).unwrap();
framebuf.clear(state.settings.color_scheme.get_color(&mtgcount_rs::display::ColorType::Background)).unwrap();
rtc_control.sleep(&rtc_config,&[&waker]);
}
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin
}

205
src/bin/mini_ulp.s Normal file
View File

@@ -0,0 +1,205 @@
REG_WR 0x103, 0x17, 0x17, 1
REG_WR 0x123, 0x18, 0x18, 0
REG_WR 0x123, 0x11, 0x11, 1
REG_WR 0x123, 0x06, 0x06, 1
entry:
MOVE R0, dutycycle //6
LD R0, R0, 0 //8
LSH R1, R0, 4 //6
ADD R0, R0, R1 //6
ADD R0, R0, 10 //6
JUMP R0 //4
//36
0x0a:
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 12 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 717 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 12 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 717 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 12 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 717 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 12 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 677 //6
JUMP entry //4
0x22:
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 84 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 645 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 84 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 645 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 84 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 645 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 84 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 605 //6
JUMP entry //4
0x3a:
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 156 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 573 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 156 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 573 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 156 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 573 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 156 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 533 //6
JUMP entry //4
0x52:
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 228 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 501 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 228 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 501 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 228 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 501 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 228 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 461 //6
JUMP entry //4
0x6a:
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 300 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 429 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 300 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 429 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 300 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 429 //6
REG_WR 0x101, 0x17, 0x17, 1 //12
WAIT 300 //6
REG_WR 0x102, 0x17, 0x17, 1 //12
WAIT 389 //6
JUMP entry //4
0x82:
REG_WR 0x102, 0x17, 0x17, 1
WAIT 357
REG_WR 0x101, 0x17, 0x17, 1
WAIT 372
REG_WR 0x102, 0x17, 0x17, 1
WAIT 357
REG_WR 0x101, 0x17, 0x17, 1
WAIT 372
REG_WR 0x102, 0x17, 0x17, 1
WAIT 357
REG_WR 0x101, 0x17, 0x17, 1
WAIT 372
REG_WR 0x102, 0x17, 0x17, 1
WAIT 357
REG_WR 0x101, 0x17, 0x17, 1
WAIT 332
JUMP entry
0x9a:
REG_WR 0x102, 0x17, 0x17, 1
WAIT 285
REG_WR 0x101, 0x17, 0x17, 1
WAIT 444
REG_WR 0x102, 0x17, 0x17, 1
WAIT 285
REG_WR 0x101, 0x17, 0x17, 1
WAIT 444
REG_WR 0x102, 0x17, 0x17, 1
WAIT 285
REG_WR 0x101, 0x17, 0x17, 1
WAIT 444
REG_WR 0x102, 0x17, 0x17, 1
WAIT 285
REG_WR 0x101, 0x17, 0x17, 1
WAIT 404
JUMP entry
0xb2:
REG_WR 0x102, 0x17, 0x17, 1
WAIT 213
REG_WR 0x101, 0x17, 0x17, 1
WAIT 516
REG_WR 0x102, 0x17, 0x17, 1
WAIT 213
REG_WR 0x101, 0x17, 0x17, 1
WAIT 516
REG_WR 0x102, 0x17, 0x17, 1
WAIT 213
REG_WR 0x101, 0x17, 0x17, 1
WAIT 516
REG_WR 0x102, 0x17, 0x17, 1
WAIT 213
REG_WR 0x101, 0x17, 0x17, 1
WAIT 476
JUMP entry
0xca:
REG_WR 0x102, 0x17, 0x17, 1
WAIT 141
REG_WR 0x101, 0x17, 0x17, 1
WAIT 606
REG_WR 0x102, 0x17, 0x17, 1
WAIT 141
REG_WR 0x101, 0x17, 0x17, 1
WAIT 606
REG_WR 0x102, 0x17, 0x17, 1
WAIT 141
REG_WR 0x101, 0x17, 0x17, 1
WAIT 606
REG_WR 0x102, 0x17, 0x17, 1
WAIT 141
REG_WR 0x101, 0x17, 0x17, 1
WAIT 566
JUMP entry
0xe2:
REG_WR 0x102, 0x17, 0x17, 1
WAIT 69
REG_WR 0x101, 0x17, 0x17, 1
WAIT 660
REG_WR 0x102, 0x17, 0x17, 1
WAIT 69
REG_WR 0x101, 0x17, 0x17, 1
WAIT 660
REG_WR 0x102, 0x17, 0x17, 1
WAIT 69
REG_WR 0x101, 0x17, 0x17, 1
WAIT 660
REG_WR 0x102, 0x17, 0x17, 1
WAIT 69
REG_WR 0x101, 0x17, 0x17, 1
WAIT 620
JUMP entry
0xfa:
REG_WR 0x102, 0x17, 0x17, 1
WAIT 12
REG_WR 0x101, 0x17, 0x17, 1
WAIT 1482
REG_WR 0x102, 0x17, 0x17, 1
WAIT 12
REG_WR 0x101, 0x17, 0x17, 1
WAIT 1442
JUMP entry
dutycycle:
.long 0

1551
src/bin/ulp_program.s Normal file

File diff suppressed because it is too large Load Diff

447
src/display.rs Normal file
View File

@@ -0,0 +1,447 @@
use embedded_graphics::prelude::{Angle, DrawTarget, Point, Primitive, RgbColor};
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::Drawable;
use u8g2_fonts::{fonts::{u8g2_font_7x13_tr, u8g2_font_9x15B_tr, u8g2_font_logisoso24_tr, u8g2_font_logisoso42_tr, u8g2_font_open_iconic_all_2x_t, u8g2_font_open_iconic_check_4x_t}, FontRenderer};
use micromath::F32Ext;
extern crate alloc;
use alloc::{vec::Vec, string::ToString};
use embedded_graphics::primitives::PrimitiveStyle;
use crate::state::{MainScreenItem, Screen, SystemState};
use crate::setting_screen::{setting_screen, setting_scroll};
pub const LARGE_FONT:FontRenderer = FontRenderer::new::<u8g2_font_logisoso42_tr>();
pub const MED_PLUS_FONT:FontRenderer = FontRenderer::new::<u8g2_font_logisoso24_tr>();
pub const MED_FONT:FontRenderer = FontRenderer::new::<u8g2_font_9x15B_tr>();
pub const SMALL_FONT:FontRenderer = FontRenderer::new::<u8g2_font_7x13_tr>();
pub const ICONS:FontRenderer = FontRenderer::new::<u8g2_font_open_iconic_all_2x_t>();
pub const CHECK:FontRenderer = FontRenderer::new::<u8g2_font_open_iconic_check_4x_t>();
const LIGHTCREAM: Rgb565 = Rgb565::new(31, 62, 26);
const LIGHTBLUE: Rgb565 = Rgb565::new(21, 55, 30);
const DARKBLUE: Rgb565 = Rgb565::new(1, 27, 22);
const LIGHTGREY: Rgb565 = Rgb565::new(25, 48, 23);
const DARKGREY: Rgb565 = Rgb565::new(8, 16, 8);
const LIGHTRED: Rgb565 = Rgb565::new(30, 42, 17);
const LIGHTGREEN: Rgb565 = Rgb565::new(19,52,21);
const ALMOSTBLACK: Rgb565 = Rgb565::new(3, 6, 3);
const CENTER: Point = Point::new(120, 120);
#[derive(Debug,Clone, Copy)]
pub enum ColorType {
Primary,
Secondary,
Tertiary,
Background
}
#[derive(Debug,Clone, Copy)]
pub enum ColorScheme {
Light,
Dark,
White,
Blue,
Black,
Red,
Green,
Azorius,
Dimir,
}
impl ColorScheme {
pub fn get_color(&self, color_type: &ColorType) -> Rgb565 {
match self {
Self::Light => {
match color_type {
ColorType::Primary => Rgb565::BLACK,
ColorType::Secondary => Rgb565::BLACK,
ColorType::Tertiary => Rgb565::BLACK,
ColorType::Background => Rgb565::WHITE,
}
},
Self::Dark => {
match color_type {
ColorType::Primary => Rgb565::WHITE,
ColorType::Secondary => ALMOSTBLACK,
ColorType::Tertiary => Rgb565::WHITE,
ColorType::Background => Rgb565::BLACK,
}
},
Self::White => {
match color_type {
ColorType::Primary => Rgb565::BLACK,
ColorType::Secondary => Rgb565::BLACK,
ColorType::Tertiary => Rgb565::BLACK,
ColorType::Background => LIGHTCREAM,
}
},
Self::Blue => {
match color_type {
ColorType::Primary => Rgb565::BLACK,
ColorType::Secondary => DARKBLUE,
ColorType::Tertiary => Rgb565::BLACK,
ColorType::Background => LIGHTBLUE
}
},
Self::Black => {
match color_type {
ColorType::Primary => Rgb565::BLACK,
ColorType::Secondary => Rgb565::BLACK,
ColorType::Tertiary => Rgb565::BLACK,
ColorType::Background => LIGHTGREY,
}
},
Self::Red => {
match color_type {
ColorType::Primary => Rgb565::BLACK,
ColorType::Secondary => Rgb565::BLACK,
ColorType::Tertiary => Rgb565::BLACK,
ColorType::Background => LIGHTRED,
}
},
Self::Green => {
match color_type {
ColorType::Primary => Rgb565::BLACK,
ColorType::Secondary => Rgb565::BLACK,
ColorType::Tertiary => Rgb565::BLACK,
ColorType::Background => LIGHTGREEN,
}
},
Self::Azorius => {
match color_type {
ColorType::Primary => DARKBLUE,
ColorType::Secondary => DARKBLUE,
ColorType::Tertiary => DARKBLUE,
ColorType::Background => LIGHTCREAM,
}
},
Self::Dimir => {
match color_type {
ColorType::Primary => DARKGREY,
ColorType::Secondary => DARKGREY,
ColorType::Tertiary => DARKGREY,
ColorType::Background => LIGHTBLUE,
}
},
}
}
pub(crate) fn as_str(&self) -> &'static str {
match self {
ColorScheme::Light => "Light",
ColorScheme::Dark => "Dark",
ColorScheme::White => "White",
ColorScheme::Blue => "Blue",
ColorScheme::Black => "Black",
ColorScheme::Red => "Red",
ColorScheme::Green => "Green",
ColorScheme::Azorius => "Azorius",
ColorScheme::Dimir => "Dmir",
}
}
pub fn inc(self) -> Self {
let mut tmp:u8 = self.into();
tmp += 1;
if tmp > 8 {
tmp = 0
}
Self::from(tmp)
}
pub fn dec(self) -> Self {
let tmp:u8 = self.into();
let tmp = tmp.checked_sub(1);
let tmp = match tmp {
Some(u) => u,
None => 8,
};
Self::from(tmp)
}
}
pub const COLORSCHEMES: usize = 9;
impl From<u8> for ColorScheme {
fn from(value: u8) -> Self {
match value {
1 => Self::Dark,
2 => Self::White,
3 => Self::Blue,
4 => Self::Black,
5 => Self::Red,
6 => Self::Green,
7 => Self::Azorius,
8 => Self::Dimir,
_ => Self::Light,
}
}
}
impl Into<u8> for ColorScheme {
fn into(self) -> u8 {
match self {
ColorScheme::Light => 0,
ColorScheme::Dark => 1,
ColorScheme::White => 2,
ColorScheme::Blue => 3,
ColorScheme::Black => 4,
ColorScheme::Red => 5,
ColorScheme::Green => 6,
ColorScheme::Azorius => 7,
ColorScheme::Dimir => 8,
}
}
}
pub fn draw_screen<A: DrawTarget<Color = Rgb565>>(ctx: &SystemState, target: &mut A) -> () {
let primary = ctx.settings.color_scheme.get_color(&ColorType::Primary);
let background = ctx.settings.color_scheme.get_color(&ColorType::Background);
_ = target.clear(background);
match &ctx.screen {
Screen::Main(selection) => {
let style = PrimitiveStyle::with_stroke(ctx.settings.color_scheme.get_color(&ColorType::Secondary), 3);
let bottom_count =
ctx.settings.show_cmd_tax as u8 +
ctx.settings.show_energy as u8 +
ctx.settings.show_experience as u8 +
ctx.settings.show_infect as u8 +
ctx.settings.show_tickets as u8;
if (ctx.settings.opponenets > 0) & (ctx.settings.opponenets < 7) {
let top_positions = ctx.positions.get_top_list(ctx.settings.opponenets);
for (pos, dmg) in top_positions.iter().zip(ctx.game.cmd_dmg) {
_ = SMALL_FONT.render_aligned(
dmg.as_string_horizontal().as_str(),
pos.position,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
}
let start = (ctx.settings.opponenets as f32 * 15.)-90.;
let sweep = ctx.settings.opponenets as f32 * -30.;
let arc = embedded_graphics::primitives::Arc::with_center(CENTER, 160, Angle::from_degrees(start), Angle::from_degrees(sweep));
//println!("start: {}", start);
let _ = arc.into_styled(style).draw(target);
for i in 0..= ctx.settings.opponenets {
let angle = (start + 90. - (30.*(i as f32))) * crate::DEG_TO_RAD;
let (sin_t, cos_t) = angle.sin_cos();
//println!("angle: {}, sin: {}, cos: {}", angle, sin_t, cos_t);
let line1 = Point::new(
((79. * sin_t)+120.) as i32,
((-79. * cos_t)+120.) as i32
);
let line2 = Point::new(
((125. * sin_t)+120.) as i32,
((-125. * cos_t)+120.) as i32
);
let drawline = embedded_graphics::primitives::Line::new(line1, line2);
//println!("{:?}", drawline);
let _ = drawline.into_styled(style).draw(target);
}
}
if bottom_count != 0 {
let bottom_positions = ctx.positions.get_bottom_list(bottom_count);
let mut bottom_vec = Vec::with_capacity(bottom_count as usize);
if ctx.settings.show_cmd_tax {
let tmp = ctx.game.cmd_tax.as_string_horizontal();
bottom_vec.push((tmp, '\u{0092}'));
}
if ctx.settings.show_energy {
let tmp = ctx.game.energy.to_string();
bottom_vec.push((tmp,'\u{0060}'));
}
if ctx.settings.show_experience {
let tmp = ctx.game.experience.to_string();
bottom_vec.push((tmp,'\u{0103}'));
}
if ctx.settings.show_tickets {
let tmp = ctx.game.tickets.to_string();
bottom_vec.push((tmp, '\u{0106}'));
}
if ctx.settings.show_infect {
let tmp = ctx.game.infect.to_string();
bottom_vec.push((tmp,'\u{005c}'));
}
for (pos, content) in bottom_positions.iter().zip(bottom_vec) {
_ = SMALL_FONT.render_aligned(
content.0.as_str(),
pos.position,
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target);
_ = ICONS.render_aligned(
content.1,
pos.position,
u8g2_fonts::types::VerticalPosition::Top,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target);
}
let start = (bottom_count as f32 * 15.)+90.;
let sweep = bottom_count as f32 * -30.;
let arc = embedded_graphics::primitives::Arc::with_center(CENTER, 160, Angle::from_degrees(start), Angle::from_degrees(sweep));
let _ = arc.into_styled(style).draw(target);
for i in 0..=bottom_count {
let angle = (start + 90. - (30.*(i as f32))) * crate::DEG_TO_RAD;
let (sin_t, cos_t) = angle.sin_cos();
//println!("angle: {}, sin: {}, cos: {}", angle, sin_t, cos_t);
let line1 = Point::new(
((79. * sin_t)+120.) as i32,
((-79. * cos_t)+120.) as i32
);
let line2 = Point::new(
((125. * sin_t)+120.) as i32,
((-125. * cos_t)+120.) as i32
);
let drawline = embedded_graphics::primitives::Line::new(line1, line2);
//println!("{:?}", drawline);
let _ = drawline.into_styled(style).draw(target);
}
}
let center_item = match selection {
MainScreenItem::Dmg1 => (ctx.game.cmd_dmg[0].as_string_horizontal(),"Opponent 1"),
MainScreenItem::Dmg2 => (ctx.game.cmd_dmg[1].as_string_horizontal(),"Opponent 2"),
MainScreenItem::Dmg3 => (ctx.game.cmd_dmg[2].as_string_horizontal(),"Opponent 3"),
MainScreenItem::Dmg4 => (ctx.game.cmd_dmg[3].as_string_horizontal(),"Opponent 4"),
MainScreenItem::Dmg5 => (ctx.game.cmd_dmg[4].as_string_horizontal(),"Opponent 5"),
MainScreenItem::Dmg6 => (ctx.game.cmd_dmg[5].as_string_horizontal(),"Opponent 6"),
MainScreenItem::Tax => (ctx.game.cmd_tax.as_string_horizontal(),"Commander Tax"),
MainScreenItem::Energy => (ctx.game.energy.to_string(),"Energy"),
MainScreenItem::Experience => (ctx.game.experience.to_string(),"Experience"),
MainScreenItem::Tickets => (ctx.game.tickets.to_string(),"Tickets"),
MainScreenItem::Poison => (ctx.game.infect.to_string(),"Poison"),
_ => (ctx.game.life.to_string(),"Life"),
};
let _ = LARGE_FONT.render_aligned(
center_item.0.as_str(),
ctx.positions.center,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
let _ = SMALL_FONT.render_aligned(
center_item.1,
Point::new(120, 150),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
let content = match selection {
MainScreenItem::Dmg1 => Some(0),
MainScreenItem::Dmg2 => Some(1),
MainScreenItem::Dmg3 => Some(2),
MainScreenItem::Dmg4 => Some(3),
MainScreenItem::Dmg5 => Some(4),
MainScreenItem::Dmg6 => Some(5),
_ => None,
};
if let Some(pos) = content {
let content = if ctx.game.cmd_dmg[pos].is_partner {
"0"
} else {
"0|0"
};
let _ = SMALL_FONT.render_aligned(
content,
Point { x: 120, y: 170 },
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
} else if *selection == MainScreenItem::Tax {
let content = if ctx.game.cmd_tax.is_partner {
"0"
} else {
"0|0"
};
let _ = SMALL_FONT.render_aligned(
content,
Point { x: 120, y: 170 },
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
}
}
Screen::Settings(selection) => {
setting_scroll(ctx, selection, target);
}
}
}
/*
opponents 1-6
life total
tax
energy
experience
tix
poison
opponents
starting life
new game
colors
brightness
show tax
show energy
show experience
show tickets
show poison
*/

115
src/init.rs Normal file
View File

@@ -0,0 +1,115 @@
use core::cell::Cell;
use embedded_hal_bus::spi::ExclusiveDevice;
use esp_hal::{delay::Delay, gpio::Output, i2c::master::I2c, peripherals::*, spi::master::Spi, time::Rate, Blocking};
use mipidsi::{interface::SpiInterface, models::GC9A01};
pub struct UsedPins<'a> {
sda: Cell<Option<GPIO21<'a>>>,
scl: Cell<Option<GPIO22<'a>>>,
irq: Cell<Option<GPIO19<'a>>>,
tp_rst: Cell<Option<GPIO4<'a>>>,
sclk: Cell<Option<GPIO14<'a>>>,
mosi: Cell<Option<GPIO15<'a>>>,
cs: Cell<Option<GPIO5<'a>>>,
dc: Cell<Option<GPIO27<'a>>>,
reset: Cell<Option<GPIO33<'a>>>,
bl: Cell<Option<GPIO32<'a>>>,
iic: Cell<Option<I2C0<'a>>>,
spi: Cell<Option<SPI2<'a>>>,
lpwr: Cell<Option<LPWR<'a>>>,
ledc: Cell<Option<LEDC<'a>>>,
//dport: Cell<Option<DPORT<'a>>>,
io_mux: Cell<Option<RTC_IO<'a>>>,
//rtc_io: Cell<Option<LPWR<'a>>>,
}
impl<'a> UsedPins<'a> {
pub fn init(peripherals: esp_hal::peripherals::Peripherals) -> Self {
UsedPins {
sda: Cell::new(Some(peripherals.GPIO21)),
scl: Cell::new(Some(peripherals.GPIO22)),
irq: Cell::new(Some(peripherals.GPIO19)),
tp_rst: Cell::new(Some(peripherals.GPIO4)),
sclk: Cell::new(Some(peripherals.GPIO14)),
mosi: Cell::new(Some(peripherals.GPIO15)),
cs: Cell::new(Some(peripherals.GPIO5)),
dc: Cell::new(Some(peripherals.GPIO27)),
reset: Cell::new(Some(peripherals.GPIO33)),
bl: Cell::new(Some(peripherals.GPIO32)),
iic: Cell::new(Some(peripherals.I2C0)),
spi: Cell::new(Some(peripherals.SPI2)),
lpwr: Cell::new(Some(peripherals.LPWR)),
ledc: Cell::new(Some(peripherals.LEDC)),
//dport: Cell::new(Some(peripherals.DPORT)),
io_mux: Cell::new(Some(peripherals.RTC_IO)),
//rtc_io: Cell::new(Some(peripherals.LPWR)),
}
}
pub fn irq(&self) -> GPIO19 {
let irq = self.irq.replace(None).unwrap();
irq
}
pub fn tp_rst(&self) -> GPIO4 {
let tp_rst = self.tp_rst.replace(None).unwrap();
tp_rst
}
pub fn get_lpwr(&self) -> LPWR<'a> {
let pin = self.lpwr.replace(None).unwrap();
pin
}
pub fn init_backlight(&self) -> (LEDC<'a>, GPIO32<'a>, RTC_IO<'a>) {
let bl = self.bl.replace(None).unwrap();
let ledc = self.ledc.replace(None).unwrap();
//let rtc_io = self.rtc_io.replace(None).unwrap();
let io_mux = self.io_mux.replace(None).unwrap();
(ledc, bl, io_mux)
}
pub fn init_iic(&self) -> I2c<'_, Blocking> {
let mut iic = I2c::new(self.iic.replace(None).unwrap(), esp_hal::i2c::master::Config::default()).unwrap()
.with_sda(self.sda.replace(None).unwrap())
.with_scl(self.scl.replace(None).unwrap());
iic.write(0x15, &[0xFA_u8, 0b00010001]).expect("Failed to set irqctl");
iic
}
pub fn init_display(&'a self, buffer: &'a mut [u8]) -> mipidsi::Display<SpiInterface<'a, ExclusiveDevice<esp_hal::spi::master::Spi<'a, Blocking>, Output<'a>, Delay>, Output<'a>>, GC9A01, Output<'a>> {
let spi = Spi::new(
self.spi.replace(None).unwrap(),
esp_hal::spi::master::Config::default()
.with_frequency(Rate::from_mhz(40))
).unwrap()
.with_sck(self.sclk.replace(None).unwrap())
.with_mosi(self.mosi.replace(None).unwrap());
let cs_pin = esp_hal::gpio::Output::new(self.cs.replace(None).unwrap(), esp_hal::gpio::Level::Low, esp_hal::gpio::OutputConfig::default());
let dc_pin = esp_hal::gpio::Output::new(self.dc.replace(None).unwrap(), esp_hal::gpio::Level::High, esp_hal::gpio::OutputConfig::default());
let rs_pin = esp_hal::gpio::Output::new(self.reset.replace(None).unwrap(), esp_hal::gpio::Level::High, esp_hal::gpio::OutputConfig::default().with_pull(esp_hal::gpio::Pull::Up));
let mut delay = esp_hal::delay::Delay::new();
let spi_dev = ExclusiveDevice::new(spi, cs_pin, delay).unwrap();
let mipi_interface = mipidsi::interface::SpiInterface::new(spi_dev, dc_pin, buffer);
let display = mipidsi::Builder::new(GC9A01, mipi_interface)
.reset_pin(rs_pin)
.invert_colors(mipidsi::options::ColorInversion::Inverted)
.color_order(mipidsi::options::ColorOrder::Bgr)
.init(&mut delay).unwrap();
display
}
}

15
src/lib.rs Normal file
View File

@@ -0,0 +1,15 @@
#![no_std]
pub mod init;
pub mod state;
pub mod display;
pub mod touch;
pub mod setting_screen;
pub const IIC_ADDRESS: u8 = 0x15_u8;
pub const TP_GESTURE: u8 = 0x01_u8;
pub const TP_X: u8 = 0x04_u8;
pub const TP_Y: u8 = 0x06_u8;
pub const RAD_TO_DEG: f32 = 57.2957795;
pub const DEG_TO_RAD: f32 = 0.017453293;

492
src/setting_screen.rs Normal file
View File

@@ -0,0 +1,492 @@
use embedded_graphics::pixelcolor::Rgb565;
use embedded_graphics::prelude::{DrawTarget, Point, Primitive, RgbColor, Size};
use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle};
use embedded_graphics::Drawable;
extern crate alloc;
use alloc::{vec::Vec, string::ToString};
use u8g2_fonts::types::{FontColor, HorizontalAlignment, VerticalPosition};
use crate::state::{SettingScreenEntry, SettingScreenItem, SystemState};
use crate::display::{CHECK, SMALL_FONT, MED_FONT, MED_PLUS_FONT};
use crate::display::{ColorScheme, COLORSCHEMES};
pub(crate) fn setting_screen<A>(ctx: &SystemState, selection: &SettingScreenItem, target: &mut A) -> ()
where A: DrawTarget<Color = Rgb565>
{
let primary = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Primary);
let background = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Background);
let top_count = 5;
let bottom_count = 5;
let top_positions = &ctx.positions.top_setting_locations;
let bottom_positions = &ctx.positions.bottom_setting_locations;
let mut top_vec = Vec::with_capacity(top_count as usize);
top_vec.push("Opponents");
top_vec.push("Starting\nLife");
top_vec.push("New Game");
top_vec.push("Color\nScheme");
top_vec.push("Brightness");
let mut bottom_vec = Vec::with_capacity(bottom_count as usize);
bottom_vec.push("Commander\nTax");
bottom_vec.push("Energy");
bottom_vec.push("Exp");
bottom_vec.push("Tix");
bottom_vec.push("Poison");
for (pos, content) in top_positions.iter().chain(bottom_positions.iter()).zip(top_vec.into_iter().chain(bottom_vec.into_iter())) {
_ = SMALL_FONT.render_aligned(
content,
pos.position,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target);
}
match selection.entry {
SettingScreenEntry::NewGame => {
let _ = MED_FONT.render_aligned(
"Start\nNew Game.",
ctx.positions.center,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::Opponents => {
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.opponenets.to_string().as_str(),
ctx.positions.center,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::StartingLife => {
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.starting_life.to_string().as_str(),
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::Colors => {
let current_scheme_number: u8 = ctx.settings.color_scheme.into();
let prev_scheme_number;
let check_sub = current_scheme_number.checked_sub(1);
if let Some(p) = check_sub {
prev_scheme_number = p;
} else {
prev_scheme_number = COLORSCHEMES as u8 - 1;
}
let prev_scheme: ColorScheme = prev_scheme_number.into();
let next_scheme_number;
let check_add = current_scheme_number + 1;
if check_add >= COLORSCHEMES as u8 {
next_scheme_number = 0;
} else {
next_scheme_number = check_add;
}
let next_scheme: ColorScheme = next_scheme_number.into();
let _ = MED_FONT.render_aligned(
prev_scheme.as_str(),
Point::new(120, 80),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.color_scheme.as_str(),
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
let _ = MED_FONT.render_aligned(
next_scheme.as_str(),
Point::new(120, 160),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::Brightness => {
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.brightness.as_str(),
ctx.positions.center,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::ShowTax => {
//Yes/No rendering
let _ = MED_FONT.render_aligned(
"Show\nCommand Tax?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_cmd_tax));
},
SettingScreenEntry::ShowEnergy => {
//Yes/No rendering
let _ = MED_FONT.render_aligned(
"Show\nEnergy?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_energy));
},
SettingScreenEntry::ShowExperience => {
//Yes/No rendering
let _ = MED_FONT.render_aligned(
"Show\nExperience?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_experience));
},
SettingScreenEntry::ShowTickets => {
//Yes/No rendering
let _ = MED_FONT.render_aligned(
"Show\nTickets?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_tickets));
},
SettingScreenEntry::ShowPoison => {
//Yes/No rendering
let _ = MED_FONT.render_aligned(
"Show\nPoison?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_infect));
},
};
}
fn draw_yes_no<A: DrawTarget<Color = Rgb565>>(primary: Rgb565, background: Rgb565, display: &mut A, selected: Option<bool>) -> () {
let yes_color;
let no_color;
let rect_point;
if let Some(sel) = selected {
if sel {
yes_color = background;
no_color = primary;
rect_point = Point::new(75, 125);
} else {
yes_color = primary;
no_color = background;
rect_point = Point::new(120,125);
}
let style = PrimitiveStyleBuilder::new()
.fill_color(primary)
.build();
let _ = Rectangle::new(rect_point, Size::new(45, 25)).into_styled(style).draw(display);
} else {
yes_color = primary;
no_color = primary;
}
_ = MED_FONT.render_aligned(
"Yes",
Point{x: 110, y: 130},
u8g2_fonts::types::VerticalPosition::Top,
u8g2_fonts::types::HorizontalAlignment::Right,
u8g2_fonts::types::FontColor::Transparent(yes_color),
display,
);
_ = MED_FONT.render_aligned(
"No",
Point{x: 135, y: 130},
u8g2_fonts::types::VerticalPosition::Top,
u8g2_fonts::types::HorizontalAlignment::Left,
u8g2_fonts::types::FontColor::Transparent(no_color),
display,
);
}
pub(crate) fn setting_scroll<A>(ctx: &SystemState, selection: &SettingScreenItem, target: &mut A) -> ()
where A: DrawTarget<Color = Rgb565>
{
let primary = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Primary);
let background = ctx.settings.color_scheme.get_color(&crate::display::ColorType::Background);
if !selection.inner {
let above = selection.entry.prev().as_str();
let selected = selection.entry.as_str();
let below = selection.entry.next().as_str();
let _above = MED_FONT.render_aligned(
above,
Point::new(120, 50),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(primary),
target
);
let _selected = MED_PLUS_FONT.render_aligned(
selected,
Point::new(120, 120),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(primary),
target
);
let _below = MED_FONT.render_aligned(
below,
Point::new(120, 190),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(primary),
target
);
} else {
setting_item(target);
match selection.entry {
SettingScreenEntry::NewGame => {
let _ = MED_PLUS_FONT.render_aligned(
selection.entry.as_str(),
Point::new(120, 120),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(primary),
target,
);
},
SettingScreenEntry::Opponents => {
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.opponenets.to_string().as_str(),
ctx.positions.center,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::StartingLife => {
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.starting_life.to_string().as_str(),
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::Colors => {
let current_scheme_number: u8 = ctx.settings.color_scheme.into();
let prev_scheme_number;
let check_sub = current_scheme_number.checked_sub(1);
if let Some(p) = check_sub {
prev_scheme_number = p;
} else {
prev_scheme_number = COLORSCHEMES as u8 - 1;
}
let prev_scheme: ColorScheme = prev_scheme_number.into();
let next_scheme_number;
let check_add = current_scheme_number + 1;
if check_add >= COLORSCHEMES as u8 {
next_scheme_number = 0;
} else {
next_scheme_number = check_add;
}
let next_scheme: ColorScheme = next_scheme_number.into();
let _ = MED_FONT.render_aligned(
prev_scheme.as_str(),
Point::new(120, 70),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.color_scheme.as_str(),
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
let _ = MED_FONT.render_aligned(
next_scheme.as_str(),
Point::new(120, 170),
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
},
SettingScreenEntry::Brightness => {
let _ = MED_PLUS_FONT.render_aligned(
ctx.settings.brightness.as_str(),
ctx.positions.center,
u8g2_fonts::types::VerticalPosition::Center,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
}
SettingScreenEntry::ShowTax => {
let _ = MED_FONT.render_aligned(
"Show\nCommand Tax?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_cmd_tax));
},
SettingScreenEntry::ShowEnergy => {
let _ = MED_FONT.render_aligned(
"Show\nEnergy?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_energy));
},
SettingScreenEntry::ShowExperience => {
let _ = MED_FONT.render_aligned(
"Show\nExperience?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_experience));
},
SettingScreenEntry::ShowTickets => {
let _ = MED_FONT.render_aligned(
"Show\nTickets?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_tickets));
},
SettingScreenEntry::ShowPoison => {
let _ = MED_FONT.render_aligned(
"Show\nPoison?",
Point::new(120, 120),
u8g2_fonts::types::VerticalPosition::Bottom,
u8g2_fonts::types::HorizontalAlignment::Center,
u8g2_fonts::types::FontColor::Transparent(primary),
target
);
draw_yes_no(primary, background, target, Some(ctx.settings.show_infect));
},
}
}
}
pub fn setting_item<A>(target: &mut A) -> ()
where A: DrawTarget<Color = Rgb565>
{
let _okay_outline_1 = CHECK.render_aligned(
'\u{0040}',
Point::new(26, 121),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(Rgb565::BLACK),
target
);
let _okay_outline_2 = CHECK.render_aligned(
'\u{0040}',
Point::new(26, 119),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(Rgb565::BLACK),
target
);
let _okay_outline_3 = CHECK.render_aligned(
'\u{0040}',
Point::new(24, 121),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(Rgb565::BLACK),
target
);
let _okay_outline_4 = CHECK.render_aligned(
'\u{0040}',
Point::new(24, 119),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(Rgb565::BLACK),
target
);
let _okay = CHECK.render_aligned(
'\u{0040}',
Point::new(25, 120),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(Rgb565::new(1, 54, 10)),
target
);
let _cancel = CHECK.render_aligned(
'\u{0044}',
Point::new(215, 120),
VerticalPosition::Center,
HorizontalAlignment::Center,
FontColor::Transparent(Rgb565::new(25, 8, 5)),
target
);
}
/*
setting scroller -> internal screen check ok/ x cancel
*/

387
src/state.rs Normal file
View File

@@ -0,0 +1,387 @@
use core::panic;
use crate::display::ColorScheme;
use embedded_graphics::prelude::{Angle, Point};
extern crate alloc;
use alloc::{string::String, string::ToString};
pub struct SystemState {
pub settings: Settings,
pub game: Game,
pub positions: Positions,
pub screen: Screen,
}
impl SystemState {
pub fn new() -> Self {
Self {
settings: Settings {
opponenets: 1,
starting_life: 40,
brightness: Brightness::Three,
color_scheme: ColorScheme::Dark,
show_cmd_tax: true,
show_infect: true,
show_energy: true,
show_experience: true,
show_tickets: true,
},
game: Game { life: 40, cmd_dmg: [CommanderDamage{main: 0, partner: 0, is_partner: true};6], infect: 0, cmd_tax: CommanderDamage { main: 0, partner: 0, is_partner: false }, energy: 0, experience: 0, tickets: 0, monarch: false},
positions: Positions::init(),
screen: Screen::Main(MainScreenItem::Life),
}
}
}
pub struct Settings {
pub opponenets: u8,
pub starting_life: i32,
pub color_scheme: ColorScheme,
pub brightness: Brightness,
pub show_cmd_tax: bool,
pub show_infect: bool,
pub show_experience: bool,
pub show_energy: bool,
pub show_tickets: bool,
}
pub struct Game {
pub life: i32,
pub cmd_dmg: [CommanderDamage;6],
pub cmd_tax: CommanderDamage,
pub infect: u8,
pub energy: u16,
pub experience: u16,
pub tickets: u16,
pub monarch: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct CommanderDamage {
pub main: u8,
pub partner: u8,
pub is_partner: bool,
}
impl CommanderDamage {
pub fn as_string_horizontal(&self) -> String {
match self.is_partner {
true => {
let mut tmpa = self.main.to_string();
let tmpb = self.partner.to_string();
tmpa.push('|');
tmpa.push_str(&tmpb);
tmpa
},
false => {
self.main.to_string()
}
}
}
pub fn as_string_vetical(&self) -> String {
match self.is_partner {
true => {
let mut tmpa = self.main.to_string();
let tmpb = self.partner.to_string();
tmpa.push('\n');
tmpa.push_str(&tmpb);
tmpa
},
false => {
self.main.to_string()
}
}
}
}
pub struct Positions {
top_even: [PeripheralLocation;6],
top_odd: [PeripheralLocation;5],
bottom_even: [PeripheralLocation;6],
bottom_odd: [PeripheralLocation;5],
pub top_setting_locations: [PeripheralLocation;5],
pub bottom_setting_locations: [PeripheralLocation;5],
pub center: Point,
}
impl Positions {
pub fn init() -> Self {
let top_odd = [
PeripheralLocation{ position: Point::new(38, 71), angle: Angle::from_degrees(150.)},
PeripheralLocation{ position: Point::new(72, 37), angle: Angle::from_degrees(120.)},
PeripheralLocation{ position: Point::new(120, 20), angle: Angle::from_degrees(90.)},
PeripheralLocation{ position: Point::new(168, 37), angle: Angle::from_degrees(60.)},
PeripheralLocation{ position: Point::new(202, 71), angle: Angle::from_degrees(30.)},
];
let top_even = [
PeripheralLocation{ position: Point::new(23, 96), angle: Angle::from_degrees(165.)},
PeripheralLocation{ position: Point::new(53, 52), angle: Angle::from_degrees(135.)},
PeripheralLocation{ position: Point::new(95, 27), angle: Angle::from_degrees(105.)},
PeripheralLocation{ position: Point::new(145, 27), angle: Angle::from_degrees(75.)},
PeripheralLocation{ position: Point::new(187, 52), angle: Angle::from_degrees(45.)},
PeripheralLocation{ position: Point::new(212, 96), angle: Angle::from_degrees(15.)},
];
let bottom_odd = [
PeripheralLocation{ position: Point::new(32, 170), angle: Angle::from_degrees(210.)},
PeripheralLocation{ position: Point::new(70, 208), angle: Angle::from_degrees(240.)},
PeripheralLocation{ position: Point::new(120, 215), angle: Angle::from_degrees(270.)},
PeripheralLocation{ position: Point::new(168, 203), angle: Angle::from_degrees(300.)},
PeripheralLocation{ position: Point::new(202, 169), angle: Angle::from_degrees(330.)},
];
let bottom_even = [
PeripheralLocation{ position: Point::new(28, 146), angle: Angle::from_degrees(195.)},
PeripheralLocation{ position: Point::new(48, 190), angle: Angle::from_degrees(225.)},
PeripheralLocation{ position: Point::new(95, 213), angle: Angle::from_degrees(255.)},
PeripheralLocation{ position: Point::new(145, 213), angle: Angle::from_degrees(285.)},
PeripheralLocation{ position: Point::new(187, 188), angle: Angle::from_degrees(315.)},
PeripheralLocation{ position: Point::new(212, 146), angle: Angle::from_degrees(345.)},
];
let top_setting_locations = [
PeripheralLocation{ position: Point::new(38, 91), angle: Angle::from_degrees(162.)},
PeripheralLocation{ position: Point::new(64, 53), angle: Angle::from_degrees(126.)},
PeripheralLocation{ position: Point::new(120, 25), angle: Angle::from_degrees(90.)},
PeripheralLocation{ position: Point::new(176, 53), angle: Angle::from_degrees(54.)},
PeripheralLocation{ position: Point::new(210, 91), angle: Angle::from_degrees(18.)},
];
let bottom_setting_locations = [
PeripheralLocation{ position: Point::new(33, 170), angle: Angle::from_degrees(210.)},//(43,169)
PeripheralLocation{ position: Point::new(72, 203), angle: Angle::from_degrees(240.)},
PeripheralLocation{ position: Point::new(120, 215), angle: Angle::from_degrees(270.)},
PeripheralLocation{ position: Point::new(168, 203), angle: Angle::from_degrees(300.)},
PeripheralLocation{ position: Point::new(202, 169), angle: Angle::from_degrees(330.)},
];
Self {
top_even,
top_odd,
bottom_even,
bottom_odd,
top_setting_locations,
bottom_setting_locations,
center: Point { x: 120, y: 120 }
}
}
pub fn get_top_list(&self, count: u8) -> &[PeripheralLocation] {
match count {
1 => &self.top_odd[2..3],
2 => &self.top_even[2..4],
3 => &self.top_odd[1..4],
4 => &self.top_even[1..5],
5 => &self.top_odd,
6 => &self.top_even,
_ => panic!("Invalid count")
}
}
pub fn get_bottom_list(&self, count: u8) -> &[PeripheralLocation] {
match count {
1 => &self.bottom_odd[2..3],
2 => &self.bottom_even[2..4],
3 => &self.bottom_odd[1..4],
4 => &self.bottom_even[1..5],
5 => &self.bottom_odd,
6 => &self.bottom_even,
_ => panic!("Invalid count")
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Screen{
Main(MainScreenItem),
Settings(SettingScreenItem),
}
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy)]
pub enum MainScreenItem {
Life,
Dmg1,
Dmg2,
Dmg3,
Dmg4,
Dmg5,
Dmg6,
Tax,
Energy,
Experience,
Tickets,
Poison,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct SettingScreenItem {
pub entry: SettingScreenEntry,
pub inner: bool,
pub prev: Option<u32>,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum SettingScreenEntry {
NewGame,
Opponents,
StartingLife,
Colors,
Brightness,
ShowTax,
ShowEnergy,
ShowExperience,
ShowTickets,
ShowPoison,
}
impl SettingScreenEntry {
pub fn prev(&self) -> Self {
match self {
SettingScreenEntry::NewGame => Self::ShowPoison,
SettingScreenEntry::Opponents => Self::NewGame,
SettingScreenEntry::StartingLife => Self::Opponents,
SettingScreenEntry::Colors => Self::StartingLife,
SettingScreenEntry::Brightness => Self::Colors,
SettingScreenEntry::ShowTax => Self::Brightness,
SettingScreenEntry::ShowEnergy => Self::ShowTax,
SettingScreenEntry::ShowExperience => Self::ShowEnergy,
SettingScreenEntry::ShowTickets => Self::ShowExperience,
SettingScreenEntry::ShowPoison => Self::ShowTickets,
}
}
pub fn next(&self) -> Self {
match self {
SettingScreenEntry::NewGame => Self::Opponents,
SettingScreenEntry::Opponents => Self::StartingLife,
SettingScreenEntry::StartingLife => Self::Colors,
SettingScreenEntry::Colors => Self::Brightness,
SettingScreenEntry::Brightness => Self::ShowTax,
SettingScreenEntry::ShowTax => Self::ShowEnergy,
SettingScreenEntry::ShowEnergy => Self::ShowExperience,
SettingScreenEntry::ShowExperience => Self::ShowTickets,
SettingScreenEntry::ShowTickets => Self::ShowPoison,
SettingScreenEntry::ShowPoison => Self::NewGame,
}
}
pub fn as_str(&self) -> &'static str {
match self {
SettingScreenEntry::NewGame => "New Game",
SettingScreenEntry::Opponents => "Opponents",
SettingScreenEntry::StartingLife => "Starting\nLife",
SettingScreenEntry::Colors => "Color\nScheme",
SettingScreenEntry::Brightness => "Brightness",
SettingScreenEntry::ShowTax => "Show\nCommander\nTax",
SettingScreenEntry::ShowEnergy => "Show\nEnergy",
SettingScreenEntry::ShowExperience => "Show\nExperience",
SettingScreenEntry::ShowTickets => "Show\nTickets",
SettingScreenEntry::ShowPoison => "Show\nPoison",
}
}
}
#[derive(Clone, Copy)]
pub enum Brightness {
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
}
impl Brightness {
pub fn inc(self) -> Self {
match self {
Brightness::One => Self::Two,
Brightness::Two => Self::Three,
Brightness::Three => Self::Four,
Brightness::Four => Self::Five,
Brightness::Five => Self::Six,
Brightness::Six => Self::Seven,
Brightness::Seven => Self::Eight,
Brightness::Eight => Self::Nine,
Brightness::Nine => Self::Ten,
Brightness::Ten => Self::Ten,
}
}
pub fn dec(self) -> Self {
match self {
Brightness::One => Self::One,
Brightness::Two => Self::One,
Brightness::Three => Self::Two,
Brightness::Four => Self::Three,
Brightness::Five => Self::Four,
Brightness::Six => Self::Five,
Brightness::Seven => Self::Six,
Brightness::Eight => Self::Seven,
Brightness::Nine => Self::Eight,
Brightness::Ten => Self::Nine,
}
}
pub fn as_str(&self) -> &'static str {
match self {
Brightness::One => "Min",
Brightness::Two => "2",
Brightness::Three => "3",
Brightness::Four => "4",
Brightness::Five => "5",
Brightness::Six => "6",
Brightness::Seven => "7",
Brightness::Eight => "8",
Brightness::Nine => "9",
Brightness::Ten => "Max",
}
}
}
impl Into<u32> for Brightness {
fn into(self) -> u32 {
match self {
Brightness::One => 15,
Brightness::Two => 20,
Brightness::Three => 30,
Brightness::Four => 40,
Brightness::Five => 50,
Brightness::Six => 60,
Brightness::Seven => 70,
Brightness::Eight => 80,
Brightness::Nine => 90,
Brightness::Ten => 100,
}
}
}
impl From<u32> for Brightness {
fn from(value: u32) -> Self {
if value <= 15 {
Brightness::One
} else if value <= 20 {
Brightness::Two
} else if value <= 30 {
Brightness::Three
} else if value <= 40 {
Brightness::Four
} else if value <= 50 {
Brightness::Five
} else if value <= 60 {
Brightness::Six
} else if value <= 70 {
Brightness::Seven
} else if value <= 80 {
Brightness::Eight
} else if value <= 90 {
Brightness::Nine
} else {
Brightness::Ten
}
}
}
pub struct PeripheralLocation {
pub position: Point,
pub angle: Angle,
}

406
src/touch.rs Normal file
View File

@@ -0,0 +1,406 @@
use crate::{display::ColorScheme, state::{CommanderDamage, Game, MainScreenItem, Screen, SettingScreenEntry, SettingScreenItem, SystemState}};
const CMDDMGLIST: [MainScreenItem;6] = [
MainScreenItem::Dmg1,
MainScreenItem::Dmg2,
MainScreenItem::Dmg3,
MainScreenItem::Dmg4,
MainScreenItem::Dmg5,
MainScreenItem::Dmg6,
];
pub fn get_touch_action(x: f32, y: f32, gesture: u8, ctx: &mut SystemState) -> () {
let x = x - 120.;
let y = -(y - 120.);
let touch_rad = (x*x)+(y*y);
let angle;
let next_state;
if (gesture == 0x3) | (gesture == 0x4) {
ctx.screen = match &ctx.screen {
Screen::Main(_) => Screen::Settings(SettingScreenItem { entry: SettingScreenEntry::NewGame, inner: false , prev: None}),
Screen::Settings(_) => Screen::Main(MainScreenItem::Life),
};
return;
}
match &ctx.screen {
Screen::Main(selected) => {
let mut bottom_selectable_list: [Option<MainScreenItem>;5] = [const {None};5];
let mut pos = 0;
if ctx.settings.show_cmd_tax {
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Tax);
pos += 1;
}
if ctx.settings.show_energy {
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Energy);
pos+=1;
};
if ctx.settings.show_experience {
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Experience);
pos+=1;
};
if ctx.settings.show_tickets {
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Tickets);
pos+=1;
};
if ctx.settings.show_infect {
bottom_selectable_list[pos] = Some(crate::state::MainScreenItem::Poison);
};
let bottom_count = bottom_selectable_list.iter().fold(0, |acc, x| acc+x.is_some() as u8);
if touch_rad > (70.*70.) {
angle = atan2_norm(y, x)*90.;
//ctx.game.life = angle as i32; //debug
let top;
let check_angles = if y >= 0. {
if ctx.settings.opponenets == 0 {
return;
}
top = true;
ctx.positions.get_top_list(ctx.settings.opponenets)
} else {
if bottom_count == 0 {
return;
}
top = false;
ctx.positions.get_bottom_list(bottom_count)
};
let touch_item = match check_angles.iter().position(|x| (x.angle.to_degrees()-angle).abs()<15.) {
Some(loc) => loc,
None => return,
};
let sel_match = if top {
Some(CMDDMGLIST.into_iter().nth(touch_item).unwrap_or(MainScreenItem::Dmg1))
} else {
bottom_selectable_list[touch_item]
};
if let Some(selected_item) = sel_match {
if selected_item == *selected {
next_state = Screen::Main(MainScreenItem::Life);
} else {
next_state = Screen::Main(selected_item);
}
} else {
next_state = Screen::Main(MainScreenItem::Life);
}
} else {
match selected {
crate::state::MainScreenItem::Life => {
let d = touch_inc_dec(y, gesture);
ctx.game.life = ctx.game.life.saturating_add(d as i32);
},
crate::state::MainScreenItem::Dmg1 => {
cmd_dmg_w_swap(ctx, x, y, gesture, 0);
},
crate::state::MainScreenItem::Dmg2 => {
cmd_dmg_w_swap(ctx, x, y, gesture, 1);
},
crate::state::MainScreenItem::Dmg3 => {
cmd_dmg_w_swap(ctx, x, y, gesture, 2);
},
crate::state::MainScreenItem::Dmg4 => {
cmd_dmg_w_swap(ctx, x, y, gesture, 3);
},
crate::state::MainScreenItem::Dmg5 => {
cmd_dmg_w_swap(ctx, x, y, gesture, 4);
},
crate::state::MainScreenItem::Dmg6 => {
cmd_dmg_w_swap(ctx, x, y, gesture, 5);
},
crate::state::MainScreenItem::Tax => {
cmd_tax_w_swap(ctx, x, y, gesture);
},
crate::state::MainScreenItem::Energy => {
let d = touch_inc_dec(y, gesture);
ctx.game.energy = ctx.game.energy.saturating_add_signed(d.into());
},
crate::state::MainScreenItem::Experience => {
let d = touch_inc_dec(y, gesture);
ctx.game.experience = ctx.game.experience.saturating_add_signed(d.into());
},
crate::state::MainScreenItem::Tickets => {
let d = touch_inc_dec(y, gesture);
ctx.game.tickets = ctx.game.tickets.saturating_add_signed(d.into());
},
crate::state::MainScreenItem::Poison => {
let d = touch_inc_dec(y, gesture);
ctx.game.infect = ctx.game.infect.saturating_add_signed(d.into());
},
};
next_state = ctx.screen;
};
},
Screen::Settings(selected) => {
if !selected.inner {
if gesture == 0x01_u8 {
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.prev(), inner: false, prev: selected.prev });
} else if gesture == 0x02_u8 {
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.next(), inner: false, prev: selected.prev });
} else {
if y > 55. {
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.prev(), inner: false, prev: selected.prev});
} else if y < -55. {
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry.next(), inner: false, prev: selected.prev });
} else {
let prev = match selected.entry {
SettingScreenEntry::NewGame => None,
SettingScreenEntry::Opponents => Some(ctx.settings.opponenets as u32),
SettingScreenEntry::StartingLife => Some(ctx.settings.starting_life as u32),
SettingScreenEntry::Colors => Some(Into::<u8>::into(ctx.settings.color_scheme) as u32),
SettingScreenEntry::Brightness => Some(ctx.settings.brightness.into()),
SettingScreenEntry::ShowTax => Some(ctx.settings.show_cmd_tax as u32),
SettingScreenEntry::ShowEnergy => Some(ctx.settings.show_energy as u32),
SettingScreenEntry::ShowExperience => Some(ctx.settings.show_experience as u32),
SettingScreenEntry::ShowTickets => Some(ctx.settings.show_tickets as u32),
SettingScreenEntry::ShowPoison => Some(ctx.settings.show_infect as u32),
};
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: true, prev: prev});
}
}
} else {
if x < -75. {
match selected.entry {
SettingScreenEntry::NewGame => {
ctx.game = Game {
life: ctx.settings.starting_life,
cmd_dmg: [CommanderDamage{main: 0, partner: 0, is_partner: false};6],
cmd_tax: CommanderDamage { main: 0, partner: 0, is_partner: false },
infect: 0,
energy: 0,
experience: 0,
tickets: 0,
monarch: false,
};
next_state = Screen::Main(MainScreenItem::Life);
},
_ => {
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: false, prev: None })
}
}
} else if x > 75. {
match selected.entry {
SettingScreenEntry::NewGame => {},
SettingScreenEntry::Opponents => {
ctx.settings.opponenets = selected.prev.unwrap_or(0) as u8;
},
SettingScreenEntry::StartingLife => {
ctx.settings.starting_life = selected.prev.unwrap_or(0) as i32;
},
SettingScreenEntry::Colors => {
ctx.settings.color_scheme =Into::<ColorScheme>::into(selected.prev.unwrap_or(0) as u8);
},
SettingScreenEntry::Brightness => {
ctx.settings.brightness = selected.prev.unwrap_or(0).into();
},
SettingScreenEntry::ShowTax => {
ctx.settings.show_cmd_tax = selected.prev.unwrap_or_default() != 0;
},
SettingScreenEntry::ShowEnergy => {
ctx.settings.show_energy = selected.prev.unwrap_or_default() != 0;
},
SettingScreenEntry::ShowExperience => {
ctx.settings.show_experience = selected.prev.unwrap_or_default() != 0;
},
SettingScreenEntry::ShowTickets => {
ctx.settings.show_tickets = selected.prev.unwrap_or_default() != 0;
},
SettingScreenEntry::ShowPoison => {
ctx.settings.show_infect = selected.prev.unwrap_or_default() != 0;
},
}
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: false, prev: None })
} else {
match selected.entry {
SettingScreenEntry::NewGame => {
},
SettingScreenEntry::Opponents => {
ctx.settings.opponenets = ctx.settings.opponenets.saturating_add_signed(touch_inc_dec(y, gesture));
},
SettingScreenEntry::StartingLife => {
ctx.settings.starting_life = ctx.settings.starting_life.saturating_add(touch_inc_dec(y, gesture) as i32);
},
SettingScreenEntry::Colors => {
if y > 40. {
ctx.settings.color_scheme = ctx.settings.color_scheme.dec();
} else if y < -40. {
ctx.settings.color_scheme = ctx.settings.color_scheme.inc();
}
},
SettingScreenEntry::Brightness => {
let tmp = touch_inc_dec(y, gesture);
if tmp > 0 {
ctx.settings.brightness = ctx.settings.brightness.inc();
} else {
ctx.settings.brightness = ctx.settings.brightness.dec();
}
},
SettingScreenEntry::ShowTax => {
let det = select_button(x, y, gesture);
if let Some(i) = det {
ctx.settings.show_cmd_tax = i;
}
},
SettingScreenEntry::ShowEnergy => {
let det = select_button(x, y, gesture);
if let Some(i) = det {
ctx.settings.show_energy = i;
}
},
SettingScreenEntry::ShowExperience => {
let det = select_button(x, y, gesture);
if let Some(i) = det {
ctx.settings.show_experience = i;
}
},
SettingScreenEntry::ShowTickets => {
let det = select_button(x, y, gesture);
if let Some(i) = det {
ctx.settings.show_tickets = i;
}
},
SettingScreenEntry::ShowPoison => {
let det = select_button(x, y, gesture);
if let Some(i) = det {
ctx.settings.show_infect = i;
}
},
}
next_state = Screen::Settings(SettingScreenItem { entry: selected.entry, inner: selected.inner, prev: selected.prev })
}
}
}
}
ctx.screen = next_state;
}
/// Approximates `atan2(y,x)` normalized to the `[0, 4)` range with a maximum
/// error of `0.1620` degrees.
fn atan2_norm(lhs: f32, rhs: f32) -> f32 {
const SIGN_MASK: u32 = 0x8000_0000;
const B: f32 = 0.596_227;
let y = lhs;
let x = rhs;
// Extract sign bits from floating point values
let ux_s = SIGN_MASK & x.to_bits();
let uy_s = SIGN_MASK & y.to_bits();
// Determine quadrant offset
let q = ((!ux_s & uy_s) >> 29 | ux_s >> 30) as f32;
// Calculate arctangent in the first quadrant
let bxy_a = (B * x * y).abs();
let n = bxy_a + y * y;
let atan_1q = n / (x * x + bxy_a + n);
// Translate it to the proper quadrant
let uatan_2q = (ux_s ^ uy_s) | atan_1q.to_bits();
q + f32::from_bits(uatan_2q)
}
fn touch_inc_dec(y: f32, gesture: u8) -> i8 {
if gesture == 0x05 {
if y >= 0. {
1
} else {
-1
}
} else if gesture == 0x02 {
5
} else if gesture == 0x01 {
-5
} else {
0
}
}
fn touch_left_right(x: f32, y: f32, gesture: u8) -> (i8, bool) {
if x <= 0. {
(touch_inc_dec(y, gesture), true)
} else {
(touch_inc_dec(y, gesture), false)
}
}
fn cmd_dmg_calc(ctx: &mut SystemState, x: f32, y: f32, gesture: u8, pos: usize) {
if ctx.game.cmd_dmg[pos].is_partner {
let (d, left) = touch_left_right(x, y, gesture);
if left {
ctx.game.cmd_dmg[pos].main = ctx.game.cmd_dmg[pos].main.saturating_add_signed(d);
} else {
ctx.game.cmd_dmg[pos].partner = ctx.game.cmd_dmg[pos].partner.saturating_add_signed(d);
}
} else {
let d = touch_inc_dec(y, gesture);
ctx.game.cmd_dmg[pos].main = ctx.game.cmd_dmg[pos].main.saturating_add_signed(d);
}
}
fn cmd_tax_calc(ctx: &mut SystemState, x: f32, y: f32, gesture: u8) {
if ctx.game.cmd_tax.is_partner {
let (mut d, left) = touch_left_right(x, y, gesture);
if d >= 0 {
d = 2;
} else {
d =-2;
}
if left {
ctx.game.cmd_tax.main = ctx.game.cmd_tax.main.saturating_add_signed(d);
} else {
ctx.game.cmd_tax.partner = ctx.game.cmd_tax.partner.saturating_add_signed(d);
}
} else {
let mut d = touch_inc_dec(y, gesture);
if d >= 0 {
d = 2;
} else {
d =-2;
}
ctx.game.cmd_tax.main = ctx.game.cmd_tax.main.saturating_add_signed(d);
}
}
/// true is left selection false is right selection
fn select_button(x: f32, y: f32, _gesture: u8) -> Option<bool> {
if (y<60.) & (y>-60.) {
if x<=0. {
Some(true)
} else {
Some(false)
}
} else {
None
}
}
fn cmd_dmg_w_swap(ctx: &mut SystemState, x: f32, y: f32, gesture: u8, pos: usize) {
if (x>-20.) & (x<20.) & (y< -30.)&(y>-50.) {
ctx.game.cmd_dmg[pos].is_partner = !ctx.game.cmd_dmg[pos].is_partner;
} else {
cmd_dmg_calc(ctx, x, y, gesture, pos);
}
}
fn cmd_tax_w_swap(ctx: &mut SystemState, x: f32, y: f32, gesture: u8) {
if (x>-20.) & (x<20.) & (y< -30.)&(y>-50.) {
ctx.game.cmd_tax.is_partner = !ctx.game.cmd_tax.is_partner;
} else {
cmd_tax_calc(ctx, x, y, gesture);
}
}