logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use super::*;

use crate::world::BoneWeightFlags;

/// SDF component.
///
/// Lets you specify the SDF of an entity, used currently for skinning. An SDF shape is specified by
/// a "saft" program, which can be compiled from a graph of operations such
/// as `sphere`, `rounded_box`, `op_union`, `op_union_smooth`, `subtract` etc.
/// (Subtract and intersect are not recommended if you want to use skinned
/// mesh rendering for animation).
///

// TODO: Rename to Sdf.
pub struct SdfModel {
    id: Entity,
}

impl std::fmt::Debug for SdfModel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Render")
            .field("entity", &self.id.name())
            .finish_non_exhaustive()
    }
}

/// Represents an SDF program you can attach to an `SdfModel` component or rendered using a `Render` component.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct SdfProgram {
    pub(crate) data: WorldData,
}

impl SdfProgram {
    /// Creates an SDF program.
    pub fn new(opcodes: &[u32], constants: &[f32]) -> Self {
        let desc = ffi::v3::SdfProgramDesc {
            num_opcodes: opcodes.len() as u32,
            opcodes_ptr: opcodes.as_ptr() as u32,
            num_constants: constants.len() as u32,
            constants_ptr: constants.as_ptr() as u32,
        };
        Self {
            data: WorldData::create_struct(ffi::CreateDataType::SdfProgram, &desc),
        }
    }
}

impl ValueConverterTrait<SdfProgram> for ValueConverter {
    fn into_value(v: SdfProgram) -> Value {
        <Self as ValueConverterTrait<WorldData>>::into_value(v.data)
    }
    fn from_value(v: &Value) -> SdfProgram {
        SdfProgram {
            data: <Self as ValueConverterTrait<WorldData>>::from_value(v),
        }
    }
}

impl SdfModel {
    impl_world_accessor!(
        /// The SDF program associated with this component.
        SdfModel,
        Program,
        SdfProgram,
        program,
        ValueAccessorDataReadWrite
    );
}

impl_world_component!(SdfModel);

/// Represents an SDF skin you can set on a `Render` component as a shape.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct SdfSkin {
    pub(crate) data: WorldData,
}

impl SdfSkin {
    /// Creates an SDF skin.
    pub fn new(
        base_sdf_entity: Entity,
        bone_entities: &[Entity],
        rest_from_shape: &[BoneTransform],
        replacement_mesh: Option<WorldMesh>,
        bone_weight_flags: BoneWeightFlags,
        bone_weight_bias: f32,
        bone_weight_falloff: f32,
    ) -> Self {
        let desc = ffi::v3::SdfSkinDesc2 {
            base_sdf_entity: base_sdf_entity.0,
            num_bone_entities: bone_entities.len() as u32,
            bone_entities_ptr: bone_entities.as_ptr() as u32,
            num_rest_from_shape: rest_from_shape.len() as u32,
            rest_from_shape_ptr: rest_from_shape.as_ptr() as u32,
            replacement_mesh: match replacement_mesh {
                Some(mesh) => mesh.as_ffi(),
                None => DataHandle::invalid().as_ffi(),
            },
            bone_weight_flags,
            bone_weight_bias,
            bone_weight_falloff,
            reserved0: 0,
        };
        Self {
            data: WorldData::create_struct(ffi::CreateDataType::SdfSkin2, &desc),
        }
    }

    /// Returns the mesh used as a replacement for this sdf skin
    pub fn replacement_mesh(&self) -> Option<WorldMesh> {
        let info: SdfSkinInfo = self.data.retrieve_data(RetrieveDataType::Info);
        WorldMesh::try_from_ffi(info.replacement_mesh)
    }
}

impl ValueConverterTrait<SdfSkin> for ValueConverter {
    fn into_value(v: SdfSkin) -> Value {
        <Self as ValueConverterTrait<WorldData>>::into_value(v.data)
    }
    fn from_value(v: &Value) -> SdfSkin {
        SdfSkin {
            data: <Self as ValueConverterTrait<WorldData>>::from_value(v),
        }
    }
}