use crate::{
components::transform::HaTransform,
image::{Image, ImageError},
math::*,
mesh::rig::{deformer::DeformerArea, skeleton::Skeleton, Rig},
};
use core::{
prefab::{Prefab, PrefabComponent},
scripting::intuicio::data::{
lifetime::Lifetime,
managed::{DynamicManaged, DynamicManagedRef, DynamicManagedRefMut},
},
};
use oxygengine_core::scripting::{
intuicio::prelude::{ValueReadAccess, ValueWriteAccess},
ScriptingValue,
};
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeMap, HashMap},
ops::{Deref, DerefMut},
};
use utils::prelude::Grid2d;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HaRigSkeleton {
#[serde(default)]
bone_transforms: HashMap<String, HaTransform>,
#[serde(skip)]
hierarchy_matrices: Vec<Mat4>,
#[serde(skip)]
bone_matrices: Vec<Mat4>,
#[serde(skip)]
dirty: bool,
}
impl Default for HaRigSkeleton {
fn default() -> Self {
Self {
bone_transforms: Default::default(),
hierarchy_matrices: Default::default(),
bone_matrices: Default::default(),
dirty: true,
}
}
}
impl HaRigSkeleton {
pub fn bone_transforms(&self) -> impl Iterator<Item = (&str, &HaTransform)> {
self.bone_transforms.iter().map(|(k, v)| (k.as_str(), v))
}
pub fn has_bone_transform(&self, name: &str) -> bool {
self.bone_transforms.contains_key(name)
}
pub fn bone_transform(&self, name: &str) -> Option<&HaTransform> {
self.bone_transforms.get(name)
}
pub fn set_bone_transform(&mut self, name: impl ToString, transform: HaTransform) {
self.bone_transforms.insert(name.to_string(), transform);
self.dirty = true;
}
pub fn unset_bone_transform(&mut self, name: &str) {
self.bone_transforms.remove(name);
self.dirty = true;
}
pub fn with_existing_bone_transforms<F>(&mut self, mut f: F)
where
F: FnMut(&str, &mut HaTransform),
{
for (name, transform) in self.bone_transforms.iter_mut() {
f(name, transform);
}
self.dirty = true;
}
pub fn with_bone_transform<F>(&mut self, name: String, mut f: F)
where
F: FnMut(&mut HaTransform),
{
let transform = self.bone_transforms.entry(name).or_default();
f(transform);
self.dirty = true;
}
pub fn bone_matrices(&self) -> &[Mat4] {
&self.bone_matrices
}
pub fn is_dirty(&self) -> bool {
self.dirty
}
pub fn mark_dirty(&mut self) {
self.dirty = true;
}
pub(crate) fn unmark_dirty(&mut self) {
self.dirty = false;
}
pub(crate) fn recalculate_bone_matrices(&mut self, skeleton: &Skeleton) {
self.hierarchy_matrices.clear();
self.hierarchy_matrices.reserve(skeleton.bones().len());
self.bone_matrices.clear();
self.bone_matrices.reserve(skeleton.bones().len());
for bone in skeleton.bones().iter() {
let local_matrix = self
.bone_transforms
.get(bone.name())
.map(|transform| transform.local_matrix())
.unwrap_or_default();
let parent_matrix = bone
.parent()
.and_then(|index| self.hierarchy_matrices.get(index))
.copied()
.unwrap_or_default();
self.hierarchy_matrices.push(parent_matrix * local_matrix);
}
for (matrix, bone) in self.hierarchy_matrices.iter().zip(skeleton.bones().iter()) {
self.bone_matrices
.push(*matrix * bone.bind_pose_inverse_matrix());
}
}
pub(crate) fn apply_bone_matrices_data(&self, image: &mut Image) -> Result<(), ImageError> {
let mut data = Vec::with_capacity(self.bone_matrices.len() * image.format().bytesize() * 4);
for matrix in &self.bone_matrices {
let values = matrix.as_col_slice();
let bytes = unsafe { values.align_to::<u8>().1 };
data.extend(bytes);
}
image.overwrite(4, self.bone_matrices.len(), 1, data)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum HaDeformerTangent {
North,
East,
South,
West,
}
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum HaDeformerTangents {
Single(Vec2),
Mirrored {
horizontal: Vec2,
vertical: Vec2,
},
Cardinal {
north: Vec2,
east: Vec2,
south: Vec2,
west: Vec2,
},
}
impl HaDeformerTangents {
pub fn to_single(&self) -> Self {
match self {
Self::Mirrored {
horizontal,
vertical,
} => Self::Single((*horizontal + vec2(vertical.y, -vertical.x)) * 0.5),
Self::Cardinal {
north,
east,
south,
west,
} => Self::Single(
(*east - *west + vec2(south.y, -south.x) + vec2(-north.y, north.x)) * 0.25,
),
value => *value,
}
}
pub fn to_mirrored(&self) -> Self {
match self {
Self::Single(tangent) => Self::Mirrored {
horizontal: *tangent,
vertical: vec2(-tangent.y, tangent.x),
},
Self::Cardinal {
north,
east,
south,
west,
} => Self::Mirrored {
horizontal: (*east - *west) * 0.5,
vertical: (*south - *north) * 0.5,
},
value => *value,
}
}
pub fn to_cardinal(&self) -> Self {
match self {
Self::Single(tangent) => Self::Cardinal {
north: vec2(tangent.y, -tangent.x),
east: *tangent,
south: vec2(-tangent.y, tangent.x),
west: -*tangent,
},
Self::Mirrored {
horizontal,
vertical,
} => Self::Cardinal {
north: -*vertical,
east: *horizontal,
south: *vertical,
west: -*horizontal,
},
value => *value,
}
}
pub fn tangent(&self, direction: HaDeformerTangent) -> Vec2 {
match self {
Self::Single(tangent) => match direction {
HaDeformerTangent::North => vec2(tangent.y, -tangent.x),
HaDeformerTangent::East => *tangent,
HaDeformerTangent::South => vec2(-tangent.y, tangent.x),
HaDeformerTangent::West => -*tangent,
},
Self::Mirrored {
horizontal,
vertical,
} => match direction {
HaDeformerTangent::North => -*vertical,
HaDeformerTangent::East => *horizontal,
HaDeformerTangent::South => *vertical,
HaDeformerTangent::West => -*horizontal,
},
Self::Cardinal {
north,
east,
south,
west,
} => match direction {
HaDeformerTangent::North => *north,
HaDeformerTangent::East => *east,
HaDeformerTangent::South => *south,
HaDeformerTangent::West => *west,
},
}
}
}
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub struct HaDeformerControlPoint {
pub position: Vec2,
pub tangents: HaDeformerTangents,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HaDeformerArea {
control_points: Grid2d<HaDeformerControlPoint>,
dirty: bool,
}
impl HaDeformerArea {
pub fn new(area: &DeformerArea) -> Self {
let cols = area.cols.max(1);
let rows = area.rows.max(1);
let tangent_horizontal = vec2(area.rectangle.w / 3.0 / cols as f32, 0.0);
let tangent_vertical = vec2(0.0, area.rectangle.h / 3.0 / rows as f32);
let cells = (0..=rows)
.flat_map(|row| {
let py = area.rectangle.h * row as f32 / rows as f32;
(0..=cols).map(move |col| {
let px = area.rectangle.w * col as f32 / cols as f32;
HaDeformerControlPoint {
position: area.rectangle.position() + vec2(px, py),
tangents: HaDeformerTangents::Mirrored {
horizontal: tangent_horizontal,
vertical: tangent_vertical,
},
}
})
})
.collect();
Self {
control_points: Grid2d::with_cells(cols + 1, cells),
dirty: true,
}
}
pub fn get(&self, col: usize, row: usize) -> Option<HaDeformerControlPoint> {
self.control_points.get(col, row)
}
pub fn set(&mut self, col: usize, row: usize, control_point: HaDeformerControlPoint) {
self.control_points.set(col, row, control_point);
self.dirty = true;
}
pub fn read(&mut self, col: usize, row: usize) -> Option<&HaDeformerControlPoint> {
self.control_points.cell(col, row)
}
pub fn write(&mut self, col: usize, row: usize) -> Option<&mut HaDeformerControlPoint> {
self.control_points.cell_mut(col, row)
}
pub fn cells_count(&self) -> usize {
(self.control_points.cols() - 1) * (self.control_points.rows() - 1)
}
fn apply_data(&self, buffer: &mut [f32]) {
let mut offset = 0;
for row in 0..(self.control_points.rows() - 1) {
for col in 0..(self.control_points.cols() - 1) {
let tl = self.control_points.cell(col, row).unwrap();
let tr = self.control_points.cell(col + 1, row).unwrap();
let br = self.control_points.cell(col + 1, row + 1).unwrap();
let bl = self.control_points.cell(col, row + 1).unwrap();
let tle = tl.tangents.tangent(HaDeformerTangent::East);
let tls = tl.tangents.tangent(HaDeformerTangent::South);
let trw = tr.tangents.tangent(HaDeformerTangent::West);
let trs = tr.tangents.tangent(HaDeformerTangent::South);
let brw = br.tangents.tangent(HaDeformerTangent::West);
let brn = br.tangents.tangent(HaDeformerTangent::North);
let ble = bl.tangents.tangent(HaDeformerTangent::East);
let bln = bl.tangents.tangent(HaDeformerTangent::North);
let values = [
tl.position.x,
tl.position.x + tle.x,
tr.position.x + trw.x,
tr.position.x,
tl.position.y,
tl.position.y + tle.y,
tr.position.y + trw.y,
tr.position.y,
bl.position.x,
bl.position.x + ble.x,
br.position.x + brw.x,
br.position.x,
bl.position.y,
bl.position.y + ble.y,
br.position.y + brw.y,
br.position.y,
tl.position.x,
tl.position.x + tls.x,
bl.position.x + bln.x,
bl.position.x,
tl.position.y,
tl.position.y + tls.y,
bl.position.y + bln.y,
bl.position.y,
tr.position.x,
tr.position.x + trs.x,
br.position.x + brn.x,
br.position.x,
tr.position.y,
tr.position.y + trs.y,
br.position.y + brn.y,
br.position.y,
];
buffer[offset..(offset + 32)].copy_from_slice(&values);
offset += 32;
}
}
}
}
pub struct HaDeformerAreaAccess<'a> {
area: &'a mut HaDeformerArea,
buffer: &'a mut [f32],
}
impl<'a> Deref for HaDeformerAreaAccess<'a> {
type Target = HaDeformerArea;
fn deref(&self) -> &Self::Target {
self.area
}
}
impl<'a> DerefMut for HaDeformerAreaAccess<'a> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.area
}
}
impl<'a> Drop for HaDeformerAreaAccess<'a> {
fn drop(&mut self) {
self.area.dirty = true;
self.area.apply_data(self.buffer);
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HaRigDeformer {
#[serde(default)]
areas: BTreeMap<String, (HaDeformerArea, usize, usize)>,
#[serde(skip)]
buffer: Vec<f32>,
#[serde(skip)]
dirty: bool,
}
impl Default for HaRigDeformer {
fn default() -> Self {
Self {
areas: Default::default(),
buffer: Default::default(),
dirty: true,
}
}
}
impl HaRigDeformer {
pub fn areas(&self) -> impl Iterator<Item = (&str, &HaDeformerArea)> {
self.areas
.iter()
.map(|(name, (area, _, _))| (name.as_str(), area))
}
pub fn has_area(&self, name: &str) -> bool {
self.areas.contains_key(name)
}
pub fn read_area(&self, name: &str) -> Option<&HaDeformerArea> {
self.areas.get(name).map(|(area, _, _)| area)
}
pub fn write_area(&mut self, name: &str) -> Option<HaDeformerAreaAccess> {
self.areas
.get_mut(name)
.map(|(area, offset, count)| HaDeformerAreaAccess {
area,
buffer: &mut self.buffer[*offset..(*offset + *count)],
})
}
pub fn is_dirty(&self) -> bool {
self.dirty || self.areas.values().any(|(area, _, _)| area.dirty)
}
pub fn mark_dirty(&mut self) {
self.dirty = true;
}
pub(crate) fn unmark_dirty(&mut self) {
self.dirty = false;
for (area, _, _) in self.areas.values_mut() {
area.dirty = false;
}
}
pub(crate) fn apply_areas_data(&self, image: &mut Image) -> Result<(), ImageError> {
let count = self
.areas
.values()
.map(|(area, _, _)| area.cells_count())
.sum();
let bytes = unsafe { self.buffer.align_to::<u8>().1 };
image.overwrite(8, count, 1, bytes.to_owned())
}
}
#[derive(Serialize, Deserialize)]
pub struct HaRigControlNode {
#[serde(default)]
transform: HaTransform,
#[serde(default)]
parent_bone: Option<String>,
#[serde(skip)]
lifetime: Lifetime,
}
impl HaRigControlNode {
pub fn with_transform(mut self, transform: HaTransform) -> Self {
self.set_transform(transform);
self
}
pub fn with_parent_bone(mut self, bone: Option<String>) -> Self {
self.set_parent_bone(bone);
self
}
pub fn transform(&self) -> &HaTransform {
&self.transform
}
pub fn set_transform(&mut self, transform: HaTransform) {
self.transform = transform;
}
pub fn borrow_transform(&self) -> Option<DynamicManagedRef> {
self.lifetime
.borrow()
.map(|lifetime| DynamicManagedRef::new(&self.transform, lifetime))
}
pub fn borrow_transform_mut(&mut self) -> Option<DynamicManagedRefMut> {
self.lifetime
.borrow_mut()
.map(|lifetime| DynamicManagedRefMut::new(&mut self.transform, lifetime))
}
pub fn parent_node(&self) -> Option<&str> {
self.parent_bone.as_deref()
}
pub fn set_parent_bone(&mut self, bone: Option<String>) {
self.parent_bone = bone;
}
}
impl Clone for HaRigControlNode {
fn clone(&self) -> Self {
Self {
transform: self.transform.clone(),
parent_bone: self.parent_bone.clone(),
lifetime: Default::default(),
}
}
}
impl std::fmt::Debug for HaRigControlNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HaRigControlNode")
.field("transform", &self.transform)
.field("parent_bone", &self.parent_bone)
.finish_non_exhaustive()
}
}
pub struct HaRigControlSignal {
pub name: String,
pub params: HashMap<String, DynamicManaged>,
}
impl HaRigControlSignal {
pub fn new(name: impl ToString) -> Self {
Self {
name: name.to_string(),
params: Default::default(),
}
}
pub fn param_raw(mut self, name: impl ToString, value: DynamicManaged) -> Self {
self.params.insert(name.to_string(), value);
self
}
pub fn param<T: 'static>(self, name: impl ToString, value: T) -> Self {
self.param_raw(name, DynamicManaged::new(value))
}
pub fn params(mut self, iter: impl IntoIterator<Item = (String, DynamicManaged)>) -> Self {
self.params.extend(iter.into_iter());
self
}
pub fn read<T: 'static>(&self, name: &str) -> Option<ValueReadAccess<T>> {
self.params.get(name)?.read::<T>()
}
}
pub struct HaRigControlProperty<'a> {
control: &'a mut HaRigControl,
name: &'a str,
}
impl<'a> HaRigControlProperty<'a> {
pub fn delete(self) -> Option<DynamicManaged> {
self.control.properties.remove(self.name)
}
pub fn does_exists(self) -> bool {
self.control.properties.contains_key(self.name)
}
pub fn while_occupied(self) -> Option<Self> {
if self.control.properties.contains_key(self.name) {
Some(self)
} else {
None
}
}
pub fn while_vacant(self) -> Option<Self> {
if !self.control.properties.contains_key(self.name) {
Some(self)
} else {
None
}
}
pub fn set<T: 'static>(self, data: T) {
self.control
.properties
.insert(self.name.to_owned(), DynamicManaged::new(data));
}
pub fn set_raw(self, data: DynamicManaged) {
self.control.properties.insert(self.name.to_owned(), data);
}
pub fn and_modify<T: 'static>(self, f: impl FnOnce(&mut T)) -> Self {
self.control
.properties
.entry(self.name.to_owned())
.and_modify(|data| {
if let Some(mut data) = data.write::<T>() {
f(&mut data);
}
});
self
}
pub fn or_default<T: 'static>(self) -> Self
where
T: Default,
{
self.control
.properties
.entry(self.name.to_owned())
.or_insert_with(|| DynamicManaged::new(T::default()));
self
}
pub fn or_insert<T: 'static>(self, data: T) -> Self {
self.control
.properties
.entry(self.name.to_owned())
.or_insert(DynamicManaged::new(data));
self
}
pub fn or_insert_raw(self, data: DynamicManaged) -> Self {
self.control
.properties
.entry(self.name.to_owned())
.or_insert(data);
self
}
pub fn or_insert_with<T: 'static>(self, f: impl FnOnce() -> T) -> Self {
self.control
.properties
.entry(self.name.to_owned())
.or_insert_with(|| DynamicManaged::new(f()));
self
}
pub fn or_insert_with_raw(self, f: impl FnOnce() -> DynamicManaged) -> Self {
self.control
.properties
.entry(self.name.to_owned())
.or_insert_with(f);
self
}
pub fn borrow(self) -> Option<DynamicManagedRef> {
self.control.properties.get(self.name)?.borrow()
}
pub fn borrow_mut(self) -> Option<DynamicManagedRefMut> {
self.control.properties.get_mut(self.name)?.borrow_mut()
}
pub fn read<T: 'static>(self) -> Option<ValueReadAccess<'a, T>> {
self.control.properties.get(self.name)?.read::<T>()
}
pub fn write<T: 'static>(self) -> Option<ValueWriteAccess<'a, T>> {
self.control.properties.get_mut(self.name)?.write::<T>()
}
pub fn consumed<T: 'static>(self) -> Option<T> {
match self.control.properties.remove(self.name)?.consume::<T>() {
Ok(result) => Some(result),
Err(data) => {
self.control.properties.insert(self.name.to_owned(), data);
None
}
}
}
pub fn cloned<T: Clone + 'static>(self) -> Option<T> {
Some(self.control.properties.get(self.name)?.read::<T>()?.clone())
}
pub fn copied<T: Copy + 'static>(self) -> Option<T> {
Some(*self.control.properties.get(self.name)?.read::<T>()?)
}
pub fn managed(self) -> Option<&'a DynamicManaged> {
self.control.properties.get(self.name)
}
pub fn managed_mut(self) -> Option<&'a mut DynamicManaged> {
self.control.properties.get_mut(self.name)
}
}
#[derive(Default, Clone, Serialize, Deserialize)]
pub struct HaRigControlDef {
#[serde(default)]
pub controls: HashMap<String, HaRigControlNode>,
#[serde(default)]
pub properties: HashMap<String, ScriptingValue>,
}
#[derive(Default, Serialize, Deserialize)]
#[serde(try_from = "HaRigControlDef")]
pub struct HaRigControl {
#[serde(default)]
controls: HashMap<String, HaRigControlNode>,
#[serde(skip)]
pub(crate) states: Vec<DynamicManaged>,
#[serde(skip)]
properties: HashMap<String, DynamicManaged>,
#[serde(skip)]
pub(crate) signals: Vec<HaRigControlSignal>,
}
impl HaRigControl {
pub fn control(&self, name: &str) -> Option<&HaRigControlNode> {
self.controls.get(name)
}
pub fn control_mut(&mut self, name: &str) -> Option<&mut HaRigControlNode> {
self.controls.get_mut(name)
}
pub fn set_control(
&mut self,
name: impl ToString,
node: HaRigControlNode,
) -> Option<HaRigControlNode> {
self.controls.insert(name.to_string(), node)
}
pub fn delete_control(&mut self, name: &str) -> Option<HaRigControlNode> {
self.controls.remove(name)
}
pub fn reset(&mut self) {
self.states.clear();
}
pub fn property<'a>(&'a mut self, name: &'a str) -> HaRigControlProperty<'a> {
HaRigControlProperty {
control: self,
name,
}
}
pub fn signal(&mut self, signal: HaRigControlSignal) {
self.signals.push(signal);
}
pub fn signals(&self) -> &[HaRigControlSignal] {
&self.signals
}
}
impl std::fmt::Debug for HaRigControl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HaRigControl")
.field("controls", &self.controls)
.finish_non_exhaustive()
}
}
impl TryFrom<HaRigControlDef> for HaRigControl {
type Error = Box<dyn std::error::Error>;
fn try_from(value: HaRigControlDef) -> Result<Self, Self::Error> {
Ok(Self {
controls: value.controls,
states: Default::default(),
properties: value
.properties
.into_iter()
.map(|(name, value)| Ok((name, value.produce()?)))
.collect::<Result<_, Box<dyn std::error::Error>>>()?,
signals: Default::default(),
})
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct HaRigInstance {
#[serde(default)]
pub skeleton: HaRigSkeleton,
#[serde(default)]
pub deformer: HaRigDeformer,
#[serde(default)]
pub control: HaRigControl,
#[serde(default)]
asset: String,
#[serde(skip)]
ready: bool,
}
impl HaRigInstance {
pub fn asset(&self) -> &str {
&self.asset
}
pub fn set_asset(&mut self, asset: impl ToString) {
self.asset = asset.to_string();
self.skeleton.dirty = true;
self.deformer.dirty = true;
self.ready = false;
}
pub(crate) fn try_initialize(&mut self, rig: &Rig) {
if self.ready {
return;
}
self.ready = true;
self.skeleton.bone_transforms = rig
.skeleton
.bones()
.iter()
.map(|bone| (bone.name().to_owned(), bone.transform().to_owned()))
.collect();
let mut offset = 0;
self.deformer.areas = rig
.deformer
.areas
.iter()
.map(|(name, area)| {
let area = HaDeformerArea::new(area);
let count = area.cells_count() * 32;
let o = offset;
offset += count;
(name.to_owned(), (area, o, count))
})
.collect();
self.deformer.buffer = vec![0.0; offset];
for (area, offset, count) in self.deformer.areas.values_mut() {
area.apply_data(&mut self.deformer.buffer[*offset..(*offset + *count)]);
}
}
}
impl Prefab for HaRigInstance {}
impl PrefabComponent for HaRigInstance {}