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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
use super::*;
use std::collections::HashMap;
use std::mem::ManuallyDrop;

/// `MeshStyle` component.
///
/// Usually accessed through `Entity::mesh_style`().

pub struct MeshStyle {
    id: Entity,
}

/// Represents morph target weights attached to the `MeshStyle`.
pub struct MorphTargetData {
    data: WorldData,
}

impl MorphTargetData {
    /// Creates `MorphTargetData` from a `HashMap`.
    pub fn new(weights_map: HashMap<String, f32>) -> Self {
        let names: Vec<(u32, u32)> = weights_map
            .keys()
            .map(|name| (name.as_ptr() as u32, name.len() as u32))
            .collect();
        let weights: Vec<f32> = weights_map.values().cloned().collect();

        let desc = ffi::v3::MorphTargetDesc {
            num_weights: weights.len() as u32,
            weights_ptr: weights.as_ptr() as u32,
            names_ptr: names.as_ptr() as u32,
        };
        Self {
            data: WorldData::create_struct(ffi::CreateDataType::MorphTargetData, &desc),
        }
    }

    /// Sets a debug name of this data object. Useful for debugging memory usage and leaks.
    pub fn set_debug_name(&self, name: &str) {
        self.data.set_debug_name(name);
    }
}

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

/// Represents a vector of `WorldMaterial`'s attached to the `MeshStyle`.
pub struct WorldMaterials {
    data: WorldData,
}

impl WorldMaterials {
    /// Creates `WorldMaterials` from a `Vec`.
    pub fn new(materials: Vec<WorldMaterial>) -> Self {
        // Would be nice to prevent the extra clone here if possible.
        let materials: Vec<ManuallyDrop<WorldMaterial>> =
            materials.into_iter().map(ManuallyDrop::new).collect();

        let desc = ffi::v3::WorldMaterialsDesc {
            materials_len: materials.len() as u32,
            materials_ptr: materials.as_ptr() as u32,
        };
        Self {
            data: WorldData::create_struct(ffi::CreateDataType::WorldMaterials, &desc),
        }
    }

    /// Sets a debug name of this data object. Useful for debugging memory usage and leaks.
    pub fn set_debug_name(&self, name: &str) {
        self.data.set_debug_name(name);
    }
}

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

impl std::fmt::Debug for MeshStyle {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MeshStyle")
            .field("entity", &self.id.name())
            .field("flags", &self.flags().get())
            .field("diffuse_tint", &self.diffuse_tint().get())
            .finish()
    }
}

impl MeshStyle {
    /// Creates a `MeshStyle` entity.
    ///
    /// * `name` - Just a name, to keep track of the entity during development.
    pub fn create(name: &str) -> Self {
        let id = World::create_entity(name, ffi::EntityTemplate::MeshStyle);
        Self { id }
    }

    /// Sets the mesh style parameters to match this mesh style.
    pub fn set_mesh_style(&self, mesh_style: &MeshStyleData) {
        self.diffuse_tint().set(mesh_style.diffuse_tint);
        self.flags().set(mesh_style.flags);
    }

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the `world::MeshStyleFlags` of the entity.
        ///
        /// Used to set/get the flags.
        MeshStyle,
        Flags,
        MeshStyleFlags,
        flags,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the diffuse tint of the entity.
        ///
        /// Used to set/get/animate the diffuse tint.
        MeshStyle,
        DiffuseTint,
        Vec4,
        diffuse_tint,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the morph target weights of the entity.
        ///
        /// Used to set/get/animate weights.
        /// There's a limit to the number of morph targets weights that can be non-zero at once
        /// and still affect the mesh. Currently that limit is 4, but it will soon be changed higher.
        MeshStyle,
        MorphTargetWeights,
        MorphTargetData,
        morph_target_weights,
        ValueAccessorDataReadWrite
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the material overrides of the entity.
        ///
        /// Used to set/get per-instance materials that override the materials of a mesh.
        MeshStyle,
        MaterialOverrides,
        WorldMaterials,
        materials,
        ValueAccessorDataReadWrite
    );

    impl_world_accessor!(
        /// Sets a view-space offset vector for billboarded meshes (if flags contains BILLBOARD).
        ///
        /// Lets you compose multiple billboards together at the same worldspace location in "2D".
        /// Useful for things like speech bubbles.
        MeshStyle,
        BillboardOffset,
        Vec3,
        billboard_offset,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Sets the thickness of the outline displayed if flags contains OUTLINE.
        ///
        /// The thickness is specified in in screen space in sort of virtual pixels, of which there are
        /// 1024 across the screen. This is so results don't feel drastically different between an 1024x768
        /// and a 4k screen. A 2px border is generally pretty appropriate as a thin border, and a 5px is a
        /// nice thick one.
        MeshStyle,
        OutlineThickness,
        f32,
        outline_thickness,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Sets the color of the outline displayed if flags contains OUTLINE.
        MeshStyle,
        OutlineColor,
        Vec4,
        outline_color,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the `world::MeshVisibilityFlags` of the entity.
        ///
        /// Used to set/get the flags.
        MeshStyle,
        MeshVisibility,
        MeshVisibilityFlags,
        visibility_flags,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Sets the visibility flags used for the player id set which overwrites [`Self::visibility_flags`].
        ///
        /// Used to set/get the visibility flag.
        MeshStyle,
        MeshVisibilityPlayerIdSetFlags,
        MeshVisibilityFlags,
        visibility_player_id_set_flags,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the set of player ids the `visibility_player_id_set_flags` value should affect.
        ///
        /// Used to set/get the player id set.
        MeshStyle,
        MeshVisibilityPlayerIdSet,
        PlayerIdSet,
        visibility_player_id_set,
        ValueAccessorDataReadWrite
    );

    impl_world_accessor!(
        /// Sets the mesh style flags used for the player id set which overwrites `flags`.
        ///
        /// Used to set/get the mesh style flag.
        MeshStyle,
        MeshStylePlayerIdSetFlags,
        MeshStyleFlags,
        mesh_style_player_id_set_flags,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// The players which we will use [`Self::mesh_style_player_id_set_flags`] for instead of `[Self::flags`].
        ///
        /// Default: the empty set (use `[Self::flags`] for everyone).
        ///
        /// Used to set/get the player id set.
        MeshStyle,
        MeshStylePlayerIdSet,
        PlayerIdSet,
        mesh_style_player_id_set,
        ValueAccessorDataReadWrite
    );
}

impl_world_component!(MeshStyle);