BlueGit

golden-age paperdoll-renderer

Files

paperdoll-renderer / src / foundation.rs

foundation.rs

foundation.rs 9.0 KiB Download Raw
1//! Honest capability report for the foundation shell.
2//!
3//! Later features add import, animation, rendering and preview. Until those
4//! features land, this module must keep reporting them as not built.
5
6/// Product capability named by the design.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum Capability {
9 ProjectShell,
10 ObjMtlTextures,
11 Fbx,
12 GltfGlb,
13 SkeletalAnimation,
14 AttachmentEditor,
15 PaperdollRender,
16 Preview2d,
17}
18
19/// Whether this build actually contains the capability.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum Availability {
22 Present,
23 NotBuilt,
24}
25
26/// What the process should do with the command line it received.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum CliRequest {
29 OpenWindow,
30 PrintStatus,
31 PrintHelp,
32}
33
34/// Rejected command line. A model path is rejected on purpose: accepting one
35/// would look like import support.
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub enum CliError {
38 UnknownArgument(String),
39}
40
41const CAPABILITIES: [Capability; 8] = [
42 Capability::ProjectShell,
43 Capability::ObjMtlTextures,
44 Capability::Fbx,
45 Capability::GltfGlb,
46 Capability::SkeletalAnimation,
47 Capability::AttachmentEditor,
48 Capability::PaperdollRender,
49 Capability::Preview2d,
50];
51
52pub fn capabilities() -> &'static [Capability] {
53 &CAPABILITIES
54}
55
56pub fn availability(capability: Capability) -> Availability {
57 match capability {
58 Capability::ProjectShell | Capability::ObjMtlTextures | Capability::GltfGlb => {
59 Availability::Present
60 }
61 Capability::Fbx
62 | Capability::SkeletalAnimation
63 | Capability::AttachmentEditor
64 | Capability::PaperdollRender
65 | Capability::Preview2d => Availability::NotBuilt,
66 }
67}
68
69pub fn machine_key(capability: Capability) -> &'static str {
70 match capability {
71 Capability::ProjectShell => "project_shell",
72 Capability::ObjMtlTextures => "obj_mtl_textures",
73 Capability::Fbx => "fbx",
74 Capability::GltfGlb => "gltf_glb",
75 Capability::SkeletalAnimation => "skeletal_animation",
76 Capability::AttachmentEditor => "attachment_editor",
77 Capability::PaperdollRender => "paperdoll_render",
78 Capability::Preview2d => "preview_2d",
79 }
80}
81
82pub fn machine_state(availability: Availability) -> &'static str {
83 match availability {
84 Availability::Present => "present",
85 Availability::NotBuilt => "not_built",
86 }
87}
88
89pub fn dutch_label(capability: Capability) -> &'static str {
90 match capability {
91 Capability::ProjectShell => "projectschil",
92 Capability::ObjMtlTextures => "OBJ + MTL + textures",
93 Capability::Fbx => "FBX",
94 Capability::GltfGlb => "glTF/GLB",
95 Capability::SkeletalAnimation => "skeletanimatie",
96 Capability::AttachmentEditor => "3D-attachmenteditor",
97 Capability::PaperdollRender => "paperdoll-render",
98 Capability::Preview2d => "2D-preview",
99 }
100}
101
102pub fn dutch_state(availability: Availability) -> &'static str {
103 match availability {
104 Availability::Present => "aanwezig",
105 Availability::NotBuilt => "niet gebouwd",
106 }
107}
108
109pub fn dutch_summary() -> &'static str {
110 "Deze build leest glTF/GLB uit tot meshes, materialen, textures, joints en animatieclips, en OBJ+MTL als statische mesh. FBX, het afspelen van skeletanimatie, de attachment-editor, paperdoll-render en de 2D-preview zijn niet gebouwd."
111}
112
113/// Stable status text shared by `--status` and the window.
114pub fn report() -> String {
115 let mut lines = Vec::with_capacity(2 + CAPABILITIES.len());
116 lines.push("name: Paperdoll Renderer".to_string());
117 lines.push("phase: model-import".to_string());
118 for capability in CAPABILITIES {
119 lines.push(format!(
120 "{}: {}",
121 machine_key(capability),
122 machine_state(availability(capability))
123 ));
124 }
125 lines.join("\n")
126}
127
128/// Shared libraries the X11 window loads. `ldd` does not list them: eframe
129/// opens them at runtime. A missing one panics inside that loader, so the
130/// shell checks first.
131pub const LINUX_WINDOW_LIBRARIES: &[&str] = &[
132 "libxkbcommon-x11.so.0",
133 "libxkbcommon.so.0",
134 "libxcb.so.1",
135 "libX11.so.6",
136 "libGL.so.1",
137];
138
139pub fn missing_library_message(missing: &[&str]) -> String {
140 format!(
141 "het statusvenster kan niet openen; deze bibliotheken ontbreken: {}. Import en render zijn niet gebouwd.",
142 missing.join(", ")
143 )
144}
145
146#[cfg(target_os = "linux")]
147pub fn missing_window_libraries() -> Vec<&'static str> {
148 LINUX_WINDOW_LIBRARIES
149 .iter()
150 .copied()
151 .filter(|name| {
152 // Safety: `name` is a nul-free soname literal. A missing library
153 // returns Err; no symbol from the library is called.
154 unsafe { libloading::Library::new(name).is_err() }
155 })
156 .collect()
157}
158
159pub fn help_text() -> &'static str {
160 "\
161Paperdoll Renderer — modelimport
162
163Gebruik:
164 paperdoll-renderer open het projectvenster
165 paperdoll-renderer --status print de status en sluit
166 paperdoll-renderer --help toon deze tekst
167
168Een modelpad op de opdrachtregel wordt niet geaccepteerd. glTF/GLB en OBJ+MTL worden in het venster gelezen. FBX en render zijn niet gebouwd."
169}
170
171pub fn parse_cli<'a, I>(args: I) -> Result<CliRequest, CliError>
172where
173 I: IntoIterator<Item = &'a str>,
174{
175 let mut request = CliRequest::OpenWindow;
176 for arg in args {
177 match arg {
178 "--help" | "-h" => request = CliRequest::PrintHelp,
179 "--status" => {
180 if request != CliRequest::PrintHelp {
181 request = CliRequest::PrintStatus;
182 }
183 }
184 other => {
185 return Err(CliError::UnknownArgument(other.to_string()));
186 }
187 }
188 }
189 Ok(request)
190}
191
192#[cfg(test)]
193mod tests {
194 use super::*;
195
196 #[test]
197 fn import_formats_are_present_and_render_is_not() {
198 assert_eq!(
199 availability(Capability::ProjectShell),
200 Availability::Present
201 );
202 assert_eq!(availability(Capability::GltfGlb), Availability::Present);
203 assert_eq!(
204 availability(Capability::ObjMtlTextures),
205 Availability::Present
206 );
207 for capability in [
208 Capability::Fbx,
209 Capability::SkeletalAnimation,
210 Capability::AttachmentEditor,
211 Capability::PaperdollRender,
212 Capability::Preview2d,
213 ] {
214 assert_eq!(
215 availability(capability),
216 Availability::NotBuilt,
217 "{capability:?} must stay not built"
218 );
219 }
220 }
221
222 #[test]
223 fn status_report_matches_the_import_build() {
224 let report = report();
225 assert!(report.starts_with("name: Paperdoll Renderer\nphase: model-import\n"));
226 for key in ["project_shell", "obj_mtl_textures", "gltf_glb"] {
227 assert!(
228 report.contains(&format!("{key}: present")),
229 "missing present {key} in {report}"
230 );
231 }
232 for key in [
233 "fbx",
234 "skeletal_animation",
235 "attachment_editor",
236 "paperdoll_render",
237 "preview_2d",
238 ] {
239 assert!(
240 report.contains(&format!("{key}: not_built")),
241 "missing {key} in {report}"
242 );
243 assert!(
244 !report.contains(&format!("{key}: present")),
245 "{key} must not be reported as present"
246 );
247 }
248 let summary = dutch_summary();
249 assert!(summary.contains("niet gebouwd"));
250 assert!(summary.contains("OBJ+MTL"));
251 assert!(summary.contains("glTF/GLB"));
252 let lower = summary.to_lowercase();
253 assert!(!lower.contains("render werkt"));
254 assert!(!lower.contains("fbx-import werkt"));
255 }
256
257 #[test]
258 fn cli_opens_a_window_or_prints_status_and_rejects_model_paths() {
259 assert_eq!(parse_cli(std::iter::empty()), Ok(CliRequest::OpenWindow));
260 assert_eq!(parse_cli(["--status"]), Ok(CliRequest::PrintStatus));
261 assert_eq!(parse_cli(["--help"]), Ok(CliRequest::PrintHelp));
262 assert_eq!(parse_cli(["-h", "--status"]), Ok(CliRequest::PrintHelp));
263 assert_eq!(
264 parse_cli(["tests/fixtures/bodies/test-body-male.glb"]),
265 Err(CliError::UnknownArgument(
266 "tests/fixtures/bodies/test-body-male.glb".to_string()
267 ))
268 );
269 assert_eq!(
270 parse_cli(["--status", "--render"]),
271 Err(CliError::UnknownArgument("--render".to_string()))
272 );
273 assert!(help_text().contains("niet gebouwd"));
274 }
275
276 #[test]
277 fn missing_library_message_names_the_library_and_does_not_claim_import() {
278 let message = missing_library_message(&["libxkbcommon-x11.so.0"]);
279 assert!(message.contains("libxkbcommon-x11.so.0"));
280 assert!(message.contains("niet gebouwd"));
281 assert!(!message.to_lowercase().contains("import werkt"));
282 assert!(!LINUX_WINDOW_LIBRARIES.is_empty());
283 }
284}