Skip to content

Commit

Permalink
Initial OpenCTM MG2 compression support (#821)
Browse files Browse the repository at this point in the history
Implemented the features we actually use for MG2 encoded OpenCTM files. It doesn't work flawlessly with the way we reference ctm files from i3d files (at the moment). The colors are stored in the i3d file and dependent on the vertex ordering in the ctm file, which isn't preserved with MG2 compression.

MG1 compressed ctm files with colors from i3d file:
![Screenshot 2020-07-16 at 13 30 27](https://user-images.githubusercontent.com/7214852/87666232-87608f80-c768-11ea-867d-df5ac37c9d73.png)

MG2 compressed:
![Screenshot 2020-07-16 at 13 30 07](https://user-images.githubusercontent.com/7214852/87666202-79ab0a00-c768-11ea-82ac-861511bee6b5.png)

Even though it doesn't work that great with i3d, the parsing logic checks out. Making it work with colors is a large undertaking involving changing the i3d format, new finalize logic, and optimizer changes.
  • Loading branch information
aslettemark authored Jul 16, 2020
1 parent eb330c2 commit 77c3ffc
Show file tree
Hide file tree
Showing 4 changed files with 338 additions and 128 deletions.
3 changes: 3 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.rs]
indent_size = 4
54 changes: 46 additions & 8 deletions openctm/src/bin/dump.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use serde_derive::{Deserialize, Serialize};
use std::error::Error;
use std::fs::File;
use std::io::stdout;
use std::io::{stdout, Cursor, Read, Seek, SeekFrom};
use std::{fs, time};
use structopt::StructOpt;

#[derive(StructOpt)]
Expand All @@ -13,6 +14,8 @@ struct Options {
compact: bool,
#[structopt(short, long)]
stats: bool,
#[structopt(short, long)]
benchmark: bool,
}

#[derive(Deserialize, Serialize)]
Expand All @@ -31,24 +34,40 @@ enum Output {
normals: Option<usize>,
uv_maps: Vec<UvMapStats>,
},
Benchmark {
runs: usize,
avg_time_micros: u64,
best_time: u64,
},
}

fn get_file_as_byte_vec(filename: &str) -> Result<Vec<u8>, Box<dyn Error>> {
let mut f = File::open(&filename)?;
let metadata = fs::metadata(&filename)?;
let mut buffer = vec![0; metadata.len() as usize];
f.read_exact(&mut buffer)?;

Ok(buffer)
}

fn main() -> Result<(), Box<dyn Error>> {
let options = Options::from_args();

let reader = Box::new(File::open(options.file)?);
let file_bytes = get_file_as_byte_vec(&options.file)?;
let cursor = Cursor::new(file_bytes);
let mut buf_reader = std::io::BufReader::new(cursor);

let file = openctm::parse(std::io::BufReader::new(reader))?;
let parsed_file = openctm::parse(&mut buf_reader)?;

let output = if options.stats {
Output::FileStats {
indices: file.indices.len(),
vertices: file.vertices.len(),
normals: match file.normals {
indices: parsed_file.indices.len(),
vertices: parsed_file.vertices.len(),
normals: match parsed_file.normals {
Some(x) => Some(x.len()),
None => None,
},
uv_maps: file
uv_maps: parsed_file
.uv_maps
.into_iter()
.map(|x| UvMapStats {
Expand All @@ -58,8 +77,27 @@ fn main() -> Result<(), Box<dyn Error>> {
})
.collect(),
}
} else if options.benchmark {
let runs = 1000;
let mut times = vec![0; runs];
for time in times.iter_mut().take(runs) {
buf_reader.seek(SeekFrom::Start(0))?;
let t1 = time::Instant::now();
openctm::parse(&mut buf_reader)?;
let t2 = time::Instant::now();
*time = t2.duration_since(t1).as_micros() as u64;
}
let total_time: u64 = times.iter().sum();
let avg_time = total_time / runs as u64;
let best_time = *times.iter().min().unwrap();

Output::Benchmark {
runs,
avg_time_micros: avg_time,
best_time,
}
} else {
Output::File(file)
Output::File(parsed_file)
};

if options.compact {
Expand Down
Loading

0 comments on commit 77c3ffc

Please sign in to comment.