proof of concept MDD
This commit is contained in:
		
						commit
						6f1c60fc70
					
				
					 7 changed files with 231 additions and 0 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
/target
 | 
			
		||||
							
								
								
									
										7
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
# This file is automatically @generated by Cargo.
 | 
			
		||||
# It is not intended for manual editing.
 | 
			
		||||
version = 3
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pointcache"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
							
								
								
									
										6
									
								
								Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Cargo.toml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
[package]
 | 
			
		||||
name = "pointcache"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
							
								
								
									
										4
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
# Parser / Encoder for pointcache file formats
 | 
			
		||||
 | 
			
		||||
## References
 | 
			
		||||
- https://github.com/brainexcerpts/MDD_file_exporter
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								output.mdd
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								output.mdd
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										213
									
								
								src/lib.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								src/lib.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,213 @@
 | 
			
		|||
use std::fmt::Display;
 | 
			
		||||
use std::io::Write;
 | 
			
		||||
use std::mem::size_of;
 | 
			
		||||
use std::ops::Range;
 | 
			
		||||
use std::{
 | 
			
		||||
    error::Error,
 | 
			
		||||
    fs::File,
 | 
			
		||||
    io::{BufReader, Read, Seek, SeekFrom},
 | 
			
		||||
    iter::repeat,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub trait PointCache {
 | 
			
		||||
    fn map<F: FnMut(MDDFrame) -> Result<(), Box<dyn Error>>>(
 | 
			
		||||
        infile: File,
 | 
			
		||||
        op: F,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>>;
 | 
			
		||||
    fn map_to<F: FnMut(MDDFrame) -> Result<MDDFrame, Box<dyn Error>>>(
 | 
			
		||||
        infile: File,
 | 
			
		||||
        outfile: File,
 | 
			
		||||
        op: F,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct MDDSeekableFile;
 | 
			
		||||
struct MDDSeekableFileReader {
 | 
			
		||||
    total_frames: i32,
 | 
			
		||||
    total_points: i32,
 | 
			
		||||
    data: Box<dyn Iterator<Item = Result<MDDFrame, Box<dyn Error>>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Point {
 | 
			
		||||
    x: f32,
 | 
			
		||||
    y: f32,
 | 
			
		||||
    z: f32,
 | 
			
		||||
}
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct MDDFrame {
 | 
			
		||||
    frame_idx: usize,
 | 
			
		||||
    point_idx: usize,
 | 
			
		||||
    time: f32,
 | 
			
		||||
    point: Point,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MDDSeekableFile {
 | 
			
		||||
    fn read_header(infile: &mut File) -> Result<(i32, i32), Box<dyn Error>> {
 | 
			
		||||
        infile.seek(SeekFrom::Start(0));
 | 
			
		||||
        let mut buff = [0u8; size_of::<i32>()];
 | 
			
		||||
        infile.read_exact(&mut buff)?;
 | 
			
		||||
        let total_frames = i32::from_be_bytes(buff);
 | 
			
		||||
        infile.read_exact(&mut buff)?;
 | 
			
		||||
        let total_points = i32::from_be_bytes(buff);
 | 
			
		||||
 | 
			
		||||
        return Ok((total_frames, total_points));
 | 
			
		||||
    }
 | 
			
		||||
    fn write_header(
 | 
			
		||||
        outfile: &mut File,
 | 
			
		||||
        total_frames: i32,
 | 
			
		||||
        total_points: i32,
 | 
			
		||||
    ) -> Result<(), Box<dyn Error>> {
 | 
			
		||||
        outfile.seek(SeekFrom::Start(0));
 | 
			
		||||
        outfile.write_all(&total_frames.to_be_bytes())?;
 | 
			
		||||
        outfile.write_all(&total_points.to_be_bytes())?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
    fn read(mut infile: File) -> Result<MDDSeekableFileReader, Box<dyn Error>> {
 | 
			
		||||
        let (total_frames, total_points) = MDDSeekableFile::read_header(&mut infile)?;
 | 
			
		||||
        let time_byte_offset = (total_frames as usize) * size_of::<f32>();
 | 
			
		||||
 | 
			
		||||
        let mut buff = [0u8; size_of::<f32>()];
 | 
			
		||||
        let times = Box::new(
 | 
			
		||||
            repeat(())
 | 
			
		||||
                .map::<Result<_, Box<dyn Error>>, _>(move |()| {
 | 
			
		||||
                    //times.read_exact(&mut buff)?;
 | 
			
		||||
                    //Ok(f32::from_be_bytes(buff))
 | 
			
		||||
                    Ok(0.0)
 | 
			
		||||
                })
 | 
			
		||||
                .take(total_frames.try_into()?),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let header_size: u64 = (size_of::<i32>() * 2).try_into()?;
 | 
			
		||||
        let f32_size: u64 = size_of::<f32>().try_into()?;
 | 
			
		||||
        let mut buff = [0u8; size_of::<f32>()];
 | 
			
		||||
        let data = Box::new(
 | 
			
		||||
            (0..((total_frames * total_points) as u64)).map::<Result<_, Box<dyn Error>>, _>(
 | 
			
		||||
                move |count| {
 | 
			
		||||
                    let frame_idx: usize = (count / (total_points as u64)).try_into()?;
 | 
			
		||||
                    let time_offset: u64 = f32_size * (frame_idx as u64);
 | 
			
		||||
                    let time_size: u64 = f32_size * (total_frames as u64);
 | 
			
		||||
                    let data_offset: u64 = f32_size * count * 3;
 | 
			
		||||
 | 
			
		||||
                    infile.seek(SeekFrom::Start(header_size + time_offset))?;
 | 
			
		||||
                    infile.read_exact(&mut buff)?;
 | 
			
		||||
                    let time = f32::from_be_bytes(buff);
 | 
			
		||||
 | 
			
		||||
                    infile.seek(SeekFrom::Start(header_size + time_size + data_offset))?;
 | 
			
		||||
                    infile.read_exact(&mut buff)?;
 | 
			
		||||
                    let x = f32::from_be_bytes(buff);
 | 
			
		||||
                    infile.read_exact(&mut buff)?;
 | 
			
		||||
                    let y = f32::from_be_bytes(buff);
 | 
			
		||||
                    infile.read_exact(&mut buff)?;
 | 
			
		||||
                    let z = f32::from_be_bytes(buff);
 | 
			
		||||
                    let point = Point { x, y, z };
 | 
			
		||||
 | 
			
		||||
                    let point_idx: usize = (count % (total_points as u64)).try_into()?;
 | 
			
		||||
                    Ok(MDDFrame {
 | 
			
		||||
                        frame_idx,
 | 
			
		||||
                        point_idx,
 | 
			
		||||
                        time,
 | 
			
		||||
                        point,
 | 
			
		||||
                    })
 | 
			
		||||
                },
 | 
			
		||||
            ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        Ok(MDDSeekableFileReader {
 | 
			
		||||
            total_frames,
 | 
			
		||||
            total_points,
 | 
			
		||||
            data,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct ExaustedPointsUnexpectedly;
 | 
			
		||||
impl Display for ExaustedPointsUnexpectedly {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        write!(f, "ExaustedPointsUnexpectedly")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
impl Error for ExaustedPointsUnexpectedly {}
 | 
			
		||||
 | 
			
		||||
impl PointCache for MDDSeekableFile {
 | 
			
		||||
    fn map<F>(infile: File, mut op: F) -> Result<(), Box<dyn Error>>
 | 
			
		||||
    where
 | 
			
		||||
        F: FnMut(MDDFrame) -> Result<(), Box<dyn Error>>,
 | 
			
		||||
    {
 | 
			
		||||
        let MDDSeekableFileReader {
 | 
			
		||||
            total_frames: _,
 | 
			
		||||
            total_points: _,
 | 
			
		||||
            data,
 | 
			
		||||
        } = MDDSeekableFile::read(infile)?;
 | 
			
		||||
 | 
			
		||||
        for frame in data {
 | 
			
		||||
            op(frame?)?;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn map_to<F>(mut infile: File, mut outfile: File, mut op: F) -> Result<(), Box<dyn Error>>
 | 
			
		||||
    where
 | 
			
		||||
        F: FnMut(MDDFrame) -> Result<MDDFrame, Box<dyn Error>>,
 | 
			
		||||
    {
 | 
			
		||||
        let (total_frames, total_points) = MDDSeekableFile::read_header(&mut infile)?;
 | 
			
		||||
        MDDSeekableFile::write_header(&mut outfile, total_frames, total_points)?;
 | 
			
		||||
 | 
			
		||||
        let header_size: u64 = (size_of::<i32>() * 2).try_into()?;
 | 
			
		||||
        let f32_size: u64 = size_of::<f32>().try_into()?;
 | 
			
		||||
        let mut count = 0;
 | 
			
		||||
 | 
			
		||||
        Self::map(infile, |frame| {
 | 
			
		||||
            let frame = op(frame)?;
 | 
			
		||||
            let frame_idx: u64 = count / (total_points as u64);
 | 
			
		||||
            let time_offset: u64 = f32_size * frame_idx;
 | 
			
		||||
            let time_size: u64 = f32_size * (total_frames as u64);
 | 
			
		||||
            let data_offset: u64 = f32_size * count * 3;
 | 
			
		||||
 | 
			
		||||
            outfile.seek(SeekFrom::Start(header_size + time_offset))?;
 | 
			
		||||
            outfile.write_all(&frame.time.to_be_bytes())?;
 | 
			
		||||
 | 
			
		||||
            outfile.seek(SeekFrom::Start(header_size + time_size + data_offset))?;
 | 
			
		||||
            outfile.write_all(&frame.point.x.to_be_bytes())?;
 | 
			
		||||
            outfile.write_all(&frame.point.y.to_be_bytes())?;
 | 
			
		||||
            outfile.write_all(&frame.point.z.to_be_bytes())?;
 | 
			
		||||
 | 
			
		||||
            count += 1;
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn add(left: usize, right: usize) -> usize {
 | 
			
		||||
    left + right
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn it_works() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
        let infile = File::open("test_cube.mdd")?;
 | 
			
		||||
        let outfile = File::create("output.mdd")?;
 | 
			
		||||
        println!("MAPPING test_cube.mdd to output.mdd");
 | 
			
		||||
        MDDSeekableFile::map_to(infile, outfile, |mut frame| {
 | 
			
		||||
            frame.point.x = frame.frame_idx as f32;
 | 
			
		||||
            frame.point.y = (frame.frame_idx * 2) as f32;
 | 
			
		||||
            frame.point.z = 0.0;
 | 
			
		||||
 | 
			
		||||
            println!("{:?}", frame);
 | 
			
		||||
            Ok(frame)
 | 
			
		||||
        })?;
 | 
			
		||||
        println!("\nReading back output.mdd");
 | 
			
		||||
        let infile = File::open("output.mdd")?;
 | 
			
		||||
        MDDSeekableFile::map(infile, |frame| {
 | 
			
		||||
            println!("{:?}", frame);
 | 
			
		||||
            Ok(())
 | 
			
		||||
        })?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								test_cube.mdd
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test_cube.mdd
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
	Add table
		
		Reference in a new issue