1use std::path::PathBuf;
2
3use pfx_gpu::screens::{Budget, Device, ScreenPolicy};
4use pfx_input::{Backend, LayoutSource};
5use pfx_live::flat::{Icons, SpriteImage};
6use pfx_live::renderer::Exposure;
7use pfx_live::upscale::Filter;
8use pfx_play::Settings;
9
10pub const WARM_BUDGET: f64 = 2.0;
11
12pub enum Pads {
13 None,
14 Gilrs,
15 Backend(Box<dyn Backend>),
16}
17
18pub type Crash = Box<dyn Fn(&str)>;
19
20pub struct Config {
21 pub name: String,
22 pub title: Option<String>,
23 pub crash: Option<Crash>,
24 pub version: String,
25 pub scene: Option<PathBuf>,
26 pub settings: Settings,
27 pub screen: ScreenPolicy,
28 pub device: Option<Device>,
29 pub render_scale: f32,
30 pub budget: Option<Budget>,
31 pub filter: Filter,
32 pub exposure: Exposure,
33 pub fonts: Vec<Vec<u8>>,
34 pub pads: Pads,
35 pub seed: u64,
36 pub sound: bool,
37 pub layout: Option<Box<dyn LayoutSource>>,
38 pub icons: Option<Icons>,
39 pub sprites: Option<SpriteImage>,
40 pub environment: Option<EnvironmentTexels>,
41 pub warm_budget: f64,
42}
43
44#[derive(Clone, Debug, PartialEq)]
45pub struct EnvironmentTexels {
46 pub width: u32,
47 pub height: u32,
48 pub linear: Vec<[f32; 4]>,
49 pub intensity: f32,
50}
51
52impl Config {
53 pub fn new(
54 name: impl Into<String>,
55 version: impl Into<String>,
56 scene: impl Into<PathBuf>,
57 ) -> Self {
58 Self {
59 scene: Some(scene.into()),
60 ..Self::flat(name, version)
61 }
62 }
63
64 pub fn flat(name: impl Into<String>, version: impl Into<String>) -> Self {
65 Self {
66 name: name.into(),
67 title: None,
68 crash: None,
69 version: version.into(),
70 scene: None,
71 settings: Settings::default(),
72 screen: ScreenPolicy::default(),
73 device: None,
74 render_scale: 1.0,
75 budget: None,
76 filter: Filter::Sharp,
77 exposure: Exposure::Auto { bias: 0.0 },
78 fonts: Vec::new(),
79 pads: Pads::Gilrs,
80 seed: 0,
81 sound: true,
82 layout: None,
83 icons: None,
84 sprites: None,
85 environment: None,
86 warm_budget: WARM_BUDGET,
87 }
88 }
89
90 pub fn bind_text(&self) {
91 pfx_load::scene::bind("name", &self.name);
92 pfx_load::scene::bind("version", &self.version);
93 }
94
95 pub fn warm_budget(mut self, seconds: f64) -> Self {
96 self.warm_budget = seconds;
97 self
98 }
99
100 pub fn title(mut self, title: impl Into<String>) -> Self {
101 self.title = Some(title.into());
102 self
103 }
104
105 pub fn window_title(&self) -> &str {
106 self.title.as_deref().unwrap_or(&self.name)
107 }
108
109 pub fn crash(mut self, hook: impl Fn(&str) + 'static) -> Self {
110 self.crash = Some(Box::new(hook));
111 self
112 }
113
114 pub fn settings(mut self, settings: Settings) -> Self {
115 self.settings = settings;
116 self
117 }
118
119 pub fn screen(mut self, screen: ScreenPolicy) -> Self {
120 self.screen = screen;
121 self
122 }
123
124 pub fn device(mut self, device: Device) -> Self {
125 self.device = Some(device);
126 self
127 }
128
129 pub fn render_scale(mut self, scale: f32) -> Self {
130 self.render_scale = scale;
131 self
132 }
133
134 pub fn budget(mut self, budget: Budget) -> Self {
135 self.budget = Some(budget);
136 self
137 }
138
139 pub fn exposure(mut self, exposure: Exposure) -> Self {
140 self.exposure = exposure;
141 self
142 }
143
144 pub fn filter(mut self, filter: Filter) -> Self {
145 self.filter = filter;
146 self
147 }
148
149 pub fn font(mut self, bytes: impl Into<Vec<u8>>) -> Self {
150 self.fonts.push(bytes.into());
151 self
152 }
153
154 pub fn pads(mut self, pads: Pads) -> Self {
155 self.pads = pads;
156 self
157 }
158
159 pub fn seed(mut self, seed: u64) -> Self {
160 self.seed = seed;
161 self
162 }
163
164 pub fn layout(mut self, layout: Box<dyn LayoutSource>) -> Self {
165 self.layout = Some(layout);
166 self
167 }
168
169 pub fn icons(mut self, icons: Icons) -> Self {
170 self.icons = Some(icons);
171 self
172 }
173
174 pub fn sprites(mut self, sprites: SpriteImage) -> Self {
175 self.sprites = Some(sprites);
176 self
177 }
178
179 pub fn environment(mut self, environment: EnvironmentTexels) -> Self {
180 self.environment = Some(environment);
181 self
182 }
183
184 pub fn sound(mut self, on: bool) -> Self {
185 self.sound = on;
186 self
187 }
188}
189
190pub(crate) fn report(name: &str, crash: Option<&Crash>, error: &str) {
191 eprintln!("{name}: {error}");
192 if let Some(crash) = crash {
193 crash(error);
194 }
195}