1use anyhow::{Context, Result};
7use std::path::Path;
8
9use oxihuman_core::policy::Policy;
10use oxihuman_export::params_json::import_params;
11use oxihuman_mesh::MeshBuffers;
12use oxihuman_morph::params::ParamState;
13use oxihuman_morph::{apply_expression_to_engine, ExpressionPreset};
14
15pub fn load_params(src: &str) -> Result<ParamState> {
17 let json_str = if Path::new(src).exists() {
18 std::fs::read_to_string(src)?
19 } else {
20 src.to_string()
21 };
22 let val: serde_json::Value = serde_json::from_str(&json_str)?;
23 import_params(&val)
24}
25
26pub fn build_mesh_with_expression(
28 base_path: &Path,
29 targets_dir: Option<&Path>,
30 params: ParamState,
31 policy: Policy,
32 output: &Path,
33 expression_preset: &ExpressionPreset,
34) -> Result<MeshBuffers> {
35 use oxihuman_core::parser::obj::parse_obj;
36 use oxihuman_mesh::normals::compute_normals;
37 use oxihuman_mesh::suit::apply_suit_flag;
38 use oxihuman_morph::HumanEngine;
39
40 let base_src = std::fs::read_to_string(base_path)
41 .with_context(|| format!("reading base OBJ: {}", base_path.display()))?;
42 let base_mesh = parse_obj(&base_src).context("parsing base OBJ")?;
43 let mut engine = HumanEngine::new(base_mesh, policy);
44
45 if let Some(td) = targets_dir {
47 if td.exists() {
48 if let Ok(n) = engine.load_targets_from_dir_auto(td) {
49 eprintln!("OxiHuman: loaded {} body targets", n);
50 }
51 }
52 }
53
54 let expr_dir = targets_dir.map(|td| td.join("expression").join("units").join("caucasian"));
56
57 if let Some(ref ed) = expr_dir {
58 let expr_count = apply_expression_to_engine(&mut engine, expression_preset, ed);
59 if expr_count > 0 {
60 eprintln!(
61 "OxiHuman: applied {} expression target(s) for '{}'",
62 expr_count, expression_preset.name
63 );
64 } else {
65 eprintln!(
66 "OxiHuman: expression preset '{}' (apply manually with --targets)",
67 expression_preset.name
68 );
69 }
70 } else {
71 eprintln!(
72 "OxiHuman: expression preset '{}' (apply manually with --targets)",
73 expression_preset.name
74 );
75 }
76
77 engine.set_params(params);
78 let morph_buffers = engine.build_mesh();
79
80 let mut mesh = MeshBuffers::from_morph(morph_buffers);
81 compute_normals(&mut mesh);
82 apply_suit_flag(&mut mesh);
83
84 oxihuman_export::glb::export_glb(&mesh, output)
85 .with_context(|| format!("exporting GLB to {}", output.display()))?;
86
87 Ok(mesh)
88}
89
90pub fn build_mesh_from_base(
92 base: &Path,
93 targets: Option<&Path>,
94 params: ParamState,
95 policy: Policy,
96) -> Result<MeshBuffers> {
97 use oxihuman_core::parser::obj::parse_obj;
98 use oxihuman_mesh::normals::compute_normals;
99 use oxihuman_mesh::suit::apply_suit_flag;
100 use oxihuman_morph::HumanEngine;
101
102 let src = std::fs::read_to_string(base)
103 .with_context(|| format!("reading base OBJ: {}", base.display()))?;
104 let obj = parse_obj(&src).context("parsing base OBJ")?;
105 let mut engine = HumanEngine::new(obj, policy);
106
107 if let Some(td) = targets {
108 if td.exists() {
109 if let Ok(n) = engine.load_targets_from_dir_auto(td) {
110 eprintln!("OxiHuman: loaded {} targets", n);
111 }
112 }
113 }
114
115 engine.set_params(params);
116 let morph_buf = engine.build_mesh();
117 let mut mesh = MeshBuffers::from_morph(morph_buf);
118 compute_normals(&mut mesh);
119 apply_suit_flag(&mut mesh);
120 Ok(mesh)
121}