feat(live2d): 添加 Pose 处理模块以管理互斥 Part 的显示状态,优化模型加载和参数更新
This commit is contained in:
@@ -64,6 +64,12 @@ pub struct CubismModel {
|
||||
pub param_ids: Vec<String>,
|
||||
/// 参数索引映射(id → index)
|
||||
pub param_index: std::collections::HashMap<String, usize>,
|
||||
/// Part 数量
|
||||
pub part_count: usize,
|
||||
/// Part ID 列表(与 Core 内部顺序一致)
|
||||
pub part_ids: Vec<String>,
|
||||
/// Part 索引映射(id → index)
|
||||
pub part_index: std::collections::HashMap<String, usize>,
|
||||
/// drawable 数量
|
||||
pub drawable_count: usize,
|
||||
/// canvas 信息
|
||||
@@ -134,6 +140,20 @@ impl CubismModel {
|
||||
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;
|
||||
|
||||
@@ -152,8 +172,8 @@ impl CubismModel {
|
||||
};
|
||||
|
||||
println!(
|
||||
"[Live2D] 模型加载成功: 参数={} drawable={} canvas={:?} origin=({:.1},{:.1})x{:.0}ppu",
|
||||
param_count, drawable_count, canvas.size, canvas.origin[0], canvas.origin[1], canvas.pixels_per_unit
|
||||
"[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 {
|
||||
@@ -165,6 +185,9 @@ impl CubismModel {
|
||||
param_count,
|
||||
param_ids,
|
||||
param_index,
|
||||
part_count,
|
||||
part_ids,
|
||||
part_index,
|
||||
drawable_count,
|
||||
canvas,
|
||||
})
|
||||
@@ -205,19 +228,34 @@ impl CubismModel {
|
||||
/// 按参数 ID 设置值
|
||||
pub fn set_param(&self, core: &CubismCore, id: &str, value: f32) -> bool {
|
||||
if let Some(&idx) = self.param_index.get(id) {
|
||||
let slice = self.param_values_mut(core);
|
||||
slice[idx] = value;
|
||||
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<f32> {
|
||||
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<f32> {
|
||||
if index >= self.param_count {
|
||||
return None;
|
||||
}
|
||||
let slice = self.param_values_mut(core);
|
||||
Some(slice[idx])
|
||||
Some(slice[index])
|
||||
}
|
||||
|
||||
/// 将所有参数重置为默认值
|
||||
@@ -229,6 +267,36 @@ impl CubismModel {
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取 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<usize> {
|
||||
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<f32> {
|
||||
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) };
|
||||
|
||||
Reference in New Issue
Block a user