1#[cfg(target_arch = "wasm32")]
2#[macro_use]
3extern crate base64_serde;
4
5pub mod config;
6pub mod key_assign;
7
8pub use config::File;
9
10use schemars::{
11 gen::SchemaGenerator,
12 schema::{Schema, SchemaObject},
13 JsonSchema,
14};
15use serde::{de::DeserializeOwned, Deserialize, Serialize};
16
17pub use crate::key_assign::{
18 Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, InputState, KeyAssign,
19 KeyCode, MultiKey, SingleKey,
20};
21
22pub struct CoreInfo {
23 pub system_name: &'static str,
24 pub abbrev: &'static str,
25 pub file_extensions: &'static [&'static str],
26}
27
28#[derive(Default)]
29pub struct FrameBuffer {
30 pub width: usize,
31 pub height: usize,
32 pub buffer: Vec<Color>,
33}
34
35impl FrameBuffer {
36 pub fn new(width: usize, height: usize) -> Self {
37 let mut ret = Self::default();
38 ret.resize(width, height);
39 ret
40 }
41
42 pub fn resize(&mut self, width: usize, height: usize) {
43 if (width, height) == (self.width, self.height) {
44 return;
45 }
46 self.width = width;
47 self.height = height;
48 self.buffer.resize(width * height, Color::default());
49 }
50
51 pub fn pixel(&self, x: usize, y: usize) -> &Color {
52 &self.buffer[y * self.width + x]
53 }
54
55 pub fn pixel_mut(&mut self, x: usize, y: usize) -> &mut Color {
56 &mut self.buffer[y * self.width + x]
57 }
58}
59
60#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(try_from = "String", into = "String")]
62pub struct Color {
63 pub r: u8,
64 pub g: u8,
65 pub b: u8,
66}
67
68impl JsonSchema for Color {
69 fn schema_name() -> String {
70 "Color".to_string()
71 }
72
73 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
74 let mut schema: SchemaObject = <String>::json_schema(gen).into();
75 schema.format = Some("color".to_owned());
76 schema.into()
77 }
78}
79
80#[derive(thiserror::Error, Debug)]
81pub enum ParseColorError {
82 #[error("Color string must be hex color code: `#RRGGBB`")]
83 InvalidFormat,
84}
85
86impl TryFrom<String> for Color {
87 type Error = ParseColorError;
88
89 fn try_from(s: String) -> Result<Self, Self::Error> {
90 if s.len() != 7 || &s[0..1] != "#" || !s[1..].chars().all(|c| c.is_ascii_hexdigit()) {
91 Err(ParseColorError::InvalidFormat)?;
92 }
93
94 Ok(Color {
95 r: u8::from_str_radix(&s[1..3], 16).unwrap(),
96 g: u8::from_str_radix(&s[3..5], 16).unwrap(),
97 b: u8::from_str_radix(&s[5..7], 16).unwrap(),
98 })
99 }
100}
101
102impl From<Color> for String {
103 fn from(c: Color) -> Self {
104 format!("#{:02X}{:02X}{:02X}", c.r, c.g, c.b)
105 }
106}
107
108impl Color {
109 pub const fn new(r: u8, g: u8, b: u8) -> Self {
110 Self { r, g, b }
111 }
112}
113
114pub struct AudioBuffer {
115 pub sample_rate: u32,
116 pub channels: u16,
117 pub samples: Vec<AudioSample>,
118}
119
120impl Default for AudioBuffer {
121 fn default() -> Self {
122 Self {
123 sample_rate: 48000,
124 channels: 2,
125 samples: vec![],
126 }
127 }
128}
129
130impl AudioBuffer {
131 pub fn new(sample_rate: u32, channels: u16) -> Self {
132 Self {
133 sample_rate,
134 channels,
135 samples: vec![],
136 }
137 }
138}
139
140#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
141pub struct AudioSample {
142 pub left: i16,
143 pub right: i16,
144}
145
146impl AudioSample {
147 pub fn new(left: i16, right: i16) -> Self {
148 Self { left, right }
149 }
150}
151
152#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
153pub struct KeyConfig {
154 pub controllers: Vec<Vec<(String, KeyAssign)>>,
155}
156
157impl KeyConfig {
158 pub fn input(&self, input_state: &impl InputState) -> InputData {
159 let controllers = self
160 .controllers
161 .iter()
162 .map(|keys| {
163 keys.iter()
164 .map(|(key, assign)| (key.clone(), assign.pressed(input_state)))
165 .collect()
166 })
167 .collect();
168
169 InputData { controllers }
170 }
171}
172
173#[derive(Default)]
174pub struct InputData {
175 pub controllers: Vec<Vec<(String, bool)>>,
176}
177
178pub trait EmulatorCore {
179 type Error: std::error::Error + Send + Sync + 'static;
180 type Config: JsonSchema + Serialize + DeserializeOwned + Default;
181
182 fn core_info() -> &'static CoreInfo;
183
184 fn try_from_file(
185 data: &[u8],
186 backup: Option<&[u8]>,
187 config: &Self::Config,
188 ) -> Result<Self, Self::Error>
189 where
190 Self: Sized;
191 fn game_info(&self) -> Vec<(String, String)>;
192
193 fn set_config(&mut self, config: &Self::Config);
194
195 fn exec_frame(&mut self, render_graphics: bool);
196 fn reset(&mut self);
197
198 fn frame_buffer(&self) -> &FrameBuffer;
199 fn audio_buffer(&self) -> &AudioBuffer;
200
201 fn default_key_config() -> KeyConfig;
202 fn set_input(&mut self, input: &InputData);
203
204 fn backup(&self) -> Option<Vec<u8>>;
205
206 fn save_state(&self) -> Vec<u8>;
207 fn load_state(&mut self, data: &[u8]) -> Result<(), Self::Error>;
208}