mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-05 22:49:41 +08:00
Co-authored-by: Andrew le Bihan <andy@mcneel.com> Co-authored-by: croudyj <croudyj@gmail.com> Co-authored-by: Dale Fugier <dale@mcneel.com> Co-authored-by: Dan Rigdon-Bel <dan@mcneel.com> Co-authored-by: Greg Arden <greg@mcneel.com> Co-authored-by: Jussi Aaltonen <jussi@mcneel.com> Co-authored-by: kike-garbo <kike@mcneel.com> Co-authored-by: piac <giulio@mcneel.com> Co-authored-by: Steve Baer <steve@mcneel.com> Co-authored-by: Will Pearson <will@mcneel.com>
508 lines
16 KiB
C++
508 lines
16 KiB
C++
//
|
|
// Copyright (c) 1993-2022 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include "opennurbs.h"
|
|
#include "opennurbs_internal_defines.h"
|
|
|
|
#if !defined(ON_COMPILING_OPENNURBS)
|
|
// This check is included in all opennurbs source .c and .cpp files to insure
|
|
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
|
|
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
|
|
// and the opennurbs .h files alter what is declared and how it is declared.
|
|
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
|
|
#endif
|
|
|
|
#define ON_RDK_UD_DECALS L"decals"
|
|
#define ON_RDK_UD_DECAL L"decal"
|
|
#define ON_RDK_UD_DECAL_CUSTOM L"custom"
|
|
#define ON_RDK_UD_DECAL_CUSTOM_RENDERER L"renderer"
|
|
#define ON_RDK_UD_DECAL_CUSTOM_PARAMS L"parameters"
|
|
#define ON_RDK_UD_DECAL_INSTANCE_ID L"instance-id"
|
|
|
|
#define ON_RDK_UD_DECAL_MAPPING L"mapping"
|
|
//----- +++++++++++++++++++
|
|
#define ON_RDK_UD_DECAL_MAPPING_PLANAR L"planar"
|
|
#define ON_RDK_UD_DECAL_MAPPING_CYLINDRICAL L"cylindrical"
|
|
#define ON_RDK_UD_DECAL_MAPPING_SPHERICAL L"spherical"
|
|
#define ON_RDK_UD_DECAL_MAPPING_UV L"uv"
|
|
#define ON_RDK_UD_DECAL_MAPPING_NONE L"none"
|
|
|
|
#define ON_RDK_UD_DECAL_PROJECTION L"projection"
|
|
//----- ++++++++++++++++++++++
|
|
#define ON_RDK_UD_DECAL_PROJECTION_FORWARD L"forward"
|
|
#define ON_RDK_UD_DECAL_PROJECTION_BACKWARD L"backward"
|
|
#define ON_RDK_UD_DECAL_PROJECTION_BOTH L"both"
|
|
#define ON_RDK_UD_DECAL_PROJECTION_NONE L"none"
|
|
|
|
#define ON_RDK_UD_DECAL_MAP_TO_INSIDE_ON L"map-to-inside-on"
|
|
#define ON_RDK_UD_DECAL_TRANSPARENCY L"transparency"
|
|
#define ON_RDK_UD_DECAL_TEXTURE_INSTANCE L"texture-instance"
|
|
#define ON_RDK_UD_DECAL_HEIGHT L"height"
|
|
#define ON_RDK_UD_DECAL_ORIGIN L"origin"
|
|
#define ON_RDK_UD_DECAL_RADIUS L"radius"
|
|
#define ON_RDK_UD_DECAL_HORZ_SWEEP_STA L"latitude-start"
|
|
#define ON_RDK_UD_DECAL_HORZ_SWEEP_END L"latitude-stop"
|
|
#define ON_RDK_UD_DECAL_VERT_SWEEP_STA L"longitude-start"
|
|
#define ON_RDK_UD_DECAL_VERT_SWEEP_END L"longitude-stop"
|
|
#define ON_RDK_UD_DECAL_VECTOR_UP L"vector-up"
|
|
#define ON_RDK_UD_DECAL_VECTOR_ACROSS L"vector-across"
|
|
#define ON_RDK_UD_DECAL_MIN_U L"min-u"
|
|
#define ON_RDK_UD_DECAL_MIN_V L"min-v"
|
|
#define ON_RDK_UD_DECAL_MAX_U L"max-u"
|
|
#define ON_RDK_UD_DECAL_MAX_V L"max-v"
|
|
#define ON_RDK_UD_DECAL_IS_TEMPORARY L"is-temporary"
|
|
#define ON_RDK_UD_DECAL_IS_VISIBLE L"is-visible"
|
|
|
|
// ON_Decal
|
|
|
|
class ON_Decal::CImpl : public ON_InternalXMLImpl
|
|
{
|
|
public:
|
|
CImpl() { ON_CreateUuid(m_decal_id); }
|
|
CImpl(ON_XMLNode& n) { ON_CreateUuid(m_decal_id); Node() = n; }
|
|
|
|
ON_UUID m_decal_id;
|
|
};
|
|
|
|
static const wchar_t* XMLPath(void)
|
|
{
|
|
return L""; // The node is the actual decal node.
|
|
}
|
|
|
|
ON_Decal::ON_Decal()
|
|
{
|
|
m_impl = new CImpl;
|
|
}
|
|
|
|
ON_Decal::ON_Decal(ON_XMLNode& model_node)
|
|
{
|
|
m_impl = new CImpl(model_node);
|
|
}
|
|
|
|
ON_Decal::ON_Decal(const ON_Decal& d)
|
|
{
|
|
m_impl = new CImpl;
|
|
operator = (d);
|
|
}
|
|
|
|
ON_Decal::~ON_Decal()
|
|
{
|
|
delete m_impl;
|
|
m_impl = nullptr;
|
|
}
|
|
|
|
const ON_Decal& ON_Decal::operator = (const ON_Decal& d)
|
|
{
|
|
if (this != &d)
|
|
{
|
|
SetTextureInstanceId(d.TextureInstanceId());
|
|
SetMapping(d.Mapping());
|
|
SetProjection(d.Projection());
|
|
SetMapToInside(d.MapToInside());
|
|
SetTransparency(d.Transparency());
|
|
SetOrigin(d.Origin());
|
|
SetVectorUp(d.VectorUp());
|
|
SetVectorAcross(d.VectorAcross());
|
|
SetHeight(d.Height());
|
|
SetRadius(d.Radius());
|
|
|
|
double sta = 0.0, end = 0.0;
|
|
d.GetHorzSweep(sta, end);
|
|
SetHorzSweep(sta, end);
|
|
d.GetVertSweep(sta, end);
|
|
SetVertSweep(sta, end);
|
|
|
|
double min_u = 0.0, min_v = 0.0, max_u = 0.0, max_v = 0.0;
|
|
d.UVBounds(min_u, min_v, max_u, max_v);
|
|
SetUVBounds(min_u, min_v, max_u, max_v);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool ON_Decal::operator == (const ON_Decal& d)
|
|
{
|
|
if (TextureInstanceId() != d.TextureInstanceId()) return false;
|
|
if (Mapping() != d.Mapping()) return false;
|
|
if (Projection() != d.Projection()) return false;
|
|
if (MapToInside() != d.MapToInside()) return false;
|
|
if (Transparency() != d.Transparency()) return false;
|
|
if (Origin() != d.Origin()) return false;
|
|
if (VectorUp() != d.VectorUp()) return false;
|
|
if (VectorAcross() != d.VectorAcross()) return false;
|
|
if (Height() != d.Height()) return false;
|
|
if (Radius() != d.Radius()) return false;
|
|
|
|
double sta1 = 0.0, end1 = 0.0, sta2 = 0.0, end2 = 0.0;
|
|
GetHorzSweep(sta1, end1);
|
|
d.GetHorzSweep(sta2, end2);
|
|
if (!IsDoubleEqual(sta1, sta2)) return false;
|
|
if (!IsDoubleEqual(end1, end2)) return false;
|
|
|
|
GetVertSweep(sta1, end1);
|
|
d.GetVertSweep(sta2, end2);
|
|
if (!IsDoubleEqual(sta1, sta2)) return false;
|
|
if (!IsDoubleEqual(end1, end2)) return false;
|
|
|
|
double min_u1 = 0.0, min_v1 = 0.0, max_u1 = 0.0, max_v1 = 0.0;
|
|
double min_u2 = 0.0, min_v2 = 0.0, max_u2 = 0.0, max_v2 = 0.0;
|
|
UVBounds(min_u1, min_v1, max_u1, max_v1);
|
|
d.UVBounds(min_u2, min_v2, max_u2, max_v2);
|
|
if (!IsDoubleEqual(min_u1, min_u2)) return false;
|
|
if (!IsDoubleEqual(min_v1, min_v2)) return false;
|
|
if (!IsDoubleEqual(max_u1, max_u2)) return false;
|
|
if (!IsDoubleEqual(max_v1, max_v2)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ON_Decal::operator != (const ON_Decal& d)
|
|
{
|
|
return !(operator == (d));
|
|
}
|
|
|
|
ON_UUID ON_Decal::TextureInstanceId(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_TEXTURE_INSTANCE, ON_nil_uuid).AsUuid();
|
|
}
|
|
|
|
void ON_Decal::SetTextureInstanceId(const ON_UUID& id)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_TEXTURE_INSTANCE, id);
|
|
}
|
|
|
|
ON_Decal::Mappings ON_Decal::Mapping(void) const
|
|
{
|
|
const ON_wString s = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_MAPPING, ON_RDK_UD_DECAL_MAPPING_UV).AsString();
|
|
|
|
if (ON_RDK_UD_DECAL_MAPPING_UV == s)
|
|
return ON_Decal::Mappings::UV;
|
|
|
|
if (ON_RDK_UD_DECAL_MAPPING_PLANAR == s)
|
|
return ON_Decal::Mappings::Planar;
|
|
|
|
if (ON_RDK_UD_DECAL_MAPPING_SPHERICAL == s)
|
|
return ON_Decal::Mappings::Spherical;
|
|
|
|
if (ON_RDK_UD_DECAL_MAPPING_CYLINDRICAL == s)
|
|
return ON_Decal::Mappings::Cylindrical;
|
|
|
|
return ON_Decal::Mappings::None;
|
|
}
|
|
|
|
void ON_Decal::SetMapping(Mappings m)
|
|
{
|
|
const wchar_t* s = L"";
|
|
switch (m)
|
|
{
|
|
case ON_Decal::Mappings::UV: s = ON_RDK_UD_DECAL_MAPPING_UV; break;
|
|
case ON_Decal::Mappings::Planar: s = ON_RDK_UD_DECAL_MAPPING_PLANAR; break;
|
|
case ON_Decal::Mappings::Spherical: s = ON_RDK_UD_DECAL_MAPPING_SPHERICAL; break;
|
|
case ON_Decal::Mappings::Cylindrical: s = ON_RDK_UD_DECAL_MAPPING_CYLINDRICAL; break;
|
|
case ON_Decal::Mappings::None: break;
|
|
}
|
|
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_MAPPING, s);
|
|
}
|
|
|
|
ON_Decal::Projections ON_Decal::Projection(void) const
|
|
{
|
|
const ON_wString s = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_PROJECTION, ON_RDK_UD_DECAL_PROJECTION_FORWARD).AsString();
|
|
|
|
if (ON_RDK_UD_DECAL_PROJECTION_FORWARD == s)
|
|
return ON_Decal::Projections::Forward;
|
|
|
|
if (ON_RDK_UD_DECAL_PROJECTION_BACKWARD == s)
|
|
return ON_Decal::Projections::Backward;
|
|
|
|
if (ON_RDK_UD_DECAL_PROJECTION_BOTH == s)
|
|
return ON_Decal::Projections::Both;
|
|
|
|
return ON_Decal::Projections::None;
|
|
}
|
|
|
|
void ON_Decal::SetProjection(Projections p)
|
|
{
|
|
const wchar_t* s = L"";
|
|
switch (p)
|
|
{
|
|
case ON_Decal::Projections::Forward: s = ON_RDK_UD_DECAL_PROJECTION_FORWARD; break;
|
|
case ON_Decal::Projections::Backward: s = ON_RDK_UD_DECAL_PROJECTION_BACKWARD; break;
|
|
case ON_Decal::Projections::Both: s = ON_RDK_UD_DECAL_PROJECTION_BOTH; break;
|
|
case ON_Decal::Projections::None: break;
|
|
}
|
|
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_PROJECTION, s);
|
|
}
|
|
|
|
bool ON_Decal::MapToInside(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_MAP_TO_INSIDE_ON, false).AsBool();
|
|
}
|
|
|
|
void ON_Decal::SetMapToInside(bool b)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_MAP_TO_INSIDE_ON, b);
|
|
}
|
|
|
|
double ON_Decal::Transparency(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_TRANSPARENCY, 0.0).AsDouble();
|
|
}
|
|
|
|
void ON_Decal::SetTransparency(double d)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_TRANSPARENCY, d);
|
|
}
|
|
|
|
ON_3dPoint ON_Decal::Origin(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_ORIGIN, ON_3dPoint::Origin).As3dPoint();
|
|
}
|
|
|
|
void ON_Decal::SetOrigin(const ON_3dPoint& pt)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_ORIGIN, pt);
|
|
}
|
|
|
|
ON_3dVector ON_Decal::VectorUp(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_VECTOR_UP, ON_3dPoint::Origin).As3dPoint();
|
|
}
|
|
|
|
void ON_Decal::SetVectorUp(const ON_3dVector& vec)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_VECTOR_UP, ON_3dPoint(vec));
|
|
}
|
|
|
|
ON_3dVector ON_Decal::VectorAcross(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_VECTOR_ACROSS, ON_3dPoint::Origin).As3dPoint();
|
|
}
|
|
|
|
void ON_Decal::SetVectorAcross(const ON_3dVector& vec)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_VECTOR_ACROSS, ON_3dPoint(vec));
|
|
}
|
|
|
|
double ON_Decal::Height(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_HEIGHT, 1.0).AsDouble();
|
|
}
|
|
|
|
void ON_Decal::SetHeight(double d)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_HEIGHT, d);
|
|
}
|
|
|
|
double ON_Decal::Radius(void) const
|
|
{
|
|
return m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_RADIUS, 1.0).AsDouble();
|
|
}
|
|
|
|
void ON_Decal::SetRadius(double d)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_RADIUS, d);
|
|
}
|
|
|
|
void ON_Decal::GetHorzSweep(double& sta, double& end) const
|
|
{
|
|
sta = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_HORZ_SWEEP_STA, 0.0).AsDouble();
|
|
end = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_HORZ_SWEEP_END, 0.0).AsDouble();
|
|
}
|
|
|
|
void ON_Decal::SetHorzSweep(double sta, double end)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_HORZ_SWEEP_STA, sta);
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_HORZ_SWEEP_END, end);
|
|
}
|
|
|
|
void ON_Decal::GetVertSweep(double& sta, double& end) const
|
|
{
|
|
sta = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_VERT_SWEEP_STA, 0.0).AsDouble();
|
|
end = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_VERT_SWEEP_END, 0.0).AsDouble();
|
|
}
|
|
|
|
void ON_Decal::SetVertSweep(double sta, double end)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_VERT_SWEEP_STA, sta);
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_VERT_SWEEP_END, end);
|
|
}
|
|
|
|
void ON_Decal::UVBounds(double& min_u, double& min_v, double& max_u, double& max_v) const
|
|
{
|
|
min_u = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_MIN_U, 0.0).AsDouble();
|
|
min_v = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_MIN_V, 0.0).AsDouble();
|
|
max_u = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_MAX_U, 1.0).AsDouble();
|
|
max_v = m_impl->GetParameter(XMLPath(), ON_RDK_UD_DECAL_MAX_V, 1.0).AsDouble();
|
|
}
|
|
|
|
void ON_Decal::SetUVBounds(double min_u, double min_v, double max_u, double max_v)
|
|
{
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_MIN_U, min_u);
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_MIN_V, min_v);
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_MAX_U, max_u);
|
|
m_impl->SetParameter(XMLPath(), ON_RDK_UD_DECAL_MAX_V, max_v);
|
|
}
|
|
|
|
ON__UINT32 ON_Decal::DataCRC(ON__UINT32 crc) const
|
|
{
|
|
return m_impl->NodeAt(XMLPath()).DataCRC(crc);
|
|
}
|
|
|
|
ON_UUID ON_Decal::Id(void) const
|
|
{
|
|
return m_impl->m_decal_id;
|
|
}
|
|
|
|
const ON_XMLNode& ON_Decal::XML(void) const
|
|
{
|
|
return m_impl->Node();
|
|
}
|
|
|
|
// ON_DecalCollection
|
|
|
|
ON_DecalCollection::~ON_DecalCollection()
|
|
{
|
|
DeleteAllDecals();
|
|
}
|
|
|
|
void ON_DecalCollection::DeleteAllDecals(void)
|
|
{
|
|
for (int i = 0; i < m_decals.Count(); i++)
|
|
{
|
|
delete m_decals[i];
|
|
}
|
|
|
|
m_decals.Destroy();
|
|
}
|
|
|
|
const ON_DecalCollection& ON_DecalCollection::operator = (const ON_DecalCollection& dc)
|
|
{
|
|
DeleteAllDecals();
|
|
|
|
for (int i = 0; i < dc.m_decals.Count(); i++)
|
|
{
|
|
ON_Decal* decal = dc.m_decals[i];
|
|
if (nullptr != decal)
|
|
{
|
|
m_decals.Append(new ON_Decal(*decal));
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool ON_DecalCollection::NodeContainsDecals(const ON_XMLRootNode& node) // Static.
|
|
{
|
|
const wchar_t* path = ON_RDK_UD_ROOT ON_RDK_SLASH ON_RDK_UD_DECALS;
|
|
const ON_XMLNode* decals_node = node.GetNodeAtPath(path);
|
|
if (nullptr == decals_node)
|
|
return false;
|
|
|
|
if (nullptr == decals_node->GetNamedChild(ON_RDK_UD_DECAL))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ON_DecalCollection::Populate(const ON_XMLRootNode& node)
|
|
{
|
|
DeleteAllDecals();
|
|
|
|
const wchar_t* path = ON_RDK_UD_ROOT ON_RDK_SLASH ON_RDK_UD_DECALS;
|
|
ON_XMLNode* decals_node = node.GetNodeAtPath(path);
|
|
if (nullptr == decals_node)
|
|
return; // No decals.
|
|
|
|
// Iterate over the decals under the decals node adding a new decal for each one.
|
|
// The decals copy the node into a local node which holds the XML for each decal
|
|
// in that decal. This XML will be modified by the decal setters and then repacked
|
|
// into the attribute user data later during the save process.
|
|
auto it = decals_node->GetChildIterator();
|
|
ON_XMLNode* child_node = nullptr;
|
|
while (nullptr != (child_node = it.GetNextChild()))
|
|
{
|
|
m_decals.Append(new ON_Decal(*child_node));
|
|
}
|
|
}
|
|
|
|
ON_Decal* ON_DecalCollection::AddDecal(void)
|
|
{
|
|
ON_XMLNode node(ON_RDK_UD_DECAL);
|
|
auto* decal = new ON_Decal(node);
|
|
m_decals.Append(decal);
|
|
|
|
return decal;
|
|
}
|
|
|
|
void CreateDecalsFromXML(const ONX_Model& model, int archive_3dm_version)
|
|
{
|
|
ONX_ModelComponentIterator cit(model, ON_ModelComponent::Type::ModelGeometry);
|
|
|
|
for (const ON_ModelComponent* component = cit.FirstComponent(); nullptr != component; component = cit.NextComponent())
|
|
{
|
|
const ON_3dmObjectAttributes* attr = GetComponentAttributes(*component);
|
|
if (nullptr == attr)
|
|
continue; // No attributes on component.
|
|
|
|
// Get the entire XML off of the attributes user data.
|
|
ON_wString xml;
|
|
GetRDKObjectInformation(*attr, xml, archive_3dm_version);
|
|
if (xml.IsEmpty())
|
|
continue; // No XML found on the component's attributes.
|
|
|
|
ON_XMLRootNode node;
|
|
if (ON_XMLNode::ReadError != node.ReadFromStream(xml))
|
|
{
|
|
attr->Internal_PopulateDecals(node);
|
|
}
|
|
else
|
|
{
|
|
ON_ERROR("Failed to read decal XML");
|
|
}
|
|
}
|
|
}
|
|
|
|
void CreateXMLFromDecals(const ONX_Model& model, int archive_3dm_version)
|
|
{
|
|
ONX_ModelComponentIterator cit(model, ON_ModelComponent::Type::ModelGeometry);
|
|
|
|
for (const ON_ModelComponent* component = cit.FirstComponent(); nullptr != component; component = cit.NextComponent())
|
|
{
|
|
ON_3dmObjectAttributes* attr = GetComponentAttributes(*component);
|
|
if (nullptr == attr)
|
|
continue; // No attributes on component.
|
|
|
|
const ON_SimpleArray<ON_Decal*>& decals = attr->GetDecalArray();
|
|
if (decals.Count() == 0)
|
|
continue; // No decals on attributes.
|
|
|
|
ON_XMLRootNode root;
|
|
ON_XMLNode* decals_node = root.CreateNodeAtPath(ON_RDK_UD_ROOT ON_RDK_SLASH ON_RDK_UD_DECALS);
|
|
if (nullptr == decals_node)
|
|
continue; // Failed to create node -- not likely to happen.
|
|
|
|
for (int i = 0; i < decals.Count(); i++)
|
|
{
|
|
const ON_Decal* decal = decals[i];
|
|
if (nullptr != decal)
|
|
{
|
|
decals_node->AttachChildNode(new ON_XMLNode(decal->XML()));
|
|
}
|
|
}
|
|
|
|
SetRDKObjectInformation(*attr, root.String(), archive_3dm_version);
|
|
}
|
|
}
|