//! Cubism Model 加载与管理 //! //! 封装 moc3 读取 → revive → model 初始化 → 参数更新 → drawable 数据提取。 use super::core_ffi::{ alloc_aligned, AlignedBuffer, CubismCore, CsmVector2, CSM_ALIGNOF_MOC, CSM_ALIGNOF_MODEL, }; use anyhow::{anyhow, Context, Result}; use std::path::Path; /// 一个 drawable 的渲染所需数据快照 #[derive(Clone)] pub struct DrawableSnapshot { /// 在 Core drawable 数组中的原始索引(用于查 mask 引用) pub index: usize, pub texture_index: i32, pub draw_order: i32, pub render_order: i32, pub opacity: f32, pub blend_mode: i32, pub constant_flags: u8, pub dynamic_flags: u8, pub vertex_positions: Vec<[f32; 2]>, pub vertex_uvs: Vec<[f32; 2]>, pub indices: Vec, pub multiply_color: [f32; 4], pub screen_color: [f32; 4], /// 本 drawable 依赖的 mask drawable 索引(空表示无遮罩) pub mask_indices: Vec, pub mask_counts: i32, } /// Canvas 信息 #[derive(Clone, Copy, Debug, Default)] pub struct CanvasInfo { pub size: [f32; 2], pub origin: [f32; 2], pub pixels_per_unit: f32, } /// 参数信息 pub struct ParameterInfo { pub id: String, pub min_value: f32, pub max_value: f32, pub default_value: f32, } /// 活跃的 Cubism Model pub struct CubismModel { /// Core 句柄(保持引用防止 .so 卸载) _core: std::sync::Arc, /// moc3 原始数据(对齐 64) _moc_buf: AlignedBuffer, /// moc 指针 moc: *mut std::ffi::c_void, /// model 内存(对齐 16) _model_buf: AlignedBuffer, /// model 指针 model: *mut std::ffi::c_void, /// 参数数量 pub param_count: usize, /// 参数 ID 列表(与 Core 内部顺序一致) pub param_ids: Vec, /// 参数索引映射(id → index) pub param_index: std::collections::HashMap, /// Part 数量 pub part_count: usize, /// Part ID 列表(与 Core 内部顺序一致) pub part_ids: Vec, /// Part 索引映射(id → index) pub part_index: std::collections::HashMap, /// drawable 数量 pub drawable_count: usize, /// canvas 信息 pub canvas: CanvasInfo, } // model 指针可跨线程发送(渲染线程独占使用) unsafe impl Send for CubismModel {} impl CubismModel { /// 从 moc3 文件加载 model pub fn load(core: std::sync::Arc, moc3_path: &Path) -> Result { let moc_data = std::fs::read(moc3_path) .with_context(|| format!("读取 moc3 失败: {}", moc3_path.display()))?; // 分配 64 对齐内存 let mut moc_buf = alloc_aligned(moc_data.len(), CSM_ALIGNOF_MOC)?; unsafe { std::ptr::copy_nonoverlapping(moc_data.as_ptr(), moc_buf.as_ptr(), moc_data.len()); } // 检查一致性 let valid = unsafe { (core.csm_has_moc_consistency)(moc_buf.as_mut_void(), moc_data.len() as u32) }; if valid != 1 { return Err(anyhow!("moc3 一致性检查失败(文件损坏或版本不支持)")); } // Revive moc let moc = unsafe { (core.csm_revive_moc_in_place)(moc_buf.as_mut_void(), moc_data.len() as u32) }; if moc.is_null() { return Err(anyhow!("csmReviveMocInPlace 返回空指针")); } // 获取 model 所需大小 let model_size = unsafe { (core.csm_get_sizeof_model)(moc) }; if model_size == 0 { return Err(anyhow!("csmGetSizeofModel 返回 0")); } // 分配 16 对齐内存 let mut model_buf = alloc_aligned(model_size as usize, CSM_ALIGNOF_MODEL)?; let model = unsafe { (core.csm_initialize_model_in_place)( moc, model_buf.as_mut_void(), model_size, ) }; if model.is_null() { return Err(anyhow!("csmInitializeModelInPlace 返回空指针")); } // 读取参数信息 let param_count = unsafe { (core.csm_get_parameter_count)(model) } as usize; let param_ids_ptr = unsafe { (core.csm_get_parameter_ids)(model) }; let mut param_ids = Vec::with_capacity(param_count); let mut param_index = std::collections::HashMap::new(); for i in 0..param_count { let id = unsafe { super::core_ffi::cstr_ptr_to_string(*param_ids_ptr.add(i)) .unwrap_or_default() }; param_index.insert(id.clone(), i); param_ids.push(id); } // 读取 part 信息(Pose 会按 PartOpacity 切换互斥部件,如 Haru 的两组手臂) let part_count = unsafe { (core.csm_get_part_count)(model) } as usize; let part_ids_ptr = unsafe { (core.csm_get_part_ids)(model) }; let mut part_ids = Vec::with_capacity(part_count); let mut part_index = std::collections::HashMap::new(); for i in 0..part_count { let id = unsafe { super::core_ffi::cstr_ptr_to_string(*part_ids_ptr.add(i)) .unwrap_or_default() }; part_index.insert(id.clone(), i); part_ids.push(id); } // 读取 drawable 数量 let drawable_count = unsafe { (core.csm_get_drawable_count)(model) } as usize; // 读取 canvas 信息 let mut size = CsmVector2::default(); let mut origin = CsmVector2::default(); let mut ppu = 0.0f32; unsafe { (core.csm_read_canvas_info)(model, &mut size, &mut origin, &mut ppu); } let canvas = CanvasInfo { size: [size.x, size.y], origin: [origin.x, origin.y], pixels_per_unit: ppu, }; println!( "[Live2D] 模型加载成功: 参数={} part={} drawable={} canvas={:?} origin=({:.1},{:.1})x{:.0}ppu", param_count, part_count, drawable_count, canvas.size, canvas.origin[0], canvas.origin[1], canvas.pixels_per_unit ); Ok(Self { _core: core, _moc_buf: moc_buf, moc, _model_buf: model_buf, model, param_count, param_ids, param_index, part_count, part_ids, part_index, drawable_count, canvas, }) } /// 获取参数最小值 pub fn param_min_values(&self, core: &CubismCore) -> Vec { unsafe { let p = (core.csm_get_parameter_minimum_values)(self.model); std::slice::from_raw_parts(p, self.param_count).to_vec() } } /// 获取参数最大值 pub fn param_max_values(&self, core: &CubismCore) -> Vec { unsafe { let p = (core.csm_get_parameter_maximum_values)(self.model); std::slice::from_raw_parts(p, self.param_count).to_vec() } } /// 获取参数默认值 pub fn param_default_values(&self, core: &CubismCore) -> Vec { unsafe { let p = (core.csm_get_parameter_default_values)(self.model); std::slice::from_raw_parts(p, self.param_count).to_vec() } } /// 获取参数值缓冲区(可读写) pub fn param_values_mut(&self, core: &CubismCore) -> &mut [f32] { unsafe { let p = (core.csm_get_parameter_values)(self.model); std::slice::from_raw_parts_mut(p, self.param_count) } } /// 按参数 ID 设置值 pub fn set_param(&self, core: &CubismCore, id: &str, value: f32) -> bool { if let Some(&idx) = self.param_index.get(id) { self.set_param_by_index(core, idx, value); true } else { false } } /// 按参数索引设置值 pub fn set_param_by_index(&self, core: &CubismCore, index: usize, value: f32) { if index < self.param_count { let slice = self.param_values_mut(core); slice[index] = value; } } /// 按参数 ID 获取值 pub fn get_param(&self, core: &CubismCore, id: &str) -> Option { let idx = *self.param_index.get(id)?; self.get_param_by_index(core, idx) } /// 按参数索引获取值 pub fn get_param_by_index(&self, core: &CubismCore, index: usize) -> Option { if index >= self.param_count { return None; } let slice = self.param_values_mut(core); Some(slice[index]) } /// 将所有参数重置为默认值 pub fn reset_to_default(&self, core: &CubismCore) { let defaults = self.param_default_values(core); let slice = self.param_values_mut(core); for (i, v) in defaults.into_iter().enumerate() { slice[i] = v; } } /// 获取 PartOpacity 缓冲区(可读写) pub fn part_opacities_mut(&self, core: &CubismCore) -> &mut [f32] { unsafe { let p = (core.csm_get_part_opacities)(self.model); std::slice::from_raw_parts_mut(p, self.part_count) } } /// 按 Part ID 获取索引 pub fn part_index(&self, id: &str) -> Option { self.part_index.get(id).copied() } /// 按 Part 索引设置 opacity pub fn set_part_opacity_by_index(&self, core: &CubismCore, index: usize, opacity: f32) { if index < self.part_count { let slice = self.part_opacities_mut(core); slice[index] = opacity.clamp(0.0, 1.0); } } /// 按 Part 索引获取 opacity pub fn get_part_opacity_by_index(&self, core: &CubismCore, index: usize) -> Option { if index >= self.part_count { return None; } let slice = self.part_opacities_mut(core); Some(slice[index]) } /// 更新 model(应用参数变化,重新计算顶点/不透明度等) pub fn update(&self, core: &CubismCore) { unsafe { (core.csm_update_model)(self.model) }; } /// 重置动态标志 pub fn reset_dynamic_flags(&self, core: &CubismCore) { unsafe { (core.csm_reset_drawable_dynamic_flags)(self.model) }; } /// 获取所有 drawable 的渲染数据快照(按 render order 排序) pub fn drawable_snapshots(&self, core: &CubismCore) -> Vec { let count = self.drawable_count; unsafe { let render_orders = (core.csm_get_render_orders)(self.model); let texture_indices = (core.csm_get_drawable_texture_indices)(self.model); let draw_orders = (core.csm_get_drawable_draw_orders)(self.model); let opacities = (core.csm_get_drawable_opacities)(self.model); let blend_modes = (core.csm_get_drawable_blend_modes)(self.model); let const_flags = (core.csm_get_drawable_constant_flags)(self.model); let dyn_flags = (core.csm_get_drawable_dynamic_flags)(self.model); let mask_counts = (core.csm_get_drawable_mask_counts)(self.model); let vertex_counts = (core.csm_get_drawable_vertex_counts)(self.model); let vertex_positions = (core.csm_get_drawable_vertex_positions)(self.model); let vertex_uvs = (core.csm_get_drawable_vertex_uvs)(self.model); let index_counts = (core.csm_get_drawable_index_counts)(self.model); let indices = (core.csm_get_drawable_indices)(self.model); let multiply_colors = (core.csm_get_drawable_multiply_colors)(self.model); let screen_colors = (core.csm_get_drawable_screen_colors)(self.model); let masks = (core.csm_get_drawable_masks)(self.model); // 先收集每个 drawable 的原始索引 let mut items: Vec<(usize, i32)> = (0..count) .map(|i| (i, *render_orders.add(i))) .collect(); // 按 render_order 升序排列 items.sort_by_key(|&(_, ro)| ro); items .into_iter() .map(|(i, ro)| { let vc = *vertex_counts.add(i) as usize; let ic = *index_counts.add(i) as usize; let vp = *vertex_positions.add(i); let vu = *vertex_uvs.add(i); let idx = *indices.add(i); let mut verts = Vec::with_capacity(vc); let mut uvs = Vec::with_capacity(vc); for v in 0..vc { let p = *vp.add(v); let u = *vu.add(v); verts.push([p.x, p.y]); uvs.push([u.x, u.y]); } let mut idx_vec = Vec::with_capacity(ic); for k in 0..ic { idx_vec.push(*idx.add(k)); } let mc = *multiply_colors.add(i); let sc = *screen_colors.add(i); // 取出本 drawable 的 mask 索引列表 let mk = *mask_counts.add(i) as usize; let mut mask_indices: Vec = Vec::with_capacity(mk); if mk > 0 { let mptr = *masks.add(i); for k in 0..mk { mask_indices.push(*mptr.add(k)); } } DrawableSnapshot { index: i, texture_index: *texture_indices.add(i), draw_order: *draw_orders.add(i), render_order: ro, opacity: *opacities.add(i), blend_mode: *blend_modes.add(i), constant_flags: *const_flags.add(i), dynamic_flags: *dyn_flags.add(i), vertex_positions: verts, vertex_uvs: uvs, indices: idx_vec, multiply_color: [mc.x, mc.y, mc.z, mc.w], screen_color: [sc.x, sc.y, sc.z, sc.w], mask_indices, mask_counts: mk as i32, } }) .collect() } } }