use super::{ffi, DataHandle, Value, ValueConverter, ValueConverterTrait, WorldData};
pub use crate::api::world::World;
use crate::ColorRgba8;
use crate::Mesh;
pub use ffi::{
GltfFlags, MaterialDesc, MeshOrigin, MeshProperties, MeshRawWithMaterialAndName,
MeshRawWithName, MeshSimplifiedFlags, ResourceHandleRepr,
};
#[must_use]
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct WorldMesh {
pub(crate) mesh: WorldData,
}
impl WorldMesh {
fn convert_to_mesh_raw_with_name(
mesh: &Mesh,
) -> Option<(MeshRawWithName, Vec<ffi::MeshStreamLayout>)> {
let mesh_data = mesh.data.as_ref()?;
let crate::MeshData {
name,
indices,
positions,
normals,
colors,
} = mesh_data;
let mut streams: Vec<ffi::MeshStreamLayout> = vec![];
if !indices.is_empty() {
streams.push(ffi::MeshStreamLayout {
semantic: ffi::MeshStreamSemantic::Indices,
component_format: ffi::MeshComponentFormat::UInt32,
component_count: 1,
buffer_ptr: indices.as_ptr() as u32,
buffer_size: (indices.len() * 4) as u32,
});
}
streams.push(ffi::MeshStreamLayout {
semantic: ffi::MeshStreamSemantic::Positions,
component_format: ffi::MeshComponentFormat::Float32,
component_count: 3,
buffer_ptr: positions.as_ptr() as u32,
buffer_size: (positions.len() * 4 * 3) as u32,
});
if let Some(normals) = normals {
streams.push(ffi::MeshStreamLayout {
semantic: ffi::MeshStreamSemantic::Normals,
component_format: ffi::MeshComponentFormat::Float32,
component_count: 3,
buffer_ptr: normals.as_ptr() as u32,
buffer_size: (normals.len() * 4 * 3) as u32,
});
}
if let Some(colors) = colors {
streams.push(ffi::MeshStreamLayout {
semantic: ffi::MeshStreamSemantic::Colors,
component_format: ffi::MeshComponentFormat::UInt8,
component_count: 4,
buffer_ptr: colors.as_ptr() as u32,
buffer_size: (colors.len() * 4) as u32,
});
}
Some((
ffi::MeshRawWithName {
primitive_topology: ffi::MeshPrimitiveTopology::TriangleList,
streams_ptr: streams.as_ptr() as u32,
num_streams: streams.len() as u32,
debug_name_ptr: name.as_ptr() as u32,
debug_name_size: name.len() as u32,
},
streams,
))
}
fn convert_to_mesh_raw_with_material(
mesh: &Mesh,
material: WorldMaterial,
) -> (MeshRawWithMaterialAndName, Vec<ffi::MeshStreamLayout>) {
let (inner, streams) = Self::convert_to_mesh_raw_with_name(mesh).unwrap();
let handle = std::mem::ManuallyDrop::new(material.data).get_data_handle();
(
ffi::MeshRawWithMaterialAndName {
inner,
material: handle.as_ffi(),
_pad: Default::default(),
},
streams,
)
}
pub fn create(mesh: Mesh) -> Self {
let data = Self::convert_to_mesh_raw_with_name(&mesh).expect("Could not create mesh.");
Self {
mesh: WorldData::create_struct(ffi::CreateDataType::MeshRawWithName, &data.0),
}
}
pub fn create_with_material(mesh: Mesh, material: WorldMaterial) -> Self {
let data = Self::convert_to_mesh_raw_with_material(&mesh, material);
Self {
mesh: WorldData::create_struct(
ffi::CreateDataType::MeshRawWithMaterialAndName,
&data.0,
),
}
}
pub fn create_from_gltf(
debug_name: &str,
gltf_data: &[u8],
buffer_data: &[u8],
flags: GltfFlags,
) -> Self {
Self {
mesh: WorldData::create_struct(
ffi::CreateDataType::MeshGltfNamed,
&ffi::MeshGltfNamed {
debug_name_ptr: debug_name.as_ptr() as u32,
debug_name_size: debug_name.len() as u32,
gltf_data_ptr: gltf_data.as_ptr() as u32,
gltf_data_size: gltf_data.len() as u32,
buffer_data_ptr: buffer_data.as_ptr() as u32,
buffer_data_size: buffer_data.len() as u32,
flags,
},
),
}
}
pub fn create_from_gltf_resource(
debug_name: &str,
gltf_resource: ResourceHandleRepr,
buffer_resource: Option<ResourceHandleRepr>,
flags: GltfFlags,
) -> Self {
Self {
mesh: WorldData::create_struct(
ffi::CreateDataType::MeshGltfResource,
&ffi::MeshGltfResource {
debug_name_ptr: debug_name.as_ptr() as u32,
debug_name_size: debug_name.len() as u32,
gltf_resource,
buffer_resource: buffer_resource.unwrap_or(ffi::INVALID_RESOURCE_HANDLE),
flags,
},
),
}
}
pub fn get_properties(&self) -> MeshProperties {
World::get_mesh_properties(self.mesh.get_data_handle())
}
pub fn get_morph_target_names(&self) -> Vec<String> {
World::get_mesh_morph_target_names(self.mesh.get_data_handle())
}
pub fn get_material_descs(&self) -> Vec<MaterialDesc> {
let mesh_handle = self.mesh.get_data_handle();
let count = ffi::get_mesh_material_count(mesh_handle.as_ffi());
(0..count)
.map(|i| ffi::get_mesh_material_desc(mesh_handle.as_ffi(), i))
.collect()
}
pub fn get_material_descs_with_names(&self) -> Vec<(Option<String>, MaterialDesc)> {
let mesh_handle = self.mesh.get_data_handle();
let count = ffi::get_mesh_material_count(mesh_handle.as_ffi());
(0..count)
.map(|i| {
let len = ffi::get_mesh_material_name(mesh_handle.as_ffi(), i, &mut []);
if len > 0 {
let mut buf: Vec<u8> = vec![0u8; len as usize];
ffi::get_mesh_material_name(mesh_handle.as_ffi(), i, &mut buf);
String::from_utf8(buf).ok()
} else {
None
}
})
.zip((0..count).map(|i| ffi::get_mesh_material_desc(mesh_handle.as_ffi(), i)))
.collect()
}
pub fn get_dominant_colors_with_area(&self) -> Vec<(ColorRgba8, f32)> {
let mesh_handle = self.mesh.get_data_handle();
let count = ffi::v4::get_mesh_section_count(mesh_handle.as_ffi());
(0..count)
.map(|i| {
let c = ffi::v4::get_mesh_section_dominant_color(mesh_handle.as_ffi(), i);
(c.color.into(), c.area)
})
.collect()
}
pub fn get_section_material_index(&self, section_idx: usize) -> usize {
let mesh_handle = self.mesh.get_data_handle();
ffi::v4::get_mesh_section_material_index(mesh_handle.as_ffi(), section_idx as u64) as usize
}
pub fn set_debug_name(&self, name: &str) {
self.mesh.set_debug_name(name);
}
pub fn as_ffi(&self) -> ffi::DataHandle {
self.mesh.get_data_handle().as_ffi()
}
pub fn from_ffi(handle: ffi::DataHandle) -> Self {
Self {
mesh: WorldData::from_data_handle(DataHandle::from_ffi(handle)),
}
}
pub fn try_from_ffi(handle: ffi::DataHandle) -> Option<Self> {
let handle = DataHandle::from_ffi(handle);
World::is_valid_data(handle).then(|| Self {
mesh: WorldData::from_data_handle(handle),
})
}
pub fn is_valid(&self) -> bool {
self.mesh.is_valid()
}
pub fn simplify(
&self,
threshold: f32,
target_error: f32,
min_triangle_count: u32,
max_triangle_count: u32,
flags: MeshSimplifiedFlags,
) -> Self {
Self {
mesh: WorldData::create_struct(
ffi::CreateDataType::MeshSimplified,
&ffi::MeshSimplified {
mesh: self.mesh.get_data_handle().as_ffi(),
threshold,
target_error,
min_triangle_count,
max_triangle_count,
flags,
reserved: [0.0f32; 15],
},
),
}
}
pub fn simplify_to_num_triangles(
&self,
target_triangle_count: u32,
max_error: f32,
flags: MeshSimplifiedFlags,
) -> Self {
self.simplify(
1.0,
max_error,
target_triangle_count,
target_triangle_count,
flags,
)
}
pub fn simplify_to_error(&self, target_error: f32, flags: MeshSimplifiedFlags) -> Self {
self.simplify(1.0, target_error, 1, 1, flags)
}
}
impl ValueConverterTrait<WorldMesh> for ValueConverter {
fn into_value(v: WorldMesh) -> Value {
<Self as ValueConverterTrait<WorldData>>::into_value(v.mesh)
}
fn from_value(v: &Value) -> WorldMesh {
WorldMesh {
mesh: <Self as ValueConverterTrait<WorldData>>::from_value(v),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct WorldMaterial {
data: WorldData,
}
#[allow(dead_code)]
impl WorldMaterial {
pub fn new(desc: MaterialDesc) -> Self {
Self {
data: WorldData::create_struct(ffi::CreateDataType::WorldMaterial, &desc),
}
}
}
impl ValueConverterTrait<WorldMaterial> for ValueConverter {
fn into_value(v: WorldMaterial) -> Value {
<Self as ValueConverterTrait<WorldData>>::into_value(v.data)
}
fn from_value(v: &Value) -> WorldMaterial {
WorldMaterial {
data: <Self as ValueConverterTrait<WorldData>>::from_value(v),
}
}
}