use std::convert::{TryFrom, TryInto};
use anyhow::{bail, format_err, Error};
use fbxcel::{low::v7400::AttributeValue, tree::v7400::NodeHandle};
pub(crate) use self::common::LayerContentIndex;
pub use self::{
color::LayerElementColorHandle,
common::{LayerElementHandle, MappingMode, ReferenceInformation, ReferenceMode},
material::LayerElementMaterialHandle,
normal::LayerElementNormalHandle,
uv::LayerElementUvHandle,
};
pub mod color;
mod common;
pub mod material;
pub mod normal;
pub mod uv;
#[derive(Debug, Clone, Copy)]
pub struct LayerHandle<'a> {
node: NodeHandle<'a>,
}
impl<'a> LayerHandle<'a> {
pub(crate) fn new(node: NodeHandle<'a>) -> Self {
Self { node }
}
pub fn get_index(&self) -> Result<LayerIndex, Error> {
let raw = self
.node
.attributes()
.get(0)
.ok_or_else(|| format_err!("Attributes not found for `Layer` element"))?
.get_i32_or_type()
.map_err(|ty| format_err!("Expected `i32` as layer index, but got {:?}", ty))?;
if raw < 0 {
bail!(
"Expected non-negative integer as layer index, but got {:?}",
raw
);
}
Ok(LayerIndex::new(raw as u32))
}
pub fn layer_element_entries(&self) -> impl Iterator<Item = LayerElementEntryHandle<'a>> {
self.children_by_name("LayerElement")
.map(LayerElementEntryHandle::new)
}
}
impl<'a> std::ops::Deref for LayerHandle<'a> {
type Target = NodeHandle<'a>;
fn deref(&self) -> &Self::Target {
&self.node
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LayerIndex(u32);
impl LayerIndex {
fn new(v: u32) -> Self {
Self(v)
}
pub fn to_u32(self) -> u32 {
self.0
}
#[deprecated(since = "0.0.3", note = "Renamed to `to_u32`")]
pub fn get_u32(self) -> u32 {
self.to_u32()
}
}
#[derive(Debug, Clone, Copy)]
pub struct LayerElementEntryHandle<'a> {
node: NodeHandle<'a>,
}
impl<'a> LayerElementEntryHandle<'a> {
fn new(node: NodeHandle<'a>) -> Self {
Self { node }
}
pub fn type_str(&self) -> Result<&'a str, Error> {
self.children_by_name("Type")
.next()
.ok_or_else(|| format_err!("Child node `Type` not found for `LayerElement`"))?
.attributes()
.get(0)
.ok_or_else(|| format_err!("Attributes not found for `Type`"))?
.get_string_or_type()
.map_err(|ty| format_err!("Expected string but got {:?}", ty))
}
pub fn type_(&self) -> Result<LayerElementType, Error> {
self.type_str()?.parse()
}
pub fn typed_index(&self) -> Result<LayerElementIndex, Error> {
let raw = self
.children_by_name("TypedIndex")
.next()
.ok_or_else(|| format_err!("Child node `TypedIndex` not found for `LayerElement`"))?
.attributes()
.get(0)
.ok_or_else(|| format_err!("Attributes not found for `TypedIndex`"))?
.get_i32_or_type()
.map_err(|ty| format_err!("Expected `i32` but got {:?}", ty))?;
if raw < 0 {
bail!(
"Expected non-negative integer as layer element index, but got {:?}",
raw
);
}
Ok(LayerElementIndex::new(raw as u32))
}
pub fn typed_layer_element(&self) -> Result<TypedLayerElementHandle<'a>, Error> {
let geometry_node = self.parent().and_then(|p| p.parent()).ok_or_else(|| {
format_err!(
"Failed to get parent of parent of `LayerElement` node, \
this is not supposed to happen"
)
})?;
let ty = self.type_()?;
let index = self.typed_index()?;
geometry_node
.children_by_name(ty.type_name())
.find(|node| {
node.attributes()
.get(0)
.and_then(AttributeValue::get_i32)
.map_or(false, |v| v == index.to_u32() as i32)
})
.ok_or_else(|| {
format_err!(
"Layer element node not found: type={:?}, index={:?}",
ty,
index
)
})
.map(|node| TypedLayerElementHandle::new(ty, node))
}
}
impl<'a> std::ops::Deref for LayerElementEntryHandle<'a> {
type Target = NodeHandle<'a>;
fn deref(&self) -> &Self::Target {
&self.node
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LayerElementType {
Color,
Material,
Normal,
Uv,
}
impl LayerElementType {
pub fn type_name(self) -> &'static str {
match self {
LayerElementType::Color => "LayerElementColor",
LayerElementType::Material => "LayerElementMaterial",
LayerElementType::Normal => "LayerElementNormal",
LayerElementType::Uv => "LayerElementUV",
}
}
}
impl TryFrom<&str> for LayerElementType {
type Error = Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
"LayerElementColor" => Ok(LayerElementType::Color),
"LayerElementMaterial" => Ok(LayerElementType::Material),
"LayerElementNormal" => Ok(LayerElementType::Normal),
"LayerElementUV" => Ok(LayerElementType::Uv),
_ => Err(format_err!("Unknown layer element type: {:?}", s)),
}
}
}
impl std::str::FromStr for LayerElementType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.try_into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LayerElementIndex(u32);
impl LayerElementIndex {
fn new(v: u32) -> Self {
Self(v)
}
pub fn to_u32(self) -> u32 {
self.0
}
#[deprecated(since = "0.0.3", note = "Renamed to `to_u32`")]
pub fn get_u32(self) -> u32 {
self.to_u32()
}
}
#[derive(Debug, Clone, Copy)]
pub enum TypedLayerElementHandle<'a> {
Color(LayerElementColorHandle<'a>),
Material(LayerElementMaterialHandle<'a>),
Normal(LayerElementNormalHandle<'a>),
Uv(LayerElementUvHandle<'a>),
}
impl<'a> TypedLayerElementHandle<'a> {
fn new(ty: LayerElementType, node: NodeHandle<'a>) -> Self {
let base = LayerElementHandle::new(node);
match ty {
LayerElementType::Color => {
TypedLayerElementHandle::Color(LayerElementColorHandle::new(base))
}
LayerElementType::Material => {
TypedLayerElementHandle::Material(LayerElementMaterialHandle::new(base))
}
LayerElementType::Normal => {
TypedLayerElementHandle::Normal(LayerElementNormalHandle::new(base))
}
LayerElementType::Uv => TypedLayerElementHandle::Uv(LayerElementUvHandle::new(base)),
}
}
}
impl<'a> std::ops::Deref for TypedLayerElementHandle<'a> {
type Target = LayerElementHandle<'a>;
fn deref(&self) -> &Self::Target {
match self {
TypedLayerElementHandle::Color(v) => v,
TypedLayerElementHandle::Normal(v) => v,
TypedLayerElementHandle::Material(v) => v,
TypedLayerElementHandle::Uv(v) => v,
}
}
}