pub mod tokens;
mod binding;
mod connectable;
mod input;
mod interface;
mod node_def;
mod output;
mod preview;
mod schema;
mod traits;
mod utils;
pub use binding::MaterialBindingAPI;
pub use connectable::{
AttributeType, ConnectedSources, ConnectionSource, ConnectionTarget, ShadingAttribute, base_name,
base_name_and_type,
};
pub use input::Input;
pub use interface::{InterfaceInputConsumersMap, NodeGraphInterface};
pub use node_def::SdrMetadata;
pub use output::Output;
pub use preview::{Channel, ReadPreviewSurface, read_preview_surface};
pub use schema::{Material, NodeGraph, ResolvedTerminal, Shader, TerminalKind, TerminalSource};
pub use traits::Connectable;
pub use utils::ProducerFilter;
use openusd::tf;
use tokens::*;
macro_rules! impl_shade_schema {
(connectable $ty:ident) => {
impl $crate::openusd::usd::SchemaBase for $ty {
const KIND: $crate::openusd::usd::SchemaKind = $crate::openusd::usd::SchemaKind::ConcreteTyped;
fn prim(&self) -> &$crate::openusd::usd::Prim {
&self.0
}
}
impl $crate::shade::Connectable for $ty {}
};
(single_api $ty:ident) => {
impl $crate::openusd::usd::SchemaBase for $ty {
const KIND: $crate::openusd::usd::SchemaKind = $crate::openusd::usd::SchemaKind::SingleApplyApi;
fn prim(&self) -> &$crate::openusd::usd::Prim {
&self.0
}
}
};
}
pub(crate) use impl_shade_schema;
macro_rules! impl_shading_attribute {
($ty:ident, $prefix:expr) => {
impl $ty {
pub fn from_attribute(attribute: $crate::openusd::usd::Attribute) -> Option<Self> {
let namespaced = attribute
.path()
.split_property()?
.1
.strip_prefix($prefix)
.is_some();
namespaced.then_some(Self { attribute })
}
pub fn attribute(&self) -> &$crate::openusd::usd::Attribute {
&self.attribute
}
pub fn into_attribute(self) -> $crate::openusd::usd::Attribute {
self.attribute
}
pub fn full_name(&self) -> &str {
self.attribute
.path()
.split_property()
.map_or("", |(_, name)| name)
}
pub fn base_name(&self) -> &str {
self.full_name().strip_prefix($prefix).unwrap_or_default()
}
pub fn set(
self,
value: impl Into<$crate::openusd::sdf::Value>,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: self.attribute.set(value)?,
})
}
pub fn set_at(
self,
value: impl Into<$crate::openusd::sdf::Value>,
time: impl Into<Option<$crate::openusd::usd::TimeCode>>,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: self.attribute.set_at(value, time)?,
})
}
pub fn set_connections(
self,
targets: impl IntoIterator<Item: $crate::openusd::sdf::IntoPath>,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: self.attribute.set_connections(targets)?,
})
}
pub fn connect_to(
self,
source: &impl $crate::shade::ConnectionTarget,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
self.set_connections([source.target_path().clone()])
}
pub fn render_type(&self) -> $crate::openusd::Result<Option<$crate::openusd::tf::Token>> {
self.attribute
.get_metadata($crate::shade::tokens::META_RENDER_TYPE)
}
pub fn set_render_type(
self,
render_type: impl Into<$crate::openusd::tf::Token>,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: self.attribute.set_metadata(
$crate::shade::tokens::META_RENDER_TYPE,
$crate::openusd::sdf::Value::Token(render_type.into()),
)?,
})
}
pub fn sdr_metadata(&self) -> $crate::openusd::Result<$crate::shade::SdrMetadata> {
$crate::shade::node_def::attribute_sdr_metadata(&self.attribute)
}
pub fn sdr_metadata_by_key(&self, key: impl AsRef<str>) -> $crate::openusd::Result<Option<String>> {
$crate::shade::node_def::attribute_sdr_metadata_by_key(&self.attribute, key.as_ref())
}
pub fn has_sdr_metadata(&self) -> $crate::openusd::Result<bool> {
$crate::shade::node_def::attribute_has_sdr_metadata(&self.attribute)
}
pub fn has_sdr_metadata_by_key(&self, key: impl AsRef<str>) -> $crate::openusd::Result<bool> {
$crate::shade::node_def::attribute_has_sdr_metadata_by_key(&self.attribute, key.as_ref())
}
pub fn set_sdr_metadata(
self,
metadata: &$crate::shade::SdrMetadata,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: $crate::shade::node_def::set_attribute_sdr_metadata(self.attribute, metadata)?,
})
}
pub fn set_sdr_metadata_by_key(
self,
key: impl Into<String>,
value: impl Into<String>,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: $crate::shade::node_def::set_attribute_sdr_metadata_by_key(
self.attribute,
key.into(),
value.into(),
)?,
})
}
pub fn clear_sdr_metadata(self) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: self
.attribute
.clear_metadata($crate::shade::tokens::META_SDR_METADATA)?,
})
}
pub fn clear_sdr_metadata_by_key(
self,
key: impl AsRef<str>,
) -> Result<Self, $crate::openusd::usd::StageAuthoringError> {
Ok(Self {
attribute: $crate::shade::node_def::clear_attribute_sdr_metadata_by_key(
self.attribute,
key.as_ref(),
)?,
})
}
pub fn connected_sources(&self) -> $crate::openusd::Result<$crate::shade::ConnectedSources> {
$crate::shade::connectable::connected_sources(&self.attribute)
}
pub fn value_producing_attributes(
&self,
filter: $crate::shade::ProducerFilter,
) -> Result<Vec<$crate::shade::ShadingAttribute>, $crate::SchemaError> {
$crate::shade::utils::value_producing_attributes(
$crate::shade::ShadingAttribute::from(self.clone()),
filter,
)
}
pub(super) fn new(attribute: $crate::openusd::usd::Attribute) -> Self {
Self { attribute }
}
}
};
}
pub(crate) use impl_shading_attribute;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ImplementationSource {
#[default]
Id,
SourceAsset,
SourceCode,
}
impl ImplementationSource {
pub fn as_token(self) -> &'static str {
match self {
ImplementationSource::Id => IMPL_SOURCE_ID,
ImplementationSource::SourceAsset => IMPL_SOURCE_SOURCE_ASSET,
ImplementationSource::SourceCode => IMPL_SOURCE_SOURCE_CODE,
}
}
pub fn from_token(token: impl Into<tf::Token>) -> Option<Self> {
Some(match token.into().as_str() {
IMPL_SOURCE_ID => ImplementationSource::Id,
IMPL_SOURCE_SOURCE_ASSET => ImplementationSource::SourceAsset,
IMPL_SOURCE_SOURCE_CODE => ImplementationSource::SourceCode,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Connectability {
#[default]
Full,
InterfaceOnly,
}
impl Connectability {
pub fn as_token(self) -> &'static str {
match self {
Connectability::Full => CONNECTABILITY_FULL,
Connectability::InterfaceOnly => CONNECTABILITY_INTERFACE_ONLY,
}
}
pub fn from_token(token: impl Into<tf::Token>) -> Option<Self> {
Some(match token.into().as_str() {
CONNECTABILITY_FULL => Connectability::Full,
CONNECTABILITY_INTERFACE_ONLY => Connectability::InterfaceOnly,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum BindingStrength {
#[default]
WeakerThanDescendants,
StrongerThanDescendants,
}
impl BindingStrength {
pub fn as_token(self) -> &'static str {
match self {
BindingStrength::WeakerThanDescendants => STRENGTH_WEAKER_THAN_DESCENDANTS,
BindingStrength::StrongerThanDescendants => STRENGTH_STRONGER_THAN_DESCENDANTS,
}
}
pub fn from_token(token: impl Into<tf::Token>) -> Option<Self> {
Some(match token.into().as_str() {
STRENGTH_WEAKER_THAN_DESCENDANTS => BindingStrength::WeakerThanDescendants,
STRENGTH_STRONGER_THAN_DESCENDANTS => BindingStrength::StrongerThanDescendants,
_ => return None,
})
}
}
crate::common::impl_token_value!(ImplementationSource, Connectability, BindingStrength);