This commit is contained in:
Spencer Killen 2023-12-02 22:11:18 -07:00
parent cc5c3d6dca
commit e0f00392d2
Signed by: sjkillen
GPG Key ID: 3AF3117BA6FBB75B
7 changed files with 394 additions and 23 deletions

203
Cargo.lock generated
View File

@ -2,13 +2,216 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cmake"
version = "0.1.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130"
dependencies = [
"cc",
]
[[package]]
name = "cppmm-build"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28ab7d173fadeec5208c3ef3eb0aef0d3f419f5fa1450f01d2aa81ce8916e2ce"
dependencies = [
"cmake",
"quick-xml",
"regex",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "imath-traits"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4659ab80c4ff995c16bd3973b6bb2e3ae7be0528b5f66cf860625b51855711ad"
dependencies = [
"half",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "openexr"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "062f65fe94f0ee4e7aeb44d6c2b366fa90611ddb632e69c753ba3076731d606e"
dependencies = [
"bitflags",
"cfg-if",
"half",
"imath-traits",
"openexr-sys",
"paste",
"thiserror",
]
[[package]]
name = "openexr-sys"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71b018f0a60798b0dbabeb2214ea3f8b68c3ac5e0aadd3036dd90a7c3f72c003"
dependencies = [
"cppmm-build",
]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pointcache"
version = "0.1.0"
[[package]]
name = "proc-macro2"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tools"
version = "0.1.0"
dependencies = [
"half",
"imath-traits",
"openexr",
"pointcache",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"

View File

@ -8,7 +8,7 @@ use std::{
};
pub trait PointCache {
type Frame;
type Frame: Frame;
fn read(
infile: File,
) -> Result<
@ -22,14 +22,22 @@ pub trait PointCache {
) -> Result<(), Box<dyn Error>>;
}
pub trait Frame {
fn point_idx(&self) -> usize;
fn point(&self) -> Point;
fn with_point(self, point: Point) -> Self;
}
pub struct MDDSeekableFile;
#[derive(Debug)]
#[repr(C)]
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct Point {
pub x: f32,
pub y: f32,
pub z: f32,
}
#[derive(Debug)]
pub struct MDDFrame {
pub frame_idx: usize,
@ -38,8 +46,20 @@ pub struct MDDFrame {
pub point: Point,
}
impl Frame for MDDFrame {
fn point_idx(&self) -> usize {
self.point_idx
}
fn point(&self) -> Point {
self.point
}
fn with_point(self, point: Point) -> Self {
MDDFrame { point, ..self }
}
}
impl MDDSeekableFile {
fn read_header(infile: &mut File) -> Result<(i32, i32), Box<dyn Error>> {
pub 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)?;

View File

@ -5,3 +5,6 @@ edition = "2021"
[dependencies]
pointcache = { path = ".." }
openexr = "0.11.0"
half = "1.8.2"
imath-traits = "0.4.0"

0
tools/output.exr Normal file
View File

View File

@ -1,29 +1,174 @@
use std::fs::File;
// Openexr library is too complex to go off documentation alone and no projects on github using library. Seek out test cases
use pointcache::{MDDSeekableFile, PointCache, MDDFrame, Point};
use imath_traits::Zero;
use openexr::core::channel_list::{CHANNEL_FLOAT, CHANNEL_UINT};
use openexr::core::frame_buffer::{FrameBuffer, Slice};
use openexr::core::header::Header;
use openexr::core::output_file::OutputFile;
use openexr::core::PixelType;
use openexr::rgba::{Rgba, RgbaChannels, RgbaOutputFile};
use openexr::tiled::TiledOutputFile;
use pointcache::{MDDFrame, MDDSeekableFile, Point, PointCache};
use std::default;
use std::{error::Error, fs::File};
// https://github.com/vfx-rs/openexr-rs/blob/25826b4f89bc768b565ba150d6f9c76876ad6bc3/src/core/output_file.rs#L275
// Godot doesn't seem to support Uint images, using f32 instead
fn write_mask_image(
filename: &str,
pixels: &Vec<f32>,
vertex_total: usize,
) -> Result<(), Box<dyn Error>> {
let width = vertex_total;
let height: usize = 1;
let mut header = Header::from_dimensions(width as i32, height as i32);
header.channels_mut().insert("R", &CHANNEL_FLOAT);
let mut frame_buffer = FrameBuffer::new();
frame_buffer.insert(
"R",
&Slice::builder(
PixelType::Float,
&pixels[0] as *const _ as *const u8,
width as i64,
height as i64,
)
.build()?,
)?;
let mut file = OutputFile::new(filename, &header, 1)?;
file.set_frame_buffer(&frame_buffer)?;
unsafe { file.write_pixels(height as i32)? };
Ok(())
}
fn write_point_image(
filename: &str,
pixels: &Vec<Point>,
width: usize,
height: usize,
) -> Result<(), Box<dyn Error>> {
let mut header = Header::from_dimensions(width as i32, height as i32);
header.channels_mut().insert("R", &CHANNEL_FLOAT);
header.channels_mut().insert("G", &CHANNEL_FLOAT);
header.channels_mut().insert("B", &CHANNEL_FLOAT);
let mut frame_buffer = FrameBuffer::new();
[
("R", &pixels[0].x),
("G", &pixels[0].y),
("B", &pixels[0].z),
]
.map(|(name, spot)| {
frame_buffer.insert(
name,
&Slice::builder(
PixelType::Float,
spot as *const _ as *const u8,
width as i64,
height as i64,
)
.x_stride(std::mem::size_of::<Point>())
.build()?,
)
})
.into_iter()
.collect::<Result<(), openexr::Error>>()?;
let mut file = OutputFile::new(filename, &header, 1)?;
file.set_frame_buffer(&frame_buffer)?;
unsafe { file.write_pixels(height as i32)? };
Ok(())
}
#[derive(Debug, Clone, Copy)]
enum PointState {
Unseen,
OneValue(Point),
Varying(usize),
}
use PointState::*;
impl PointState {
fn mask_value(&self) -> f32 {
match *self {
Unseen => panic!(),
OneValue(_) => -1.0,
Varying(idx) => idx as f32,
}
}
}
fn main() {
let file_a = std::env::args().nth(1).expect("Need three files");
let file_b = std::env::args().nth(1).expect("Need three files");
let file_c = std::env::args().nth(1).expect("Need three files");
let mdd_filename = std::env::args()
.nth(1)
.expect("expected first argument to be a file path to an .mdd file");
let path = std::env::args()
.nth(2)
.expect("expected second argument to be an output directory");
let file_a = File::open(file_a).unwrap();
let file_b = File::open(file_b).unwrap();
let file_c = File::create(file_c).unwrap();
let mut mdd_file = File::open(mdd_filename).expect("Mdd filename is not valid");
let mut file_b = MDDSeekableFile::read(file_b).unwrap();
let (total_frames, total_points) = MDDSeekableFile::read_header(&mut mdd_file).unwrap();
MDDSeekableFile::map_to(file_a, file_c, |frame| {
let frame_b = file_b.next().unwrap()?;
Ok(MDDFrame {
point: Point {
x: frame_b.point.x - frame.point.x,
y: frame_b.point.y - frame.point.y,
z: frame_b.point.z - frame.point.z,
},
..frame
})
}).unwrap();
let mut mask_last: Vec<PointState> = vec![Unseen; total_points as usize];
let pc = MDDSeekableFile::read(mdd_file.try_clone().unwrap()).unwrap();
let mut total_varying = 0;
for frame in pc {
let MDDFrame {
point, point_idx, ..
} = frame.unwrap();
match mask_last[point_idx] {
Unseen => mask_last[point_idx] = OneValue(point),
OneValue(old_point) => {
if point != old_point {
mask_last[point_idx] = Varying(total_varying);
total_varying += 1;
}
}
Varying(_) => {}
}
}
let mask: Vec<f32> = mask_last.iter().map(PointState::mask_value).collect();
// write_mask_image(
// "/home/rat/cow/godot/vertex_animation/mask.exr",
// &pixels.collect(),
// width as usize,
// )
// .unwrap();
let mut pixels: Vec<Point> = Vec::with_capacity(total_varying * (total_frames as usize));
let pc = MDDSeekableFile::read(mdd_file.try_clone().unwrap()).unwrap();
pixels.extend(pc.filter_map(|frame| {
let MDDFrame {
point_idx, point, ..
} = frame.unwrap();
match mask_last[point_idx] {
Unseen => panic!(),
OneValue(_) => None,
Varying(_) => Some(point),
}
}));
assert!(pixels.len() == total_varying * (total_frames as usize));
write_point_image(
"/home/rat/cow/godot/vertex_animation/test.exr",
&pixels,
total_varying,
total_frames as usize,
)
.unwrap();
}

BIN
tools/test.mdd Normal file

Binary file not shown.

BIN
tools/write_deep1.exr Normal file

Binary file not shown.