Skip to content

Commit

Permalink
Finished common custom mesh data infrastructure. Segments of type Cus…
Browse files Browse the repository at this point in the history
…tomIndex can now be saved.
  • Loading branch information
FractalFir committed May 20, 2023
1 parent d9a5be3 commit d38894d
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 31 deletions.
94 changes: 73 additions & 21 deletions src/custom_data.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::IndexType;
use crate::tmf::SectionType;
use crate::IndexType;
#[derive(Clone)]
pub struct CustomDataSegment {
name: [u8; u8::MAX as usize],
Expand All @@ -12,6 +12,18 @@ pub enum DataSegmentError {
NameTooLong,
}
impl CustomDataSegment {
fn new_raw(data: CustomData, raw:[u8;u8::MAX as usize],name_len:u8) -> Self{
Self {
name:raw,
name_len,
data,
}
}
pub fn custom_data(&self)->&CustomData{
&self.data
}
pub(crate) fn name_len(&self)->u8{self.name_len}
pub(crate) fn name_bytes(&self)->&[u8]{&self.name}
pub fn new(data: CustomData, name: &str) -> Result<Self, DataSegmentError> {
let bytes = name.as_bytes();
let len = name.len();
Expand All @@ -25,51 +37,88 @@ impl CustomDataSegment {
for index in 0..bytes.len() {
name[index] = bytes[index];
}
Ok(Self {
name,
name_len,
data,
})
Ok(Self::new_raw(data,name,name_len))
}
}
#[derive(Clone)]
pub enum CustomData {
CustomIndex(Box<[IndexType]>),
CustomIndex(Box<[IndexType]>,usize),
}
impl CustomData{
fn section_type(&self)->SectionType{
impl CustomData {
/// Returns the index data if custom segment is an index segment. Returns the index array and max index.
pub fn is_index(&self)->Option<(&[IndexType],usize)>{
match self{
Self::CustomIndex(array,max_index)=>Some((&array,*max_index)),
_=>None,
}
}
fn write<W:std::io::Write>(&self,target:&mut W)->std::io::Result<()>{
match self{
Self::CustomIndex(_)=>SectionType::CustomIndexSegment,
Self::CustomIndex(data,max_index)=>crate::vertices::save_triangles(data,*max_index,target),
}?;
Ok(())
}
fn section_type(&self) -> SectionType {
match self {
Self::CustomIndex(_,_) => SectionType::CustomIndexSegment,
}
}
fn new_index(indices:&[IndexType],max_index:Option<usize>)->Self{
let max_index = match max_index{
Some(max_index)=>max_index,
None=>indices.iter().max().copied().unwrap_or(0) as usize,
};
Self::CustomIndex(indices.into(),max_index)
}
}
impl From<&[IndexType]> for CustomData {
fn from(indices: &[IndexType]) -> Self {
Self::CustomIndex(indices.into())
Self::new_index(indices.into(),None)
}
}
impl CustomDataSegment{
pub(crate) fn write<W:std::io::Write>(&self,target:&mut W)->std::io::Result<()>{
target.write(&(self.data.section_type() as u16).to_le_bytes())?;
todo!();
impl CustomDataSegment {
pub(crate) fn write<W: std::io::Write>(&self, target: &mut W) -> std::io::Result<()> {
let mut out_bytes = Vec::with_capacity(4096);
use std::io::Write;
out_bytes.write_all(&[self.name_len])?;
out_bytes.write_all(&self.name[..(self.name_len as usize)])?;
self.data.write(&mut out_bytes)?;
target.write_all(&(self.data.section_type() as u16).to_le_bytes())?;
target.write_all(&(out_bytes.len() as u64).to_le_bytes())?;
target.write_all(&[crate::tmf::CompressionType::None as u8])?;

target.write_all(&out_bytes)
}
fn read<R:std::io::Read>(src:&mut R)->Self{
todo!();
//return Err(std::io::Error::new(std::io::ErrorKind::Other,format!("Invalid custom se"),)),
pub(crate) fn read<R: std::io::Read>(mut src:R,kind:SectionType) -> std::io::Result<Self> {
let mut name_len = [0];
src.read_exact(&mut name_len)?;
let name_len = name_len[0];
let mut name = [0;u8::MAX as usize];
src.read_exact(&mut name[..(name_len as usize)])?;
match kind{
SectionType::CustomIndexSegment=>{
let result = crate::vertices::read_triangles(&mut src)?;
Ok(Self::new_raw(CustomData::new_index(&result,None),name,name_len))
},
_=>panic!("InternalError: Invalid custom section type, must be custom!"),
}
}
}
#[cfg(test)]
fn init_test_env() {
std::fs::create_dir_all("target/test_res").unwrap();
}
#[test]
#[cfg(all(feature = "obj_import",test))]
#[cfg(all(feature = "obj_import", test))]
fn index_data() {
use crate::{TMFMesh,TMFPrecisionInfo};
use crate::{TMFMesh, TMFPrecisionInfo};
init_test_env();
let mut file = std::fs::File::open("testing/susan.obj").unwrap();
let (mut tmf_mesh, name) = TMFMesh::read_from_obj_one(&mut file).unwrap();
let index_data:[IndexType;10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let index_data_seg = CustomDataSegment::new(CustomData::from(&index_data[..]), "custom_index").unwrap();
let index_data: [IndexType; 10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let index_data_seg =
CustomDataSegment::new(CustomData::from(&index_data[..]), "custom_index").unwrap();
tmf_mesh.add_custom_data(index_data_seg);
tmf_mesh.verify().unwrap();
assert!(name == "Suzanne", "Name should be Suzanne but is {name}");
Expand All @@ -81,4 +130,7 @@ fn index_data() {
let (r_mesh, name) = TMFMesh::read_tmf_one(&mut (&out as &[u8])).unwrap();
assert!(name == "Suzanne", "Name should be Suzanne but is {name}");
r_mesh.verify().unwrap();
let read_indices = tmf_mesh.lookup_custom_data("custom_index").expect("Could not find the custom index array!");
let (read_indices,_) = read_indices.is_index().unwrap();
assert_eq!(index_data,read_indices);
}
17 changes: 15 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//! This means that while saving a model may take a slightly longer time (2-4x loading), models can be loaded at considerable speed(loading a model with around 40 000 points takes 1.6 ms)
//! ## Feature flags
#![doc = document_features::document_features!()]
mod custom_data;
pub mod custom_data;
mod material;
#[cfg(feature = "model_importer")]
mod model_importer;
Expand Down Expand Up @@ -131,7 +131,7 @@ impl TMFMesh {
if self.materials.is_some() {
count += 1
};
count
count + self.custom_data.len()
}
/// Sets mesh vertex array and returns old vertex array if present. New mesh data is **not** checked during this function call, so to ensure mesh is valid call [`Self::verify`] before saving.
///```
Expand Down Expand Up @@ -635,6 +635,19 @@ impl TMFMesh {
pub fn add_custom_data(&mut self, custom_data: CustomDataSegment) {
self.custom_data.push(custom_data);
}
pub fn lookup_custom_data(&self,name:&str)->Option<&CustomData>{
let bytes = name.as_bytes();
if bytes.len() > u8::MAX as usize{
return None;
}
let bytes_len = bytes.len() as u8;
for data in &self.custom_data{
if data.name_len() == bytes_len && bytes == &data.name_bytes()[..(data.name_len() as usize)]{
return Some(data.custom_data());
}
}
None
}
}
#[cfg(test)]
mod testing {
Expand Down
14 changes: 11 additions & 3 deletions src/tmf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub(crate) enum SectionType {
CustomUnit3Segment = 18,
CustomVector2Segment = 19,
CustomVector3Segment = 20,
CustomVector4Segment = 21,
CustomColorSegment = 23,
}
impl SectionType {
pub fn from_u16(input: u16) -> Self {
Expand All @@ -32,13 +34,14 @@ impl SectionType {
4 => Self::NormalTriangleSegment,
5 => Self::UvSegment,
6 => Self::UvTriangleSegment,
15 => Self::CustomIndexSegment,
_ => Self::Invalid,
}
}
}
#[repr(u8)]
#[derive(PartialEq)]
enum CompressionType {
pub(crate) enum CompressionType {
None = 0,
Ommited = 1,
UnalignedLZZ = 2,
Expand Down Expand Up @@ -350,7 +353,7 @@ pub(crate) fn write_mesh<W: Write>(
}
None => (),
};
for data in &mesh.custom_data{
for data in &mesh.custom_data {
data.write(&mut curr_segment_data)?;
w.write_all(&curr_segment_data)?;
curr_segment_data.clear();
Expand Down Expand Up @@ -497,7 +500,12 @@ pub fn read_mesh<R: Read>(reader: &mut R) -> Result<(TMFMesh, String)> {
));
}
}
_ => (), //Unknown header, ignoring
SectionType::CustomIndexSegment =>{
println!("data:{data:?}");
let cd = crate::custom_data::CustomDataSegment::read(&*data,seg_type)?;
res.add_custom_data(cd);
}
_ =>(), //Unknown header, ignoring
}
}
//todo!();
Expand Down
10 changes: 5 additions & 5 deletions src/vertices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,10 @@ pub fn read_tmf_vertices<R: Read>(reader: &mut R) -> Result<Box<[Vector3]>> {
}
pub fn save_triangles<W: Write>(
triangles: &[IndexType],
count: usize,
max_index: usize,
writer: &mut W,
) -> Result<()> {
let precision = (count as FloatType).log2().ceil() as u8;
let precision = (max_index as FloatType).log2().ceil() as u8;
writer.write_all(&precision.to_le_bytes())?;
writer.write_all(&(triangles.len() as u64).to_le_bytes())?;
let precision = UnalignedRWMode::precision_bits(precision);
Expand All @@ -183,15 +183,15 @@ pub fn read_triangles<R: Read>(reader: &mut R) -> Result<Box<[IndexType]>> {
reader.read_exact(&mut tmp)?;
tmp[0]
};
let count = {
let max_index = {
let mut tmp = [0; std::mem::size_of::<u64>()];
reader.read_exact(&mut tmp)?;
u64::from_le_bytes(tmp)
};
let precision = UnalignedRWMode::precision_bits(precision);
let mut reader = UnalignedReader::new(reader);
let mut res = Vec::with_capacity(count as usize);
for _ in 0..count {
let mut res = Vec::with_capacity(max_index as usize);
for _ in 0..max_index {
res.push(reader.read_unaligned(precision)? as IndexType);
}
Ok(res.into())
Expand Down

0 comments on commit d38894d

Please sign in to comment.