Skip to content

Commit

Permalink
Read payloads
Browse files Browse the repository at this point in the history
  • Loading branch information
mxpv committed Jan 18, 2024
1 parent dd12cd2 commit 6ea5378
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 3 deletions.
13 changes: 13 additions & 0 deletions fixtures/payload.usda
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#usda 1.0

def Sphere "MySphere1" (
payload = @./payload.usda@</MySphere>
)
{
}

def Sphere "MySphere2" (
prepend payload = @./cube_payload.usda@</PayloadCube>
)
{
}
Binary file added fixtures/payload.usdc
Binary file not shown.
7 changes: 5 additions & 2 deletions src/sdf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,14 @@ impl LayerOffset {
/// Unloaded payloads represent a boundary that lazy composition and
/// system behaviors will not traverse across, providing a user-visible
/// way to manage the working set of the scene.
#[derive(Debug)]
#[derive(Debug, Default)]
pub struct Payload {
/// The asset path to the external layer.
pub asset_path: String,
/// The root prim path to the referenced prim in the external layer.
pub prim_path: Path,
pub layer_offset: LayerOffset,
/// The layer offset to transform time.
pub layer_offset: Option<LayerOffset>,
}

/// Represents a reference and all its meta data.
Expand Down Expand Up @@ -158,6 +160,7 @@ pub type StringListOp = ListOp<String>;
pub type TokenListOp = ListOp<String>;
pub type PathListOp = ListOp<Path>;
pub type ReferenceListOp = ListOp<Reference>;
pub type PayloadListOp = ListOp<Payload>;

/// Interface to access scene description data similar to `SdfAbstractData` in C++ version of USD.
///
Expand Down
24 changes: 23 additions & 1 deletion src/sdf/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub enum Value {

UnregisteredValue,
UnregisteredValueListOp,
PayloadListOp,
PayloadListOp(PayloadListOp),

TimeCode(f64),
PathExpression,
Expand Down Expand Up @@ -196,3 +196,25 @@ impl TryFrom<Value> for ReferenceListOp {
}
}
}

impl TryFrom<Value> for Payload {
type Error = anyhow::Error;

fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
match value {
Value::Payload(payload) => Ok(payload),
_ => bail!("Unable to unpack payload"),
}
}
}

impl TryFrom<Value> for PayloadListOp {
type Error = anyhow::Error;

fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
match value {
Value::PayloadListOp(list) => Ok(list),
_ => bail!("Unable to unpack payload list op"),
}
}
}
48 changes: 48 additions & 0 deletions src/usdc/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,27 @@ impl<R: io::Read + io::Seek> CrateFile<R> {
})
}

fn read_payload(&mut self) -> Result<sdf::Payload> {
let asset_path = self.read_string()?;
let prim_path = self.read_path()?;

let mut payload = sdf::Payload {
asset_path,
prim_path,
layer_offset: None,
};

// Layer offsets were added to SdfPayload starting in 0.8.0. Files
// before that cannot have them.
// See https://github.com/PixarAnimationStudios/OpenUSD/blob/0b18ad3f840c24eb25e16b795a5b0821cf05126e/pxr/usd/usd/crateFile.cpp#L1214C41-L1214C41
if self.version() >= version(0, 8, 0) {
let layer_offset = self.reader.read_pod::<sdf::LayerOffset>()?;
payload.layer_offset = Some(layer_offset);
}

Ok(payload)
}

fn read_custom_data(&mut self) -> Result<HashMap<String, Value>> {
let mut count = self.reader.read_count()?;
let mut dict = HashMap::default();
Expand Down Expand Up @@ -925,6 +946,7 @@ impl<R: io::Read + io::Seek> CrateFile<R> {
let tokens = self.read_token_vec()?;
sdf::Value::TokenVector(tokens)
}

Type::Specifier => {
let tmp: i32 = self.unpack_value(value)?;
let specifier = sdf::Specifier::from_repr(tmp)
Expand Down Expand Up @@ -962,6 +984,32 @@ impl<R: io::Read + io::Seek> CrateFile<R> {
sdf::Value::LayerOffsetVector(vec)
}

Type::Payload => {
ensure!(!value.is_inlined());
ensure!(!value.is_array());
ensure!(!value.is_compressed());

self.set_position(value.payload())?;

let payload = self.read_payload()?;
sdf::Value::Payload(payload)
}

Type::PayloadListOp => {
let list = self.read_list_op(value, |file: &mut Self| {
let count = file.reader.read_count()?;
let mut vec = Vec::with_capacity(count);
for _ in 0..count {
let payload = file.read_payload()?;
vec.push(payload);
}

Ok(vec)
})?;

sdf::Value::PayloadListOp(list)
}

Type::VariantSelectionMap => {
ensure!(!value.is_inlined());
ensure!(!value.is_array());
Expand Down
38 changes: 38 additions & 0 deletions src/usdc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,44 @@ mod tests {
Ok(())
}

#[test]
fn test_read_payload() -> Result<()> {
let mut data = read_file("fixtures/payload.usdc")?;

let payload = {
let value = data.get(&sdf::path("/MySphere1")?, "payload")?;
sdf::Payload::try_from(value)?
};

assert_eq!(payload.asset_path, "./payload.usda");
assert_eq!(payload.prim_path, sdf::path("/MySphere")?);

assert!(payload.layer_offset.is_some());

let layer_offset = payload.layer_offset.unwrap();
assert_eq!(layer_offset.offset, 0.0);
assert_eq!(layer_offset.scale, 1.0);

let payload_list_op = {
let value = data.get(&sdf::path("/MySphere2")?, "payload")?;
sdf::PayloadListOp::try_from(value)?
};

assert!(!payload_list_op.explicit);

assert!(payload_list_op.explicit_items.is_empty());
assert!(payload_list_op.added_items.is_empty());
assert!(payload_list_op.appended_items.is_empty());
assert!(payload_list_op.deleted_items.is_empty());
assert!(payload_list_op.ordered_items.is_empty());

assert_eq!(payload_list_op.prepended_items.len(), 1);
assert_eq!(payload_list_op.prepended_items[0].asset_path, "./cube_payload.usda");
assert_eq!(payload_list_op.prepended_items[0].prim_path, sdf::path("/PayloadCube")?);

Ok(())
}

#[test]
fn test_read_array_fields() -> Result<()> {
let mut data = read_file("fixtures/fields.usdc")?;
Expand Down

0 comments on commit 6ea5378

Please sign in to comment.