From 3c751dd0ea7f1ec8c6efd51894669293cd67fa63 Mon Sep 17 00:00:00 2001 From: Bozo the Builder Date: Tue, 27 Jun 2023 14:12:47 -0700 Subject: [PATCH] Sync changes from upstream repository Co-authored-by: croudyj Co-authored-by: Dale Lear Co-authored-by: Greg Arden Co-authored-by: Jussi Aaltonen Co-authored-by: piac Co-authored-by: Pierre Cuvilliers Co-authored-by: Steve Baer Co-authored-by: Will Pearson --- opennurbs_3dm_attributes.cpp | 11 +- opennurbs_3dm_attributes.h | 2 +- opennurbs_3dm_settings.cpp | 12 + opennurbs_3dm_settings.h | 3 + opennurbs_curve.cpp | 9 + opennurbs_curve.h | 5 +- opennurbs_curveonsurface.cpp | 1 + opennurbs_curveproxy.cpp | 13 +- opennurbs_curveproxy.h | 10 +- opennurbs_dithering.h | 3 +- opennurbs_file_utilities.cpp | 130 ++-- opennurbs_file_utilities.h | 3 +- opennurbs_internal_defines.h | 9 + opennurbs_mesh.cpp | 83 +- opennurbs_nurbscurve.cpp | 9 + opennurbs_planesurface.cpp | 6 +- opennurbs_planesurface.h | 16 +- opennurbs_polycurve.cpp | 9 + opennurbs_post_effects.cpp | 2 +- opennurbs_post_effects.h | 5 +- opennurbs_public_version.h | 12 +- opennurbs_render_channels.h | 3 +- opennurbs_render_content.cpp | 370 +++++---- opennurbs_render_content.h | 20 +- opennurbs_safe_frame.h | 3 +- opennurbs_skylight.h | 7 +- opennurbs_subd.cpp | 47 +- opennurbs_subd.h | 509 ++++++------ opennurbs_subd_fragment.cpp | 1095 +++++++++++++------------- opennurbs_subd_heap.cpp | 39 +- opennurbs_subd_texture.cpp | 62 +- opennurbs_xml.cpp | 1422 +++++++++++++++++----------------- opennurbs_xml.h | 77 +- 33 files changed, 2151 insertions(+), 1856 deletions(-) diff --git a/opennurbs_3dm_attributes.cpp b/opennurbs_3dm_attributes.cpp index f9aa9384..5f27724e 100644 --- a/opennurbs_3dm_attributes.cpp +++ b/opennurbs_3dm_attributes.cpp @@ -781,7 +781,7 @@ bool ON_3dmObjectAttributes::Internal_ReadV5( ON_BinaryArchive& file ) ON_Color color = ON_Color::UnsetColor; rc = file.ReadColor(color); if (!rc) break; - SetHatchBackgrounFillColor(color); + SetHatchBackgroundFillColor(color); rc = file.ReadChar(&itemid); if (!rc || 0 == itemid) break; } @@ -1989,7 +1989,12 @@ unsigned int ON_3dmObjectAttributes::ApplyParentalControl( SetSectionAttributesSource(parents_attributes.SectionAttributesSource()); if (ON::SectionAttributesSource::FromLayer == SectionAttributesSource() && parent_layer.Index() >= 0) { - SetSectionAttributesSource(ON::SectionAttributesSource::FromLayer); + SetSectionAttributesSource(ON::SectionAttributesSource::FromObject); + const ON_SectionStyle* sectionStyle = parent_layer.CustomSectionStyle(); + if (sectionStyle) + SetCustomSectionStyle(*sectionStyle); + else + RemoveCustomSectionStyle(); } else { @@ -2446,7 +2451,7 @@ ON_Color ON_3dmObjectAttributes::HatchBackgroundFillColor() const { return m_private ? m_private->m_hatch_background_fill : ON_Color::UnsetColor; } -void ON_3dmObjectAttributes::SetHatchBackgrounFillColor(const ON_Color& color) +void ON_3dmObjectAttributes::SetHatchBackgroundFillColor(const ON_Color& color) { ON_Color c = color; if (c.Alpha() == 255) diff --git a/opennurbs_3dm_attributes.h b/opennurbs_3dm_attributes.h index d4862795..831b67ce 100644 --- a/opennurbs_3dm_attributes.h +++ b/opennurbs_3dm_attributes.h @@ -430,7 +430,7 @@ public: #pragma region Hatch Specific Attributes ON_Color HatchBackgroundFillColor() const; - void SetHatchBackgrounFillColor(const ON_Color& color); + void SetHatchBackgroundFillColor(const ON_Color& color); bool HatchBoundaryVisible() const; void SetHatchBoundaryVisible(bool on); #pragma endregion diff --git a/opennurbs_3dm_settings.cpp b/opennurbs_3dm_settings.cpp index 0c09821f..2f92a642 100644 --- a/opennurbs_3dm_settings.cpp +++ b/opennurbs_3dm_settings.cpp @@ -1849,6 +1849,18 @@ const ON_PostEffects& ON_3dmRenderSettings::PostEffects(void) const return const_cast(this)->PostEffects(); } +void ON_3dmRenderSettings::InvalidateCaches(void) const +{ + m_private->_ground_plane->OnInternalXmlChanged(nullptr); + m_private->_dithering->OnInternalXmlChanged(nullptr); + m_private->_safe_frame->OnInternalXmlChanged(nullptr); + m_private->_skylight->OnInternalXmlChanged(nullptr); + m_private->_linear_workflow->OnInternalXmlChanged(nullptr); + m_private->_render_channels->OnInternalXmlChanged(nullptr); + m_private->_sun->OnInternalXmlChanged(nullptr); + m_private->_post_effects->OnInternalXmlChanged(nullptr); +} + #ifdef RDK_RENDER_PRESETS extern ON_UUID uuidRenderPreset_Studio; diff --git a/opennurbs_3dm_settings.h b/opennurbs_3dm_settings.h index 8ce73354..798734d7 100644 --- a/opennurbs_3dm_settings.h +++ b/opennurbs_3dm_settings.h @@ -872,6 +872,9 @@ public: // Sets the id of the rendering environment for a particular usage. void SetRenderEnvironmentId(EnvironmentUsage usage, const ON_UUID& id); + // Invalidate any caches in the render settings. + void InvalidateCaches(void) const; + private: unsigned short m_reserved1 = 0; diff --git a/opennurbs_curve.cpp b/opennurbs_curve.cpp index 858b1573..9676b41f 100644 --- a/opennurbs_curve.cpp +++ b/opennurbs_curve.cpp @@ -559,6 +559,15 @@ bool ON_Curve::IsPlanar( ON_Plane* plane, double tolerance ) const } } } + + // RH-75060 GBA 9-June-23 + // For a planar simple closed curve we should return the plane + // whose orientation that matches the curve orientation. + if (rc && plane && IsClosed()) + { + if (ON_ClosedCurveOrientation(*this, *plane) < 0) + plane->Flip(); + } } return rc; } diff --git a/opennurbs_curve.h b/opennurbs_curve.h index 8692222b..6234be33 100644 --- a/opennurbs_curve.h +++ b/opennurbs_curve.h @@ -396,7 +396,10 @@ public: // Parameters: // plane - [out] if not nullptr and true is returned, // the plane parameters are filled in. - // tolerance - [in] tolerance to use when checking + // tolerance - [in] tolerance to use when checkin + // Note: + // If the curve is a simple planar closed curve the plane + // orientation agrees with the curve orientation. // Returns: // true if there is a plane such that the maximum distance from // the curve to the plane is <= tolerance. diff --git a/opennurbs_curveonsurface.cpp b/opennurbs_curveonsurface.cpp index 3c9b80e7..1e7edc65 100644 --- a/opennurbs_curveonsurface.cpp +++ b/opennurbs_curveonsurface.cpp @@ -326,6 +326,7 @@ ON_CurveOnSurface::IsPlanar( double tolerance // tolerance to use when checking linearity ) const { + // todo 9-June-23 GBA This just seams wrong?! return ( ON_PlaneSurface::Cast(m_s) ) ? true : false; } diff --git a/opennurbs_curveproxy.cpp b/opennurbs_curveproxy.cpp index a9455a36..99edc4dd 100644 --- a/opennurbs_curveproxy.cpp +++ b/opennurbs_curveproxy.cpp @@ -706,7 +706,18 @@ ON_CurveProxy::IsPlanar( double tolerance // tolerance to use when checking linearity ) const { - return ( m_real_curve ) ? m_real_curve->IsPlanar(plane,tolerance) : false; + // RH-75060 GBA 9-June-23 Changed to consider only the m_real_curve_domain if need be. + // return (m_real_curve) ? m_real_curve->IsPlanar(plane, tolerance) : false; + bool rc = false; + if(m_real_curve) + { + rc = m_real_curve->IsPlanar(plane, tolerance); + if (!rc) + { + rc = ON_Curve::IsPlanar(plane, tolerance); + } + } + return rc; } bool diff --git a/opennurbs_curveproxy.h b/opennurbs_curveproxy.h index 61bda601..2a8f4ad2 100644 --- a/opennurbs_curveproxy.h +++ b/opennurbs_curveproxy.h @@ -164,14 +164,14 @@ private: // the reverse of the m_curve parameterization. bool m_bReversed; - // The m_domain interval is always increasing and included in - // m_curve->Domain(). The m_domain interval defines the portion - // of m_curve that "this" proxy uses and it can be a proper - // sub-interval of m_curve->Domain(). + // The m_real_curve_domain interval is always increasing and included in + // m_real_curve->Domain(). The m_real_curve_domain interval defines the portion + // of m_real_curve that "this" proxy uses and it can be a proper + // sub-interval of m_real_curve->Domain(). ON_Interval m_real_curve_domain; // The evaluation domain of this curve. If "t" is a parameter for - // "this" and "r" is a parameter for m_curve, then when m_bReversed==false + // "this" and "r" is a parameter for m_real_curve, then when m_bReversed==false // we have // t = m_this_domain.ParameterAt(m_real_curve_domain.NormalizedParameterAt(r)) // r = m_real_curve_domain.ParameterAt(m_this_domain.NormalizedParameterAt(t)) diff --git a/opennurbs_dithering.h b/opennurbs_dithering.h index ef195036..cf6e1a7a 100644 --- a/opennurbs_dithering.h +++ b/opennurbs_dithering.h @@ -47,8 +47,7 @@ public: // Emergency virtual function for future expansion. virtual void* EVF(const wchar_t* func, void* data); -private: // For internal use only. - friend class ON_3dmRenderSettingsPrivate; + // For internal use only. virtual void OnInternalXmlChanged(const ON_Dithering*); private: diff --git a/opennurbs_file_utilities.cpp b/opennurbs_file_utilities.cpp index 9a8df8ba..7003f0bc 100644 --- a/opennurbs_file_utilities.cpp +++ b/opennurbs_file_utilities.cpp @@ -4236,15 +4236,24 @@ class ON_File public: virtual ~ON_File() { } - bool Open(const wchar_t* filename, const wchar_t* mode) { m_pFile = ON_FileStream::Open(filename, mode); return nullptr != m_pFile; } - bool Close(void) const { return ON_FileStream::Close(m_pFile) == 0; } - bool SeekFromCurrentPosition(ON__INT64 offset) const { return ON_FileStream::SeekFromCurrentPosition(m_pFile, offset); } - bool SeekFromStart(ON__INT64 offset) const { return ON_FileStream::SeekFromStart(m_pFile, offset); } - bool SeekFromEnd(ON__INT64 offset) const { return ON_FileStream::SeekFromEnd(m_pFile, offset); } - bool Seek(ON__INT64 offset, int origin) const { return ON_FileStream::Seek(m_pFile, offset, origin); } - ON__INT64 CurrentPosition(void) const { return ON_FileStream::CurrentPosition(m_pFile); } - ON__UINT64 Read(ON__UINT64 count, void* buffer) const { return ON_FileStream::Read(m_pFile, count, buffer); } - ON__UINT64 Write(ON__UINT64 count, const void* buffer) const { return ON_FileStream::Write(m_pFile, count, buffer); } + bool Open(const wchar_t* filename, const wchar_t* mode) + { + _file = ON_FileStream::Open(filename, mode); + return nullptr != _file; + } + + bool Close(void) const { return ON_FileStream::Close(_file) == 0; } + bool SeekFromCurrentPosition(ON__INT64 offset) const { return ON_FileStream::SeekFromCurrentPosition(_file, offset); } + bool SeekFromStart(ON__INT64 offset) const { return ON_FileStream::SeekFromStart(_file, offset); } + bool SeekFromEnd(ON__INT64 offset) const { return ON_FileStream::SeekFromEnd(_file, offset); } + bool Seek(ON__INT64 offset, int origin) const { return ON_FileStream::Seek(_file, offset, origin); } + ON__INT64 CurrentPosition(void) const { return ON_FileStream::CurrentPosition(_file); } + ON__UINT64 Read(ON__UINT64 count, void* buffer) const { return ON_FileStream::Read(_file, count, buffer); } + + ON__UINT64 Write(ON__UINT64 count, const void* buffer) const + { + return ON_FileStream::Write(_file, count, buffer); + } ON__UINT64 GetLength(void) const { @@ -4257,19 +4266,19 @@ public: } private: - FILE* m_pFile = nullptr; + FILE* _file = nullptr; }; -class ON_UnicodeTextFile::CImpl final +class ON_UnicodeTextFilePrivate final { public: - ~CImpl() { Close(); } + ~ON_UnicodeTextFilePrivate() { Close(); } - bool Open(const wchar_t* wszFullPath, Modes mode); + bool Open(const wchar_t* wszFullPath, ON_UnicodeTextFile::Modes mode); bool Close(void); bool ReadString(ON_wString& s); bool WriteString(const wchar_t* wsz); - bool ReadHeader(Types& t); + bool ReadHeader(ON_UnicodeTextFile::Types& t); bool WriteHeader(void); bool ReadStringFromUTF8(ON_wString& s); bool ReadStringFromUTF16(ON_wString& s); @@ -4279,18 +4288,18 @@ public: size_t WriteData(const void* buf, size_t bytes_to_write); public: - ON_File m_File; - Types m_Type = Types::Unknown; + ON_File _file; + ON_UnicodeTextFile::Types _type = ON_UnicodeTextFile::Types::Unknown; }; -size_t ON_UnicodeTextFile::CImpl::ReadData(void* buf, size_t bytes_to_read) +size_t ON_UnicodeTextFilePrivate::ReadData(void* buf, size_t bytes_to_read) { - return m_File.Read(bytes_to_read, buf); + return _file.Read(bytes_to_read, buf); } -size_t ON_UnicodeTextFile::CImpl::WriteData(const void* buf, size_t bytes_to_write) +size_t ON_UnicodeTextFilePrivate::WriteData(const void* buf, size_t bytes_to_write) { - return m_File.Write(bytes_to_write, buf); + return _file.Write(bytes_to_write, buf); } static const wchar_t* FileStreamMode(ON_UnicodeTextFile::Modes m) @@ -4305,14 +4314,14 @@ static const wchar_t* FileStreamMode(ON_UnicodeTextFile::Modes m) return L""; } -bool ON_UnicodeTextFile::CImpl::Open(const wchar_t* wszFullPath, Modes mode) +bool ON_UnicodeTextFilePrivate::Open(const wchar_t* wszFullPath, ON_UnicodeTextFile::Modes mode) { bool ok = false; int attemptsCounter = 0; while (!ok && (attemptsCounter < 100)) { - if (m_File.Open(wszFullPath, FileStreamMode(mode))) + if (_file.Open(wszFullPath, FileStreamMode(mode))) { ok = true; } @@ -4325,27 +4334,27 @@ bool ON_UnicodeTextFile::CImpl::Open(const wchar_t* wszFullPath, Modes mode) if (ok) { - if (Modes::Write == mode) + if (ON_UnicodeTextFile::Modes::Write == mode) { ok = WriteHeader(); } else { - ok = ReadHeader(m_Type); + ok = ReadHeader(_type); } } return ok; } -bool ON_UnicodeTextFile::CImpl::Close(void) +bool ON_UnicodeTextFilePrivate::Close(void) { - return m_File.Close(); + return _file.Close(); } -bool ON_UnicodeTextFile::CImpl::ReadHeader(Types& t) +bool ON_UnicodeTextFilePrivate::ReadHeader(ON_UnicodeTextFile::Types& t) { - if (0 != m_File.CurrentPosition()) + if (0 != _file.CurrentPosition()) return false; ON__UINT8 pBuf[3] = { 0 }; @@ -4357,7 +4366,7 @@ bool ON_UnicodeTextFile::CImpl::ReadHeader(Types& t) { if (pBuf[1] == ON__UINT8(0xFE)) { - t = Types::UTF16; + t = ON_UnicodeTextFile::Types::UTF16; return true; } } @@ -4370,7 +4379,7 @@ bool ON_UnicodeTextFile::CImpl::ReadHeader(Types& t) { if (pBuf[2] == ON__UINT8(0xBF)) { - t = Types::UTF8; + t = ON_UnicodeTextFile::Types::UTF8; return true; } } @@ -4378,18 +4387,18 @@ bool ON_UnicodeTextFile::CImpl::ReadHeader(Types& t) } // No BOM was found so rewind and assume UTF8. This allows testing with ASCII files. - m_File.SeekFromStart(0); - t = Types::UTF8; + _file.SeekFromStart(0); + t = ON_UnicodeTextFile::Types::UTF8; return true; } -bool ON_UnicodeTextFile::CImpl::WriteHeader(void) +bool ON_UnicodeTextFilePrivate::WriteHeader(void) { ON__UINT8 pBuf[3] = { 0 }; size_t sizeBOM = 2; - if (Types::UTF8 == m_Type) + if (ON_UnicodeTextFile::Types::UTF8 == _type) { sizeBOM = 3; pBuf[0] = ON__UINT8(0xEF); @@ -4397,7 +4406,7 @@ bool ON_UnicodeTextFile::CImpl::WriteHeader(void) pBuf[2] = ON__UINT8(0xBF); } else - if (Types::UTF16 == m_Type) + if (ON_UnicodeTextFile::Types::UTF16 == _type) { pBuf[0] = ON__UINT8(0xFF); pBuf[1] = ON__UINT8(0xFE); @@ -4410,41 +4419,41 @@ bool ON_UnicodeTextFile::CImpl::WriteHeader(void) return true; } -bool ON_UnicodeTextFile::CImpl::ReadString(ON_wString& s) +bool ON_UnicodeTextFilePrivate::ReadString(ON_wString& s) { - switch (m_Type) + switch (_type) { - case Types::UTF8: + case ON_UnicodeTextFile::Types::UTF8: return ReadStringFromUTF8(s); - case Types::UTF16: + case ON_UnicodeTextFile::Types::UTF16: return ReadStringFromUTF16(s); - - case Types::Unknown: + + case ON_UnicodeTextFile::Types::Unknown: default: return false; } } -bool ON_UnicodeTextFile::CImpl::WriteString(const wchar_t* wsz) +bool ON_UnicodeTextFilePrivate::WriteString(const wchar_t* wsz) { - switch (m_Type) + switch (_type) { - case Types::UTF8: + case ON_UnicodeTextFile::Types::UTF8: return WriteStringToUTF8(wsz); - case Types::UTF16: + case ON_UnicodeTextFile::Types::UTF16: return WriteStringToUTF16(wsz); - - case Types::Unknown: + + case ON_UnicodeTextFile::Types::Unknown: default: return false; } } -bool ON_UnicodeTextFile::CImpl::ReadStringFromUTF8(ON_wString& s) +bool ON_UnicodeTextFilePrivate::ReadStringFromUTF8(ON_wString& s) { - const auto size_in_bytes = m_File.GetLength() - m_File.CurrentPosition(); + const auto size_in_bytes = _file.GetLength() - _file.CurrentPosition(); auto p = std::unique_ptr(new ON__UINT8[size_in_bytes + 1]); auto* pBuffer = p.get(); @@ -4464,10 +4473,10 @@ bool ON_UnicodeTextFile::CImpl::ReadStringFromUTF8(ON_wString& s) return !s.IsEmpty(); } -bool ON_UnicodeTextFile::CImpl::ReadStringFromUTF16(ON_wString& s) +bool ON_UnicodeTextFilePrivate::ReadStringFromUTF16(ON_wString& s) { const auto char_size = sizeof(ON__UINT16); - const auto size_in_bytes = m_File.GetLength() - m_File.CurrentPosition(); + const auto size_in_bytes = _file.GetLength() - _file.CurrentPosition(); const auto size_in_chars = size_in_bytes / char_size; #ifdef ON_RUNTIME_WIN @@ -4502,7 +4511,7 @@ bool ON_UnicodeTextFile::CImpl::ReadStringFromUTF16(ON_wString& s) return true; } -bool ON_UnicodeTextFile::CImpl::WriteStringToUTF8(const wchar_t* wsz) +bool ON_UnicodeTextFilePrivate::WriteStringToUTF8(const wchar_t* wsz) { const auto num_chars = ON_ConvertWideCharToUTF8(false, wsz, -1, nullptr, 0, nullptr, 0, 0, nullptr); @@ -4517,7 +4526,7 @@ bool ON_UnicodeTextFile::CImpl::WriteStringToUTF8(const wchar_t* wsz) return true; } -bool ON_UnicodeTextFile::CImpl::WriteStringToUTF16(const wchar_t* wsz) +bool ON_UnicodeTextFilePrivate::WriteStringToUTF16(const wchar_t* wsz) { #ifdef ON_RUNTIME_WIN // On Windows, wchar_t is UTF16 so we can save the file directly from 'wsz'. @@ -4549,32 +4558,31 @@ bool ON_UnicodeTextFile::CImpl::WriteStringToUTF16(const wchar_t* wsz) ON_UnicodeTextFile::ON_UnicodeTextFile(Types t) { - m_impl = new CImpl; - m_impl->m_Type = t; + _private = new ON_UnicodeTextFilePrivate; + _private->_type = t; } ON_UnicodeTextFile::~ON_UnicodeTextFile() { - m_impl->~CImpl(); - m_impl = nullptr; + delete _private; } bool ON_UnicodeTextFile::Open(const wchar_t* wszFullPath, Modes mode) { - return m_impl->Open(wszFullPath, mode); + return _private->Open(wszFullPath, mode); } bool ON_UnicodeTextFile::Close(void) { - return m_impl->Close(); + return _private->Close(); } bool ON_UnicodeTextFile::ReadString(ON_wString& s) { - return m_impl->ReadString(s); + return _private->ReadString(s); } bool ON_UnicodeTextFile::WriteString(const wchar_t* wsz) { - return m_impl->WriteString(wsz); + return _private->WriteString(wsz); } diff --git a/opennurbs_file_utilities.h b/opennurbs_file_utilities.h index 31c1e5b4..980fd6c4 100644 --- a/opennurbs_file_utilities.h +++ b/opennurbs_file_utilities.h @@ -1808,8 +1808,7 @@ public: const ON_UnicodeTextFile& operator = (const ON_UnicodeTextFile&) = delete; private: - class CImpl; - CImpl* m_impl; + class ON_UnicodeTextFilePrivate* _private; }; #endif diff --git a/opennurbs_internal_defines.h b/opennurbs_internal_defines.h index 7925d7c5..1c031d38 100644 --- a/opennurbs_internal_defines.h +++ b/opennurbs_internal_defines.h @@ -27,6 +27,15 @@ #undef max #endif +#ifdef ON_RUNTIME_WIN +#define PRIVATE_CHECK(c) auto priv_has = sizeof(_PRIVATE), priv_needs = sizeof(c) + 64; \ + if (priv_has < priv_needs) { ON_wString priv; \ + priv.Format(L#c L" _PRIVATE has %u but needs %u bytes\n", priv_has, priv_needs); \ + OutputDebugString(priv); ON_ASSERT(false); } +#else +#define PRIVATE_CHECK(c) { } +#endif + #define ON_KIND_MATERIAL L"material" #define ON_KIND_ENVIRONMENT L"environment" #define ON_KIND_TEXTURE L"texture" diff --git a/opennurbs_mesh.cpp b/opennurbs_mesh.cpp index 7ca1a864..435c8566 100644 --- a/opennurbs_mesh.cpp +++ b/opennurbs_mesh.cpp @@ -1360,11 +1360,68 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const dump.Print("m_Ttag:\n"); dump.PushIndent(); m_Ttag.Dump(dump); dump.PopIndent(); dump.Print( ON_wString(L"Memory used: ") + ON_wString::ToMemorySize(this->SizeOf()) + ON_wString(L"\n") ); - dump.PushIndent(); + + const ON_MeshParameters* mp = this->MeshParameters(); + if (nullptr != mp) + { + ON_String description; + switch (mp->GeometrySettingsType(true)) + { + case ON_MeshParameters::Type::Unset: + description = ON_String::EmptyString; + break; + case ON_MeshParameters::Type::Default: + description = ON_String("ON_MeshParameters::DefaultMesh"); + break; + case ON_MeshParameters::Type::FastRender: + description = ON_String("ON_MeshParameters::FastRenderMesh"); + break; + case ON_MeshParameters::Type::QualityRender: + description = ON_String("ON_MeshParameters::QualityRenderMesh"); + break; + case ON_MeshParameters::Type::DefaultAnalysis: + description = ON_String("ON_MeshParameters::DefaultAnalysisMesh"); + break; + case ON_MeshParameters::Type::FromMeshDensity: + description = ON_String::FormatToString("ON_MeshParameters::CreateFromMeshDensity(%g)", mp->MeshDensity()); + break; + case ON_MeshParameters::Type::Custom: + description = ON_String::EmptyString; + break; + default: + description = ON_String::EmptyString; + break; + } + + dump.PrintNewLine(); + if (description.IsNotEmpty()) + { + dump.Print("NURBS, ON_Brep, ON_Extrusion meshing parameters:\n"); + { + const ON_TextLogIndent indent1(dump); + dump.Print("%s\n", static_cast(description)); + } + dump.Print("SubD meshing parameters:\n"); + { + const ON_TextLogIndent indent1(dump); + const ON_SubDDisplayParameters subdmp = mp->SubDDisplayParameters(); + subdmp.Dump(dump); + } + } + else + { + dump.Print("Custom meshing parameters:\n"); + const ON_TextLogIndent indent1(dump); + mp->Dump(dump); + } + dump.PrintNewLine(); + } + + const ON_TextLogIndent indent1(dump); dump.Print("%d mesh vertices:\n",m_V.Count()); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); Internal_PrintMeshArrayHash(dump, m_V, L"m_V array hash", true); const ON_3dPoint* D = 0; if ( bDoubles ) @@ -1397,14 +1454,13 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const } } } - dump.PopIndent(); } if ( HasVertexNormals() ) { dump.Print("%d mesh vertex normals:\n",m_N.Count()); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); Internal_PrintMeshArrayHash(dump, m_N, L"m_N array hash", true); for (i = 0; i < vcount; i++) { @@ -1419,7 +1475,6 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const dump.Print("m_N[%d] = (%g,%g,%g)\n",i,p.x,p.y,p.z); } } - dump.PopIndent(); } } @@ -1427,7 +1482,7 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const { dump.Print("%d mesh vertex texture coordinates:\n",m_T.Count()); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); Internal_PrintMeshArrayHash(dump, m_T, L"m_T array hash", true); for (i = 0; i < vcount; i++) { @@ -1444,7 +1499,6 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const dump.Print("m_T[%d] = (%g,%g)\n",i,p.x,p.y); } } - dump.PopIndent(); } } @@ -1453,7 +1507,7 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const { dump.Print("%d mesh vertex surface parameters:\n",m_S.Count()); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); Internal_PrintMeshArrayHash(dump, m_S, L"m_S array hash", true); for (i = 0; i < vcount; i++) { @@ -1468,13 +1522,12 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const dump.Print("m_S[%d] = (%g,%g)\n",i,srfuv.x,srfuv.y); } } - dump.PopIndent(); } } dump.Print("%d mesh faces:\n",m_F.Count()); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); Internal_PrintMeshArrayHash(dump, m_F, L"m_F array hash", true); for (i = 0; i < fcount; i++) { @@ -1488,14 +1541,13 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const else dump.Print("m_F[%d].vi = (%d,%d,%d,%d)\n",i,m_F[i].vi[0],m_F[i].vi[1],m_F[i].vi[2],m_F[i].vi[3]); } - dump.PopIndent(); } if ( HasFaceNormals() ) { dump.Print("%d mesh face normals:\n",m_FN.Count()); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); for (i = 0; i < fcount; i++) { if ( i == half_max && 2*half_max < fcount ) @@ -1509,7 +1561,6 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const dump.Print("m_FN[%d] = (%g,%g,%g)\n",i,p.x,p.y,p.z); } } - dump.PopIndent(); } } @@ -1520,7 +1571,7 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const const int ngon_count = NgonCount(); dump.Print("%d mesh n-gons:\n",ngon_count); { - dump.PushIndent(); + const ON_TextLogIndent indent2(dump); for (i = 0; i < ngon_count; i++) { if ( i == half_max && 2*half_max < ngon_count ) @@ -1545,12 +1596,8 @@ void ON_Mesh::Dump( ON_TextLog& dump ) const } } } - dump.PopIndent(); } } - - - dump.PopIndent(); } diff --git a/opennurbs_nurbscurve.cpp b/opennurbs_nurbscurve.cpp index e9457bb6..519bb221 100644 --- a/opennurbs_nurbscurve.cpp +++ b/opennurbs_nurbscurve.cpp @@ -1503,6 +1503,15 @@ ON_NurbsCurve::IsPlanar( rc = IsInPlane( test_plane, tolerance ); if ( rc && plane ) *plane = test_plane; + + // RH-75060 GBA 9-June-23 + // For a planar simple closed curve we should return the plane + // whose orientation that matches the curve orientation. + if (rc && plane && IsClosed()) + { + if (ON_ClosedCurveOrientation(*this, *plane) < 0) + plane->Flip(); + } } } return rc; diff --git a/opennurbs_planesurface.cpp b/opennurbs_planesurface.cpp index 4a0a632c..eb8b18cd 100644 --- a/opennurbs_planesurface.cpp +++ b/opennurbs_planesurface.cpp @@ -650,7 +650,7 @@ bool ON_PlaneSurface::CreatePseudoInfinitePlane( } -bool ON_PlaneSurface::CreatePseudoInfinitePlaneTight( +bool ON_PlaneSurface::CreatePlaneThroughBox( const ON_Plane& plane, const ON_BoundingBox& bbox, double padding @@ -683,7 +683,7 @@ bool ON_PlaneSurface::CreatePseudoInfinitePlaneTight( } -bool ON_PlaneSurface::CreatePseudoInfinitePlaneTight( +bool ON_PlaneSurface::CreatePlaneThroughBox( const ON_PlaneEquation& plane_equation, const ON_BoundingBox& bbox, double padding @@ -692,7 +692,7 @@ bool ON_PlaneSurface::CreatePseudoInfinitePlaneTight( ON_Plane plane(plane_equation); ON_3dPoint center = plane.ClosestPointTo(bbox.Center()); plane.origin = center; - return CreatePseudoInfinitePlaneTight(plane, bbox, padding); + return CreatePlaneThroughBox(plane, bbox, padding); } diff --git a/opennurbs_planesurface.h b/opennurbs_planesurface.h index 3060a1de..77de5bef 100644 --- a/opennurbs_planesurface.h +++ b/opennurbs_planesurface.h @@ -506,8 +506,10 @@ public: /* Description: - Create a plane that contains the projection of a bounding box. - This method is slower, yet stricter because it uses box edges intersection rather than box + Create a plane that contains the intersection of a bounding box. + This method uses box edges intersections rather than box vertices + projections on the plane, which is what CreatePseudoInfinitePlane + uses. Parameters: plane - [in] bbox - [in] @@ -517,7 +519,7 @@ public: Returns: true if successful */ - bool CreatePseudoInfinitePlaneTight( + bool CreatePlaneThroughBox( const ON_Plane& plane, const ON_BoundingBox& bbox, double padding = 0.0625 @@ -525,8 +527,10 @@ public: /* Description: - Create a plane that contains the projection of a bounding box. - This method is slower, yet stricter because it uses box edges intersection rather than box + Create a plane that contains the intersection of a bounding box. + This method uses box edges intersections rather than box vertices + projections on the plane, which is what CreatePseudoInfinitePlane + uses. Parameters: plane - [in] bbox - [in] @@ -536,7 +540,7 @@ public: Returns: true if successful */ - bool CreatePseudoInfinitePlaneTight( + bool CreatePlaneThroughBox( const ON_PlaneEquation& plane, const ON_BoundingBox& bbox, double padding = 0.0625 diff --git a/opennurbs_polycurve.cpp b/opennurbs_polycurve.cpp index 7a94a004..9ed8da01 100644 --- a/opennurbs_polycurve.cpp +++ b/opennurbs_polycurve.cpp @@ -1042,6 +1042,15 @@ ON_PolyCurve::IsPlanar( rc = IsInPlane( test_plane, tolerance ); if (rc && plane) *plane = test_plane; + + // RH-75060 GBA 9-June-23 + // For a planar simple closed curve we should return the plane + // whose orientation that matches the curve orientation. + if (rc && plane && IsClosed()) + { + if (ON_ClosedCurveOrientation(*this, *plane) < 0) + plane->Flip(); + } } return rc; } diff --git a/opennurbs_post_effects.cpp b/opennurbs_post_effects.cpp index 67435a5e..ceb8ba74 100644 --- a/opennurbs_post_effects.cpp +++ b/opennurbs_post_effects.cpp @@ -803,7 +803,7 @@ void* ON_PostEffects::EVF(const wchar_t*, void*) return nullptr; } -void ON_PostEffects::OnInternalXmlChanged(ON_PostEffects*) +void ON_PostEffects::OnInternalXmlChanged(const ON_PostEffects*) { _impl->Clear(); } diff --git a/opennurbs_post_effects.h b/opennurbs_post_effects.h index ead76334..85662c4a 100644 --- a/opennurbs_post_effects.h +++ b/opennurbs_post_effects.h @@ -191,11 +191,12 @@ public: // Expert access to the post effect XML. // Sets the XML node that stores the state of all the post effects (ON_RDK_POST_EFFECTS). void SetPostEffectsNode(const ON_XMLNode&); + // For internal use only. + virtual void OnInternalXmlChanged(const ON_PostEffects*); + private: // For internal use only. - friend class ON_3dmRenderSettingsPrivate; friend class ON_PostEffect; ON_XMLNode& WritablePostEffectsNode(void); - virtual void OnInternalXmlChanged(ON_PostEffects*); public: class CImpl; diff --git a/opennurbs_public_version.h b/opennurbs_public_version.h index fd7a38f6..c01c1b22 100644 --- a/opennurbs_public_version.h +++ b/opennurbs_public_version.h @@ -15,9 +15,9 @@ // #define RMA_VERSION_YEAR 2023 #define RMA_VERSION_MONTH 6 -#define RMA_VERSION_DATE 9 +#define RMA_VERSION_DATE 27 #define RMA_VERSION_HOUR 14 -#define RMA_VERSION_MINUTE 36 +#define RMA_VERSION_MINUTE 0 //////////////////////////////////////////////////////////////// // @@ -35,8 +35,8 @@ // 3 = build system release build #define RMA_VERSION_BRANCH 0 -#define VERSION_WITH_COMMAS 8,0,23160,14360 -#define VERSION_WITH_PERIODS 8.0.23160.14360 +#define VERSION_WITH_COMMAS 8,0,23178,14000 +#define VERSION_WITH_PERIODS 8.0.23178.14000 #define COPYRIGHT "Copyright (C) 1993-2023, Robert McNeel & Associates. All Rights Reserved." #define SPECIAL_BUILD_DESCRIPTION "Public OpenNURBS C++ 3dm file IO library." @@ -47,8 +47,8 @@ #define RMA_VERSION_NUMBER_SR_STRING "SR0" #define RMA_VERSION_NUMBER_SR_WSTRING L"SR0" -#define RMA_VERSION_WITH_PERIODS_STRING "8.0.23160.14360" -#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.0.23160.14360" +#define RMA_VERSION_WITH_PERIODS_STRING "8.0.23178.14000" +#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.0.23178.14000" diff --git a/opennurbs_render_channels.h b/opennurbs_render_channels.h index 952e8ae9..5dbc7b71 100644 --- a/opennurbs_render_channels.h +++ b/opennurbs_render_channels.h @@ -50,8 +50,7 @@ public: // Emergency virtual function for future expansion. virtual void* EVF(const wchar_t* func, void* data); -private: // For internal use only. - friend class ON_3dmRenderSettingsPrivate; + // For internal use only. virtual void OnInternalXmlChanged(const ON_RenderChannels*); private: diff --git a/opennurbs_render_content.cpp b/opennurbs_render_content.cpp index 0757ea4b..26c692bd 100644 --- a/opennurbs_render_content.cpp +++ b/opennurbs_render_content.cpp @@ -339,11 +339,11 @@ ON_UUID UniversalRenderEngineId(void) return uuid; } -class ON_RenderContent::CImpl +class ON_RenderContentPrivate { public: - CImpl(ON_RenderContent& rc, const wchar_t* kind); - virtual ~CImpl(); + ON_RenderContentPrivate(ON_RenderContent& rc, const wchar_t* kind); + virtual ~ON_RenderContentPrivate(); void SetXMLNode(const ON_XMLNode& node); @@ -364,6 +364,12 @@ public: public: void InternalSetPropertyValue(const wchar_t* name, const ON_XMLVariant& value); + static void SetRenderContentNodeRecursive(const ON_RenderContent& rc, ON_XMLNode& node); + static void BuildXMLHierarchy(const ON_RenderContent& rc, ON_XMLNode& node); + static ON_XMLNode* NewXMLNodeRecursive(const ON_RenderContent& rc); + static void SetModel(const ON_RenderContent& rc, ONX_Model& model); + static ON_RenderContent* NewRenderContentFromNode(const ON_XMLNode& node); + private: ON_RenderContent* FindLastChild(void) const; ON_RenderContent* FindPrevSibling(ON_RenderContent* child) const; @@ -378,24 +384,24 @@ public: mutable std::recursive_mutex m_mutex; }; -ON_RenderContent::CImpl::CImpl(ON_RenderContent& rc, const wchar_t* kind) +ON_RenderContentPrivate::ON_RenderContentPrivate(ON_RenderContent& rc, const wchar_t* kind) : m_node(kind), m_render_content(rc) { } -ON_RenderContent::CImpl::~CImpl() +ON_RenderContentPrivate::~ON_RenderContentPrivate() { DeleteAllChildren(); } -const ON_XMLNode* ON_RenderContent::CImpl::XMLNode_Simulation(void) const +const ON_XMLNode* ON_RenderContentPrivate::XMLNode_Simulation(void) const { return m_node.GetNamedChild(ON_RENDER_CONTENT_SIMULATION); } -ON_XMLVariant ON_RenderContent::CImpl::GetPropertyValue(const wchar_t* name) const +ON_XMLVariant ON_RenderContentPrivate::GetPropertyValue(const wchar_t* name) const { // Gets a property from the content node. This is one of: // @@ -416,14 +422,14 @@ ON_XMLVariant ON_RenderContent::CImpl::GetPropertyValue(const wchar_t* name) con return v; } -void ON_RenderContent::CImpl::SetPropertyValue(const wchar_t* name, const ON_XMLVariant& value) +void ON_RenderContentPrivate::SetPropertyValue(const wchar_t* name, const ON_XMLVariant& value) { std::lock_guard lg(m_mutex); InternalSetPropertyValue(name, value); } -void ON_RenderContent::CImpl::InternalSetPropertyValue(const wchar_t* name, const ON_XMLVariant& value) +void ON_RenderContentPrivate::InternalSetPropertyValue(const wchar_t* name, const ON_XMLVariant& value) { // Sets a property on the content node. This is one of: // @@ -442,7 +448,7 @@ void ON_RenderContent::CImpl::InternalSetPropertyValue(const wchar_t* name, cons } } -void ON_RenderContent::CImpl::SetXMLNode(const ON_XMLNode& node) +void ON_RenderContentPrivate::SetXMLNode(const ON_XMLNode& node) { std::lock_guard lg(m_mutex); @@ -483,9 +489,9 @@ void ON_RenderContent::CImpl::SetXMLNode(const ON_XMLNode& node) m_render_content.SetId(GetPropertyValue(ON_RENDER_CONTENT_INSTANCE_ID).AsUuid()); } -bool ON_RenderContent::CImpl::AddChild(ON_RenderContent& child) +bool ON_RenderContentPrivate::AddChild(ON_RenderContent& child) { - if ((nullptr != child.m_impl->m_model) || (nullptr != child.m_impl->m_parent) || (nullptr != child.m_impl->m_next_sibling)) + if ((nullptr != child._private->m_model) || (nullptr != child._private->m_parent) || (nullptr != child._private->m_next_sibling)) return false; if (nullptr == m_first_child) @@ -498,16 +504,16 @@ bool ON_RenderContent::CImpl::AddChild(ON_RenderContent& child) if (nullptr == last_child) return false; - last_child->m_impl->m_next_sibling = &child; + last_child->_private->m_next_sibling = &child; } - child.m_impl->m_next_sibling = nullptr; - child.m_impl->m_parent = &m_render_content; + child._private->m_next_sibling = nullptr; + child._private->m_parent = &m_render_content; return true; } -void ON_RenderContent::CImpl::DeleteAllChildren(void) +void ON_RenderContentPrivate::DeleteAllChildren(void) { std::lock_guard lg(m_mutex); @@ -518,14 +524,14 @@ void ON_RenderContent::CImpl::DeleteAllChildren(void) while (nullptr != child_rc) { auto* delete_rc = child_rc; - child_rc = child_rc->m_impl->m_next_sibling; + child_rc = child_rc->_private->m_next_sibling; delete delete_rc; } m_first_child = nullptr; } -ON_RenderContent* ON_RenderContent::CImpl::FindLastChild(void) const +ON_RenderContent* ON_RenderContentPrivate::FindLastChild(void) const { ON_RenderContent* result = nullptr; @@ -533,40 +539,40 @@ ON_RenderContent* ON_RenderContent::CImpl::FindLastChild(void) const while (nullptr != candidate) { result = candidate; - candidate = candidate->m_impl->m_next_sibling; + candidate = candidate->_private->m_next_sibling; } return result; } -ON_RenderContent* ON_RenderContent::CImpl::FindPrevSibling(ON_RenderContent* child) const +ON_RenderContent* ON_RenderContentPrivate::FindPrevSibling(ON_RenderContent* child) const { if (child != m_first_child) { ON_RenderContent* candidate = m_first_child; while (nullptr != candidate) { - if (child == candidate->m_impl->m_next_sibling) + if (child == candidate->_private->m_next_sibling) return candidate; - candidate = candidate->m_impl->m_next_sibling; + candidate = candidate->_private->m_next_sibling; } } return nullptr; } -ON_RenderContent& ON_RenderContent::CImpl::TopLevel(void) +ON_RenderContent& ON_RenderContentPrivate::TopLevel(void) { if (nullptr != m_parent) { - return m_parent->m_impl->TopLevel(); + return m_parent->_private->TopLevel(); } return m_render_content; } -bool ON_RenderContent::CImpl::ChangeChild(ON_RenderContent* old_child, ON_RenderContent* new_child) +bool ON_RenderContentPrivate::ChangeChild(ON_RenderContent* old_child, ON_RenderContent* new_child) { if (nullptr == old_child) return false; @@ -579,7 +585,7 @@ bool ON_RenderContent::CImpl::ChangeChild(ON_RenderContent* old_child, ON_Render } else { - m_first_child = old_child->m_impl->m_next_sibling; + m_first_child = old_child->_private->m_next_sibling; } } else @@ -590,18 +596,18 @@ bool ON_RenderContent::CImpl::ChangeChild(ON_RenderContent* old_child, ON_Render if (nullptr != new_child) { - prev_sibling->m_impl->m_next_sibling = new_child; + prev_sibling->_private->m_next_sibling = new_child; } else { - prev_sibling->m_impl->m_next_sibling = old_child->m_impl->m_next_sibling; + prev_sibling->_private->m_next_sibling = old_child->_private->m_next_sibling; } } if (nullptr != new_child) { - new_child->m_impl->m_next_sibling = old_child->m_impl->m_next_sibling; - new_child->m_impl->m_parent = old_child->m_impl->m_parent; + new_child->_private->m_next_sibling = old_child->_private->m_next_sibling; + new_child->_private->m_parent = old_child->_private->m_parent; } delete old_child; @@ -609,7 +615,7 @@ bool ON_RenderContent::CImpl::ChangeChild(ON_RenderContent* old_child, ON_Render return true; } -ON_RenderContent* ON_RenderContent::CImpl::FindChild(const wchar_t* child_slot_name) const +ON_RenderContent* ON_RenderContentPrivate::FindChild(const wchar_t* child_slot_name) const { std::lock_guard lg(m_mutex); @@ -619,28 +625,28 @@ ON_RenderContent* ON_RenderContent::CImpl::FindChild(const wchar_t* child_slot_n if (child_rc->ChildSlotName() == child_slot_name) return child_rc; - child_rc = child_rc->m_impl->m_next_sibling; + child_rc = child_rc->_private->m_next_sibling; } return nullptr; } -bool ON_RenderContent::CImpl::SetChild(ON_RenderContent* child, const wchar_t* child_slot_name) +bool ON_RenderContentPrivate::SetChild(ON_RenderContent* child, const wchar_t* child_slot_name) { std::lock_guard lg(m_mutex); if (nullptr != child) { - if (nullptr != child->m_impl->m_model) + if (nullptr != child->_private->m_model) return false; - if (nullptr != child->m_impl->m_parent) + if (nullptr != child->_private->m_parent) return false; if ((nullptr == child_slot_name) || (0 == child_slot_name[0])) return false; - child->m_impl->SetPropertyValue(ON_RENDER_CONTENT_CHILD_SLOT_NAME, child_slot_name); + child->_private->SetPropertyValue(ON_RENDER_CONTENT_CHILD_SLOT_NAME, child_slot_name); } // Get any existing child with the same child slot name (may be null). @@ -663,20 +669,20 @@ bool ON_RenderContent::CImpl::SetChild(ON_RenderContent* child, const wchar_t* c if (nullptr != child) { - auto* pModel = TopLevel().m_impl->m_model; - child->m_impl->m_model = pModel; + auto* pModel = TopLevel()._private->m_model; + child->_private->m_model = pModel; } return true; } -void SetRenderContentNodeRecursive(const ON_RenderContent& rc, ON_XMLNode& node) +void ON_RenderContentPrivate::SetRenderContentNodeRecursive(const ON_RenderContent& rc, ON_XMLNode& node) // Static. { // Copy the component name to the XML instance name. - rc.m_impl->SetPropertyValue(ON_RENDER_CONTENT_INSTANCE_NAME, rc.Name()); + rc._private->SetPropertyValue(ON_RENDER_CONTENT_INSTANCE_NAME, rc.Name()); // Copy the component id to the XML instance id. - rc.m_impl->SetPropertyValue(ON_RENDER_CONTENT_INSTANCE_ID, rc.Id()); + rc._private->SetPropertyValue(ON_RENDER_CONTENT_INSTANCE_ID, rc.Id()); auto* child_node = new ON_XMLNode(rc.XMLNode()); node.AttachChildNode(child_node); @@ -689,30 +695,84 @@ void SetRenderContentNodeRecursive(const ON_RenderContent& rc, ON_XMLNode& node) } } -static void BuildXMLHierarchy(const ON_RenderContent& rc, ON_XMLNode& node) +void ON_RenderContentPrivate::BuildXMLHierarchy(const ON_RenderContent& rc, ON_XMLNode& node) // Static. { // Recursively builds 'node' from the tree structure of the XML nodes in 'rc' and its children. - node = rc.m_impl->m_node; + node = rc._private->m_node; - auto* child_rc = rc.m_impl->m_first_child; + auto* child_rc = rc._private->m_first_child; while (nullptr != child_rc) { auto* child_node = new ON_XMLNode(L""); BuildXMLHierarchy(*child_rc, *child_node); node.AttachChildNode(child_node); - child_rc = child_rc->m_impl->m_next_sibling; + child_rc = child_rc->_private->m_next_sibling; } } +ON_XMLNode* ON_RenderContentPrivate::NewXMLNodeRecursive(const ON_RenderContent& rc) // Static. +{ + ON_XMLNode* node = new ON_XMLNode(rc._private->m_node); + + ON_RenderContent* child_rc = rc._private->m_first_child; + while (nullptr != child_rc) + { + ON_XMLNode* child_node = NewXMLNodeRecursive(*child_rc); + if (nullptr != child_node) + { + node->AttachChildNode(child_node); + } + + child_rc = child_rc->_private->m_next_sibling; + } + + return node; +} + +void ON_RenderContentPrivate::SetModel(const ON_RenderContent& rc, ONX_Model& model) // Static. +{ + rc._private->m_model = &model; + + auto it = rc.GetChildIterator(); + ON_RenderContent* child_rc = nullptr; + while (nullptr != (child_rc = it.GetNextChild())) + { + SetModel(*child_rc, model); + } +} + +ON_RenderContent* ON_RenderContentPrivate::NewRenderContentFromNode(const ON_XMLNode& node) // Static. +{ + ON_RenderContent* rc = nullptr; + + const ON_wString& kind = node.TagName(); + + if (ON_KIND_MATERIAL == kind) + rc = new ON_RenderMaterial; + else + if (ON_KIND_ENVIRONMENT == kind) + rc = new ON_RenderEnvironment; + else + if (ON_KIND_TEXTURE == kind) + rc = new ON_RenderTexture; + + if (nullptr != rc) + { + rc->_private->SetXMLNode(node); + } + + return rc; +} + ON_VIRTUAL_OBJECT_IMPLEMENT(ON_RenderContent, ON_ModelComponent, "A98DEDDA-E4FA-4E1E-9BD3-2A0695C6D4E9"); ON_RenderContent::ON_RenderContent(const wchar_t* kind) : ON_ModelComponent(ON_ModelComponent::Type::RenderContent) { - m_impl = new (m_Impl) CImpl(*this, kind); + _private = new (_PRIVATE) ON_RenderContentPrivate(*this, kind); PRIVATE_CHECK(ON_RenderContentPrivate); // Set a unique instance id. ON_UUID uuid; @@ -720,24 +780,24 @@ ON_RenderContent::ON_RenderContent(const wchar_t* kind) SetId(uuid); // Set the plug-in id to the RDK plug-in id. - m_impl->InternalSetPropertyValue(ON_RENDER_CONTENT_PLUG_IN_ID, RdkPlugInId()); + _private->InternalSetPropertyValue(ON_RENDER_CONTENT_PLUG_IN_ID, RdkPlugInId()); // Set the render engine id to 'universal'. - m_impl->InternalSetPropertyValue(ON_RENDER_CONTENT_RENDER_ENGINE_ID, UniversalRenderEngineId()); + _private->InternalSetPropertyValue(ON_RENDER_CONTENT_RENDER_ENGINE_ID, UniversalRenderEngineId()); } ON_RenderContent::ON_RenderContent(const ON_RenderContent& rc) : ON_ModelComponent(ON_ModelComponent::Type::RenderContent, rc) { - m_impl = new (m_Impl) CImpl(*this, L""); + _private = new (_PRIVATE) ON_RenderContentPrivate(*this, L""); PRIVATE_CHECK(ON_RenderContentPrivate); operator = (rc); } ON_RenderContent::~ON_RenderContent() { - m_impl->~CImpl(); - m_impl = nullptr; + _private->~ON_RenderContentPrivate(); + _private = nullptr; } const ON_RenderContent& ON_RenderContent::operator = (const ON_RenderContent& rc) @@ -745,8 +805,8 @@ const ON_RenderContent& ON_RenderContent::operator = (const ON_RenderContent& rc if (this != &rc) { ON_XMLRootNode root; - BuildXMLHierarchy(rc, root); - m_impl->SetXMLNode(root); + ON_RenderContentPrivate::BuildXMLHierarchy(rc, root); + _private->SetXMLNode(root); } return *this; @@ -754,113 +814,113 @@ const ON_RenderContent& ON_RenderContent::operator = (const ON_RenderContent& rc ON_wString ON_RenderContent::TypeName(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_TYPE_NAME).AsString(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_TYPE_NAME).AsString(); } void ON_RenderContent::SetTypeName(const wchar_t* name) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_TYPE_NAME, name); + _private->SetPropertyValue(ON_RENDER_CONTENT_TYPE_NAME, name); } ON_wString ON_RenderContent::Notes(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_NOTES).AsString(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_NOTES).AsString(); } void ON_RenderContent::SetNotes(const wchar_t* notes) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_NOTES, notes); + _private->SetPropertyValue(ON_RENDER_CONTENT_NOTES, notes); } ON_wString ON_RenderContent::Tags(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_TAGS).AsString(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_TAGS).AsString(); } void ON_RenderContent::SetTags(const wchar_t* tags) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_TAGS, tags); + _private->SetPropertyValue(ON_RENDER_CONTENT_TAGS, tags); } ON_UUID ON_RenderContent::TypeId(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_TYPE_ID).AsUuid(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_TYPE_ID).AsUuid(); } void ON_RenderContent::SetTypeId(const ON_UUID& uuid) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_TYPE_ID, uuid); + _private->SetPropertyValue(ON_RENDER_CONTENT_TYPE_ID, uuid); } ON_UUID ON_RenderContent::RenderEngineId(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_RENDER_ENGINE_ID).AsUuid(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_RENDER_ENGINE_ID).AsUuid(); } void ON_RenderContent::SetRenderEngineId(const ON_UUID& uuid) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_RENDER_ENGINE_ID, uuid); + _private->SetPropertyValue(ON_RENDER_CONTENT_RENDER_ENGINE_ID, uuid); } ON_UUID ON_RenderContent::PlugInId(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_PLUG_IN_ID).AsUuid(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_PLUG_IN_ID).AsUuid(); } void ON_RenderContent::SetPlugInId(const ON_UUID& uuid) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_PLUG_IN_ID, uuid); + _private->SetPropertyValue(ON_RENDER_CONTENT_PLUG_IN_ID, uuid); } ON_UUID ON_RenderContent::GroupId(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_GROUP_ID).AsUuid(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_GROUP_ID).AsUuid(); } void ON_RenderContent::SetGroupId(const ON_UUID& group) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_GROUP_ID, group); + _private->SetPropertyValue(ON_RENDER_CONTENT_GROUP_ID, group); } bool ON_RenderContent::Hidden(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_HIDDEN).AsBool(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_HIDDEN).AsBool(); } void ON_RenderContent::SetHidden(bool hidden) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_HIDDEN, hidden); + _private->SetPropertyValue(ON_RENDER_CONTENT_HIDDEN, hidden); } bool ON_RenderContent::Reference(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_REFERENCE).AsBool(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_REFERENCE).AsBool(); } void ON_RenderContent::SetReference(bool ref) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_REFERENCE, ref); + _private->SetPropertyValue(ON_RENDER_CONTENT_REFERENCE, ref); } bool ON_RenderContent::AutoDelete(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_AUTO_DELETE).AsBool(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_AUTO_DELETE).AsBool(); } void ON_RenderContent::SetAutoDelete(bool autodel) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_AUTO_DELETE, autodel); + _private->SetPropertyValue(ON_RENDER_CONTENT_AUTO_DELETE, autodel); } ON_XMLVariant ON_RenderContent::GetParameter(const wchar_t* name) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); ON_XMLVariant value; value.SetNull(); // Try to get the new V8 parameter section. - const ON_XMLNode* node = m_impl->m_node.GetNamedChild(ON_RENDER_CONTENT_PARAMETERS_V8); + const ON_XMLNode* node = _private->m_node.GetNamedChild(ON_RENDER_CONTENT_PARAMETERS_V8); if (nullptr != node) { // Got it, so use the new ON_XMLParametersV8 to get the parameter's value. @@ -871,7 +931,7 @@ ON_XMLVariant ON_RenderContent::GetParameter(const wchar_t* name) const { // Either no V8 section was found or the parameter isn't there yet. // Try to get the legacy parameter section. This should not fail. - node = m_impl->m_node.GetNamedChild(ON_RENDER_CONTENT_PARAMETERS); + node = _private->m_node.GetNamedChild(ON_RENDER_CONTENT_PARAMETERS); if (nullptr != node) { // Got it, so use the legacy ON_XMLParameters to get the parameter's value. @@ -885,12 +945,12 @@ ON_XMLVariant ON_RenderContent::GetParameter(const wchar_t* name) const bool ON_RenderContent::SetParameter(const wchar_t* name, const ON_XMLVariant& value) { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); bool success = false; // Create / get the new V8 parameter section. - auto* node = m_impl->m_node.CreateNodeAtPath(ON_RENDER_CONTENT_PARAMETERS_V8); + auto* node = _private->m_node.CreateNodeAtPath(ON_RENDER_CONTENT_PARAMETERS_V8); if (nullptr != node) { // Use the new ON_XMLParametersV8 to write the parameter's value. @@ -900,7 +960,7 @@ bool ON_RenderContent::SetParameter(const wchar_t* name, const ON_XMLVariant& va } // Create / get the legacy parameter section. - node = m_impl->m_node.CreateNodeAtPath(ON_RENDER_CONTENT_PARAMETERS); + node = _private->m_node.CreateNodeAtPath(ON_RENDER_CONTENT_PARAMETERS); if (nullptr != node) { // Use the legacy ON_XMLParameters to write the parameter's value. @@ -919,52 +979,52 @@ ON_RenderContent::ChildIterator ON_RenderContent::GetChildIterator(void) const const ON_RenderContent* ON_RenderContent::Parent(void) const { - return m_impl->m_parent; + return _private->m_parent; } const ON_RenderContent* ON_RenderContent::FirstChild(void) const { - return m_impl->m_first_child; + return _private->m_first_child; } const ON_RenderContent* ON_RenderContent::NextSibling(void) const { - return m_impl->m_next_sibling; + return _private->m_next_sibling; } const ON_RenderContent& ON_RenderContent::TopLevel(void) const { - return m_impl->TopLevel(); + return _private->TopLevel(); } bool ON_RenderContent::IsTopLevel(void) const { - return nullptr == m_impl->m_parent; + return nullptr == _private->m_parent; } bool ON_RenderContent::IsChild(void) const { - return nullptr != m_impl->m_parent; + return nullptr != _private->m_parent; } bool ON_RenderContent::SetChild(const ON_RenderContent& child, const wchar_t* child_slot_name) { - return m_impl->SetChild(child.Duplicate(), child_slot_name); + return _private->SetChild(child.Duplicate(), child_slot_name); } bool ON_RenderContent::DeleteChild(const wchar_t* child_slot_name) { - return m_impl->SetChild(nullptr, child_slot_name); + return _private->SetChild(nullptr, child_slot_name); } ON_wString ON_RenderContent::ChildSlotName(void) const { - return m_impl->GetPropertyValue(ON_RENDER_CONTENT_CHILD_SLOT_NAME).AsString(); + return _private->GetPropertyValue(ON_RENDER_CONTENT_CHILD_SLOT_NAME).AsString(); } void ON_RenderContent::SetChildSlotName(const wchar_t* csn) { - m_impl->SetPropertyValue(ON_RENDER_CONTENT_CHILD_SLOT_NAME, csn); + _private->SetPropertyValue(ON_RENDER_CONTENT_CHILD_SLOT_NAME, csn); } bool ON_RenderContent::ChildSlotOn(const wchar_t* child_slot_name) const @@ -981,35 +1041,16 @@ bool ON_RenderContent::SetChildSlotOn(bool on, const wchar_t* child_slot_name) const ON_RenderContent* ON_RenderContent::FindChild(const wchar_t* child_slot_name) const { - return m_impl->FindChild(child_slot_name); -} - -static ON_XMLNode* NewXMLNodeRecursive(const ON_RenderContent& rc) -{ - ON_XMLNode* node = new ON_XMLNode(rc.m_impl->m_node); - - ON_RenderContent* child_rc = rc.m_impl->m_first_child; - while (nullptr != child_rc) - { - ON_XMLNode* child_node = NewXMLNodeRecursive(*child_rc); - if (nullptr != child_node) - { - node->AttachChildNode(child_node); - } - - child_rc = child_rc->m_impl->m_next_sibling; - } - - return node; + return _private->FindChild(child_slot_name); } ON_wString ON_RenderContent::XML(bool recursive) const { - ON_XMLNode* node = &m_impl->m_node; + ON_XMLNode* node = &_private->m_node; if (recursive) { - node = NewXMLNodeRecursive(*this); + node = ON_RenderContentPrivate::NewXMLNodeRecursive(*this); } const ON__UINT32 logical_count = node->WriteToStream(nullptr, 0); @@ -1031,19 +1072,19 @@ bool ON_RenderContent::SetXML(const wchar_t* xml) if (ON_XMLNode::ReadError == node.ReadFromStream(xml)) return false; - m_impl->SetXMLNode(node); + _private->SetXMLNode(node); return true; } const ON_XMLNode& ON_RenderContent::XMLNode(void) const { - return m_impl->m_node; + return _private->m_node; } ON_wString ON_RenderContent::Kind(void) const { - return m_impl->m_node.TagName(); + return _private->m_node.TagName(); } const ON_RenderContent* ON_RenderContent::FromModelComponentRef(const ON_ModelComponentReference& ref, @@ -1063,34 +1104,33 @@ void* ON_RenderContent::EVF(const wchar_t* func, void* data) // ON_RenderContent::ChildIterator -class ON_RenderContent::ChildIterator::CImpl final +class ON_RenderContentChildIteratorPrivate final { public: - ON_RenderContent* m_current = nullptr; + ON_RenderContent* _current = nullptr; }; ON_RenderContent::ChildIterator::ChildIterator(const ON_RenderContent* parent_rc) { - m_impl = new CImpl; + _private = new ON_RenderContentChildIteratorPrivate; if (nullptr != parent_rc) { - m_impl->m_current = parent_rc->m_impl->m_first_child; + _private->_current = parent_rc->_private->m_first_child; } } ON_RenderContent::ChildIterator::~ChildIterator() { - delete m_impl; - m_impl = nullptr; + delete _private; } ON_RenderContent* ON_RenderContent::ChildIterator::GetNextChild(void) { - ON_RenderContent* rc = m_impl->m_current; + ON_RenderContent* rc = _private->_current; if (nullptr != rc) { - m_impl->m_current = rc->m_impl->m_next_sibling; + _private->_current = rc->_private->m_next_sibling; } return rc; @@ -1103,37 +1143,17 @@ void* ON_RenderContent::ChildIterator::EVF(const wchar_t*, void*) void SetModel(const ON_RenderContent& rc, ONX_Model& model) { - rc.m_impl->m_model = &model; - - auto it = rc.GetChildIterator(); - ON_RenderContent* child_rc = nullptr; - while (nullptr != (child_rc = it.GetNextChild())) - { - SetModel(*child_rc, model); - } + ON_RenderContentPrivate::SetModel(rc, model); } ON_RenderContent* NewRenderContentFromNode(const ON_XMLNode& node) { - ON_RenderContent* rc = nullptr; + return ON_RenderContentPrivate::NewRenderContentFromNode(node); +} - const ON_wString& kind = node.TagName(); - - if (ON_KIND_MATERIAL == kind) - rc = new ON_RenderMaterial; - else - if (ON_KIND_ENVIRONMENT == kind) - rc = new ON_RenderEnvironment; - else - if (ON_KIND_TEXTURE == kind) - rc = new ON_RenderTexture; - - if (nullptr != rc) - { - rc->m_impl->SetXMLNode(node); - } - - return rc; +void SetRenderContentNodeRecursive(const ON_RenderContent& rc, ON_XMLNode& node) +{ + ON_RenderContentPrivate::SetRenderContentNodeRecursive(rc, node); } // ON_RenderMaterial @@ -1179,11 +1199,11 @@ ON_XMLVariant ParamHelper(const ON_XMLParameters& p, const wchar_t* name) ON_Material ON_RenderMaterial::ToOnMaterial(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); ON_Material mat; - const ON_XMLNode* sim_node = m_impl->XMLNode_Simulation(); + const ON_XMLNode* sim_node = _private->XMLNode_Simulation(); if (nullptr != sim_node) { ON_XMLParameters p(*sim_node); @@ -1324,11 +1344,11 @@ const ON_RenderEnvironment& ON_RenderEnvironment::operator = (const ON_RenderEnv ON_Environment ON_RenderEnvironment::ToOnEnvironment(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); ON_Environment env; - const ON_XMLNode* sim_node = m_impl->XMLNode_Simulation(); + const ON_XMLNode* sim_node = _private->XMLNode_Simulation(); if (nullptr != sim_node) { ON_XMLVariant v; @@ -1389,11 +1409,11 @@ const ON_RenderTexture& ON_RenderTexture::operator = (const ON_RenderTexture& te ON_Texture ON_RenderTexture::ToOnTexture(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); ON_Texture tex; - const ON_XMLNode* sim_node = m_impl->XMLNode_Simulation(); + const ON_XMLNode* sim_node = _private->XMLNode_Simulation(); if (nullptr != sim_node) { ON_XMLVariant v; @@ -1444,11 +1464,53 @@ ON_Texture ON_RenderTexture::ToOnTexture(void) const { tex.m_mapping_channel_id = v.AsInteger(); } + + if (p.GetParam(ON_TEXTURE_SIMULATION_TRANSPARENT_COLOR, v)) + { + tex.m_transparent_color = v.AsColor(); // ANDY CHECK -- IS THIS RIGHT? + } + } + + const auto* parent = Parent(); + if (nullptr != parent) + { + const ON_wString csn = ChildSlotName(); + tex.m_bOn = parent->ChildSlotOn(csn); + +// TODO: Discuss with Andy. +// tex.m_type ??? +// tex.m_mode ??? +// tex.m_bTreatAsLinear ??? +// tex.m_border_color ??? +// tex.m_transparency_texture_id ??? +// tex.m_bump_scale ??? +// tex.m_blend_A0 ??? +// tex.m_blend_A1 ??? +// tex.m_blend_A2 ??? +// tex.m_blend_A3 ??? +// tex.m_blend_RGB0 ??? +// tex.m_blend_RGB1 ??? +// tex.m_blend_RGB2 ??? +// tex.m_blend_RGB3 ??? +// tex.m_blend_order ??? +// tex.m_blend_constant_A ??? +// tex.m_blend_constant_RGB ??? +// tex.m_minfilter ??? +// tex.m_magfilter ??? } return tex; } +ON_wString ON_RenderTexture::Filename(void) const +{ + const ON_XMLVariant v = GetParameter(ON_RENDER_TEXTURE_FILENAME); + if (v.IsNull()) + return L""; + + return v.AsString(); +} + int ONX_Model::AddRenderMaterial(const wchar_t* mat_name) { static ON_UUID uuidPB = { 0x5a8d7b9b, 0xcdc9, 0x49de, { 0x8c, 0x16, 0x2e, 0xf6, 0x4f, 0xb0, 0x97, 0xab } }; diff --git a/opennurbs_render_content.h b/opennurbs_render_content.h index a146d09b..4f60ee25 100644 --- a/opennurbs_render_content.h +++ b/opennurbs_render_content.h @@ -147,7 +147,7 @@ public: class ON_CLASS ChildIterator { public: - ChildIterator(const ON_RenderContent* pParent); + ChildIterator(const ON_RenderContent* parent); virtual ~ChildIterator(); virtual ON_RenderContent* GetNextChild(void); @@ -157,8 +157,7 @@ public: virtual void* EVF(const wchar_t* func, void* data); private: - class CImpl; - CImpl* m_impl; + class ON_RenderContentChildIteratorPrivate* _private; }; // Returns: An iterator for iterating over the content's children. @@ -234,12 +233,13 @@ protected: // Emergency virtual function for future expansion. virtual void* EVF(const wchar_t* func, void* data); -public: - class CImpl; - CImpl* m_impl; - protected: - ON__UINT8 m_Impl[328]; + class ON_RenderContentPrivate* _private; + friend class ON_RenderContentPrivate; + friend class ON_RenderTexture; + +private: + ON__UINT8 _PRIVATE[360+64]; }; class ON_CLASS ON_RenderMaterial : public ON_RenderContent @@ -284,7 +284,11 @@ public: virtual const ON_RenderContent& operator = (const ON_RenderContent&) override; virtual const ON_RenderTexture& operator = (const ON_RenderTexture&); + // Get an ON_Texture from this render texture. virtual ON_Texture ToOnTexture(void) const; + + // If the texture has a file name, returns that file name. Otherwise returns an empty string. + virtual ON_wString Filename(void) const; }; #endif diff --git a/opennurbs_safe_frame.h b/opennurbs_safe_frame.h index 85999089..7bdcac41 100644 --- a/opennurbs_safe_frame.h +++ b/opennurbs_safe_frame.h @@ -106,8 +106,7 @@ public: // Emergency virtual function for future expansion. virtual void* EVF(const wchar_t* func, void* data); -private: // For internal use only. - friend class ON_3dmRenderSettingsPrivate; + // For internal use only. virtual void OnInternalXmlChanged(const ON_SafeFrame*); private: diff --git a/opennurbs_skylight.h b/opennurbs_skylight.h index 2e59428f..d94ff667 100644 --- a/opennurbs_skylight.h +++ b/opennurbs_skylight.h @@ -42,6 +42,9 @@ public: // Emergency virtual function for future expansion. virtual void* EVF(const wchar_t* func, void* data); + // For internal use only. + virtual void OnInternalXmlChanged(const ON_Skylight*); + public: // These methods are only here to support deprecated C# SDK methods. // Please use the equivalent methods in ON_3dmRenderSettings. /* DEPRECATED*/ bool EnvironmentOverride(void) const; @@ -49,10 +52,6 @@ public: // These methods are only here to support deprecated C# SDK methods. /* DEPRECATED*/ ON_UUID EnvironmentId(void) const; /* DEPRECATED*/ void SetEnvironmentId(const ON_UUID& id); -private: // For internal use only. - friend class ON_3dmRenderSettingsPrivate; - virtual void OnInternalXmlChanged(const ON_Skylight*); - private: class CImpl; CImpl* m_impl; diff --git a/opennurbs_subd.cpp b/opennurbs_subd.cpp index 90300c7c..df71b709 100644 --- a/opennurbs_subd.cpp +++ b/opennurbs_subd.cpp @@ -9428,10 +9428,10 @@ static const ON_SHA1_Hash Internal_FragmentColorsHash(const ON_SubDFace* first_f bool bAccumulateId = true; for (const ON_SubDMeshFragment* frag = first_frag; nullptr != frag; frag = frag->NextFaceFragment(false)) { - if (frag->ColorsExist()) + const unsigned count = frag->ColorArrayCount(ON_SubDComponentLocation::Surface); + if (count > 0) { const ON_Color* a = frag->ColorArray(ON_SubDComponentLocation::Surface); - const unsigned count = frag->ColorArrayCount(ON_SubDComponentLocation::Surface); if (nullptr != a && count > 0) { bNotEmpty = true; @@ -9460,10 +9460,10 @@ static const ON_SHA1_Hash Internal_FragmentCurvaturesHash(const ON_SubDFace* fir bool bAccumulateId = true; for (const ON_SubDMeshFragment* frag = first_frag; nullptr != frag; frag = frag->NextFaceFragment(false)) { - if (frag->CurvaturesExist()) + const unsigned count = frag->CurvatureArrayCount(ON_SubDComponentLocation::Surface); + if (count > 0) { const ON_SurfaceCurvature* a = frag->CurvatureArray(ON_SubDComponentLocation::Surface); - const unsigned count = frag->CurvatureArrayCount(ON_SubDComponentLocation::Surface); if (nullptr != a && count > 0) { bNotEmpty = true; @@ -25100,6 +25100,26 @@ unsigned int ON_SubDEdgeChain::SortEdgesIntoEdgeChains( return ON_SubDEdgeChain::SortEdgesIntoEdgeChains(a, minimum_chain_length, sorted_edges); } +unsigned int ON_SubDEdgeChain::SortEdgesIntoEdgeChains( + const ON_SimpleArray< const ON_SubDEdge* >& unsorted_edges, + unsigned int minimum_chain_length, + ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges +) +{ + // Dale Lear - June 20 2023 https://mcneel.myjetbrains.com/youtrack/issue/RH-75228 + // To avoid breaking the the 7.x SDK + // Call Mikko's modified version. https://mcneel.myjetbrains.com/youtrack/issue/RH-66258 + // It is extremely unlikely anybody outside of core McNeel devs ever called the original function. + const bool bIgnoreCorners = false; + return ON_SubDEdgeChain::SortEdgesIntoEdgeChains( + unsorted_edges, + minimum_chain_length, + sorted_edges, + bIgnoreCorners + ); +} + + unsigned int ON_SubDEdgeChain::SortEdgesIntoEdgeChains( const ON_SimpleArray< const ON_SubDEdge* >& unsorted_edges, unsigned int minimum_chain_length, @@ -25122,6 +25142,25 @@ unsigned int ON_SubDEdgeChain::SortEdgesIntoEdgeChains( return ON_SubDEdgeChain::SortEdgesIntoEdgeChains(unsorted_eptrs, minimum_chain_length, sorted_edges, bIgnoreCorners); } +unsigned int ON_SubDEdgeChain::SortEdgesIntoEdgeChains( + const ON_SimpleArray< ON_SubDEdgePtr >& unsorted_edges, + unsigned int minimum_chain_length, + ON_SimpleArray< ON_SubDEdgePtr >& sorted_edges +) +{ + // Dale Lear - June 20 2023 https://mcneel.myjetbrains.com/youtrack/issue/RH-75228 + // To avoid breaking the the 7.x SDK + // Call Mikko's modified version. https://mcneel.myjetbrains.com/youtrack/issue/RH-66258 + // It is extremely unlikely anybody outside of core McNeel devs ever called the original function. + const bool bIgnoreCorners = false; + return ON_SubDEdgeChain::SortEdgesIntoEdgeChains( + unsorted_edges, + minimum_chain_length, + sorted_edges, + bIgnoreCorners + ); +} + unsigned int ON_SubDEdgeChain::SortEdgesIntoEdgeChains( const ON_SimpleArray< ON_SubDEdgePtr >& unsorted_edges, unsigned int minimum_chain_length, diff --git a/opennurbs_subd.h b/opennurbs_subd.h index 5658cd2a..f374600e 100644 --- a/opennurbs_subd.h +++ b/opennurbs_subd.h @@ -304,6 +304,17 @@ enum class ON_SubDHashType : unsigned char }; #pragma endregion +ON_DECL +ON_SubDHashType ON_SubDHashTypeFromUnsigned( + unsigned int subd_hash_type_as_unsigned +); + +ON_DECL +const ON_wString ON_SubDHashTypeToString( + ON_SubDHashType subd_hash_type, + bool bVerbose +); + /// /// ON_SubDHash provides a simple way to save a SubD's vertex, edge, and face SHA1 hashes. /// Typically it is used when a calculation needs to know if the current SubD has is geometrically @@ -9832,6 +9843,27 @@ public: bool CopyFrom( const ON_SubDMeshFragment& src_fragment ); + + /// + /// Clear all information except the memory management inforation. + /// + /// The intent is to be able to clear and reuse the fragment at + /// its current vertex capacity. + /// + /// Secifically: + /// + /// Set referenced SubDFace to nullptr. + /// Set vertex count to zero. + /// Set existance of textures, curvatures, and colors to false. + /// Set control net quad values to nans. + /// Set the grid to ON_SubDMeshFragmentGrid::Empty. + /// Set the surface bounding box to nan. + /// + /// Does not change vertex capacity or deallocate managed arrays. + /// + void Clear() ON_NOEXCEPT; + + /* Parameters: src_fragment - [in] @@ -10275,8 +10307,12 @@ public: ON_3dPoint texture_coordinate ) const; - bool TextureCoordinatesExist() const; - void SetTextureCoordinatesExist(bool bTextureCoordinatesExist) const; + + void ClearTextureCoordinates() const; + + bool TextureCoordinatesExistForExperts() const; + + void SetTextureCoordinatesExistForExperts(bool bTextureCoordinatesExist) const; /* Parameters: @@ -10538,7 +10574,8 @@ public: /* Description: - Sets number of fragment vertices available (number of elements available in the m_P[], m_N[], and m_T[] arrays). + Sets number of fragment vertices available (number of elements available in the + m_P[], m_N[], m_T[], m_K[], and m_C[] arrays). The memory for the arrays is managed by something besides this ON_SubDMeshFragment instance. Parameters: vertex_capacity - [in] @@ -10546,12 +10583,13 @@ public: Returns: True if successful */ - bool SetUnmanagedVertexCapacity(size_t vertex_capacity); + bool SetUnmanagedVertexCapacityForExperts(size_t vertex_capacity); /* Description: - Sets number of fragment vertices available (number of elements available in the m_P[], m_N[], m_T[], and m_C[] arrays). + Sets number of fragment vertices available + (number of elements available in the m_P[], m_N[], m_T[], m_K[], and m_C[] arrays). The memory for the arrays is managed by something besides this ON_SubDMeshFragment instance. Parameters: vertex_capacity - [in] @@ -10563,31 +10601,33 @@ public: /* - Description: - Sets number of fragment vertices available (number of elements available in the m_P[], m_N[], m_T[], m_C[], and m_K[] arrays). - The memory for the arrays is managed by something besides this ON_SubDMeshFragment instance. - Parameters: - vertex_capacity - [in] - A value no larger than ON_SubDMeshFragment::MaximumVertexCount. Returns: - True if successful - */ - bool ReserveManagedVertexCapacity(size_t vertex_capacity, bool bWithCurvature); - - /* - Returns: - True if the memory in the m_P[], m_N[], and m_T[] is managed by this ON_SubDMeshFragment instance. + True if the memory in the m_P[], m_N[], m_T[], m_K[], and m_C[] arrays + is managed by this ON_SubDMeshFragment instance and can be deleted by + calling DeleteManagedArrays(). + False if an external agent is managing the memory. */ bool ManagedArrays() const; + + /* + True if the memory in the m_P[], m_N[], m_T[], m_K[], and m_C[] arrays + is managed by this ON_SubDMeshFragment instance, this function deletes + it and zeros the appropriate ponters and strides. + Otherwise nothing is done. + */ bool DeleteManagedArrays(); /* Returns: - True if the memory in the m_P[], m_N[], and m_T[] is managed by something besides this ON_SubDMeshFragment instance. + True if the memory in the m_P[], m_N[], m_T[], m_K[], and m_C[] arrays + is managed by something besides this ON_SubDMeshFragment instance. */ bool UnmanagedArrays() const; + // True if the memory for points, normals, textures, colors, and curvatures is interlaced. + bool InterlacedArrays() const; + private: friend class ON_SubDManagedMeshFragment; friend class ON_SubDMeshImpl; @@ -10597,102 +10637,48 @@ private: enum { /// - /// 3 double for the vertex point - /// 3 double for the vertex normal - /// 3 double for the vertex texture coordinate + /// 3 doubles for the vertex point + /// 3 doubles for the vertex normal + /// 3 doubles for the vertex texture coordinate + /// 2 doubles for the vertex principal curvatures (ON_SurfaceCurvature class) /// 1 double (4 bytes used for vertex color and 4 bytes currently not used) /// /// - /// This does not hold space for curvature information. - /// Interlaced managed arrays will not work with curvature. + /// This number must be even to permit both contiguous and interlaced + /// values for points, normals, textures, colors, and curvature. + /// The PNTCK array should must have a miniumum of + /// (ON_SubDMeshFragment::DoublesPerVertex * vertex_capacity * sizeof(double)) + /// bytes and begin on a double aligned address. /// - ManagedDoublesPerVertex = 10, - - /// - /// 3 double for the vertex point - /// 3 double for the vertex normal - /// 3 double for the vertex texture coordinate - /// 1 double (4 bytes used for vertex color and 4 bytes currently not used) - /// 2 doubles for the curvatures - /// - ManagedDoublesPerVertexWithCurvature = 12, - - /// - /// Number of doubles between successive 3d points in m_P[]/m_N[]/m_T[]. - /// When managed arrays are not interlaced, this value must be 3. - /// When managed arrays are interlaced, this value must be ManagedDoublesPerVertex(WithCurvature). - /// - Managed_3d_stride = 3, - - /// - /// Number of ON_Color elements between successive colors in m_C[]. - /// When managed arrays are not interlaced, this value must be 1 (or 2, see remarks). - /// When managed arrays are interlaced, this value must be - /// ManagedDoublesPerVertex(WithCurvature)*sizeof(double)/sizeof(ON_Color). - /// - /// - /// Setting this value to 1 for non-interlaced arrays means that - /// there will be a block of vertexCount ON_Color-sized values that are set, - /// then a block of vertexCount ON_Color-sized unset values. This allows - /// ManagedDoublesPerVertex(WithCurvature) to only count doubles, not doubles and floats. - /// The PNTC(K) array should always be of size ManagedDoublesPerVertex(WithCurvature) * vertexCount. - /// - Managed_color_stride = 1, - - /// - /// Number of ON_SurfaceCurvature elements between successive curvatures in m_K[]. - /// When managed arrays are not interlaced, this value must be 1. - /// When managed arrays are interlaced, this value must be - /// ManagedDoublesPerVertex(WithCurvature)*sizeof(double)/sizeof(ON_SurfaceCurvature). - /// - Managed_curvature_stride = 1, + DoublesPerVertex = 12 }; - static bool Internal_ManagedArraysAreInterlaced(); - static size_t Internal_Managed3dArrayOffset(size_t vertex_capacity); - static size_t Internal_ManagedColorArrayOffset(size_t vertex_capacity); - /* Parameters: - PNTC_array[] - [in] - An array of ManagedDoublesPerVertex*vertex_capacity doubles. - */ - void Internal_LayoutArrays( - bool bManagedArray, - double* PNTC_array, - size_t vertex_capacity - ); + bManagedArray - [in] + True if this instance of an ON_SubDMeshFragment will manage the PNTCK_array + and PNTCK_array = new(std::nothrow) double[ON_SubDMeshFragment::DoublesPerVertex * vertex capacity]. + Otherwise an external agent is responsible for managing the PNTCK_array memory. + vertex_capacity[] - [in] + Maximum number of vertices this fragment can hold. + Must be 0 or >= 4 and <= ON_SubDMeshFragment::MaximumVertexCount. + PNTKC_array[] - [in] + When PNTKC_array is not nullptr (typical), it is an array of + (ON_SubDMeshFragment::DoublesPerVertex * vertex_capacity * sizeof(double)) + bytes that begins on a double aligned address. When pNTKC_array is not nullptr, + Something besides this particular instance of ON_SubDMeshFragment is managing the PNTKC_array. + The array provides storage for the fragments m_P[], n_N[], m_T[], m_K[], and m_C[] + arrays. This approach is taken to provide efficient and fast memory managment of + large sets of fragments. - /* - Parameters: - PNTCK_array[] - [in] - An array of - (bWithCurvature ? ManagedDoublesPerVertexWithCurvature : ManagedDoublesPerVertex) - * vertex_capacity - doubles. + If PNTCK_array is nullptr, then it is allocated inside Internal_LayoutArrays() + and calling this->DeleteManagedArrays() will deallocate it. + This approach is used in odd situations, is uncommon, and the caller must + call this->DeleteManagedArrays() at an appropriate time. */ void Internal_LayoutArrays( - bool bManagedArray, - bool bWithCurvature, - double* PNTCK_array, - size_t vertex_capacity - ); - - /* - Parameters: - PNTC_array[] - [in] - K_array[] - [in] - Two arrays with total space for - (K_array == nullptr ? ManagedDoublesPerVertex : ManagedDoublesPerVertexWithCurvature) - * vertex_capacity - doubles. - They may point to diferent positions in the same array. - */ - void Internal_LayoutArrays( - bool bManagedArray, - double* PNTC_array, - ON_SurfaceCurvature* K_array, - size_t vertex_capacity + size_t vertex_capacity, + double* PNTKC_array ); enum : unsigned short @@ -10740,7 +10726,8 @@ private: /// This bit is on m_vertex_capacity_etc. /// Set means the memory for the m_P[], m_N[], m_T[], and m_C[] arrays is managed by this class as a single /// allocation. - /// m_P = new(std::nothrow) double[10*(point capacity)] and m_N, m_T, and m_C point into this allocation. + /// m_P = new(std::nothrow) double[ON_SubDMeshFragment::DoublesPerVertex * point capacity] and + /// m_N[], m_T[], m_C[], and m_K[] point into this allocation. /// EtcManagedArraysBit = 0x8000, }; @@ -10832,6 +10819,15 @@ public: const ON_2dPoint fragment_pack_rect_corners[4] ); + /* + Description: + Clears the pack rectangle. + Remarks: + Does not change the value of ON_SubDFace::PackId() or ON_SubDFace::TextureCoordinateType() + Use ON_SubDFace::ClearPackId() to clear the pack id. + */ + void ClearPackRect(); + /* Description: This functions sets the pack rect corners on fragments used to render @@ -11015,12 +11011,18 @@ public: ON_3dVector quad_normal ); + ON_DEPRECATED_MSG("Use ON_SubDMeshFragment::ClearControlNetQuad()") void UnsetControlNetQuad(); + void ClearControlNetQuad(); + const ON_BoundingBox SurfaceBoundingBox() const; const ON_BoundingBox ControlNetQuadBoundingBox() const; const ON_BoundingBox BoundingBox(ON_SubDComponentLocation subd_appearance) const; + void ClearSurfaceBoundingBox(); + + public: /* Returns: @@ -11196,6 +11198,139 @@ private: int corner_dim ) const; +private: + /////////////////////////////////////////////////////////////////////////////////// + // + // Principal curvatures + // + // If m_K is not nullptr and m_K_stride>0, then m_K[] can accommodate up to m_P_capacity + // principal curvatures (two doubles k1, k2). Otherwise there are no principal curvatures. + // At exceptional points, the curvature values may be nan. + // Never modify m_K_stride and the m_K pointer. + // Use m_grid functions to get principal curvature indices and quad face indices. + // + // NOTE WELL: + // m_K_stride is the number of ON_SurfaceCurvature elements between m_K[i] and m_K[i+1]. + // This is different than m_P_stride, m_N_stride, and m_T_stride, which count + // the number of doubles between successive + // points/normals/texture points in m_P[]/m_N[]/m_T[]. + // + // If m_K[] is interlaced, the number of bytes between successive elements of m_K[] must be a multiple of + // sizeof(ON_SurfaceCurvature) because m_K_stride is a ON_SurfaceCurvature element stride. + mutable ON_SurfaceCurvature* m_K; + mutable size_t m_K_stride; // stride for m_K[] as an array of 16 byte ON_SurfaceCurvature elements (so 0 or >= 1). + +public: + /* + Returns: + If the grid has set curvatures, then VertexCount() is returned. + Otherwise 0 is returned. + Remarks: + Use CurvatureCapacity() to get capacity of the m_K[] array (set or unset). + This function return the number of set curvatures. + */ + unsigned int CurvatureCount() const; + + /* + Returns: + If the grid has memory to store curvatures, then VertexCount() is returned. + Otherwise 0 is returned. + Remarks: + Use CurvaturesExist() or CurvatureCount() to determine if the curvature values are actually set. + */ + unsigned int CurvatureCapacity() const; + + const ON_SurfaceCurvature* CurvatureArray(ON_SubDComponentLocation subd_appearance)const; + unsigned CurvatureArrayCount(ON_SubDComponentLocation subd_appearance) const; + + /* + Call ClearCurvatures() if the fragment points are changed and any + existing curvature values are now invalid. + */ + void ClearCurvatures() const; + + /* + Description: + Computes curvature values at grid points for this fragment. + Note that fragment curvature values are a mutable property + and can be set at any time after the fragment's points are set. + Parameters: + bLazy - [in] + If bLazy is true and if CurvaturesExist() is true, then no changes are made. + If bLazy is false, the curvature values are unconditionally calculated from the + fragment's surface and saved in m_K[]. + Returns: + True if curvatures are set. + False if curvatures cannot be set. + */ + bool SetCurvatures(bool bLazy) const; + + /* + Returns: + True if the curvatures exist bit is set. This bit is used for + control net and vertex values. + Remarks: + Use CurvatureCount() to determine if vertices have set curvature values. + */ + bool CurvaturesExistForExperts() const; + + /* + Parameters: + bSetCurvaturesExist - [in] + True if curvatures exist. + False vertex curvatures do not exist or are no longer valid. + Note that SetCurvaturesExist(false) and ClearCurvatures() + are two ways to do the same thing. + Remarks: + When curvatures exist, CurvatureCount() = CurvatureCapacity(). + When curvatures do not exist, CurvatureCount() = 0. + Typically + */ + void SetCurvaturesExistForExperts(bool bSetCurvaturesExist) const; + + + /* + Description: + Computes normal curvature values for this fragment. Evaluation + points are uniformly spaced over the fragment to fill the N, Ku, Kv + arrays. + Parameters: + sample_count - [in] + How many samples to get in both directions. + comb_count_params - [in] + How many combs to get in both directions (+1 if get_first_comb is false). + get_first_comb - [in] + Wheter to skip combs at u = 0 and v = 0. The parameters at which to + get the combs are the same when: + - get_first_comb is true and comb_count is n + - get_first_comb is false and comb_count is n + getKu, getKv - [in] + Should the curvature be computed along u-isos, v-isos, or both. + P, Kuv - [out] + Arrays of size (getKu + getKv) * sample_count * comb_count_arrays where + Points and Curvatures along u-isos or along v-isos are stored. + Sample (i, j) in u direction, on u-dir comb j at sample i is stored + at index i + (j - get_first_comb ? 0 : 1) * sample_count. + Sample (i, j) in v direction, on v-dir comb i at sample j is stored + at index (getKu * sample_count * comb_count_arrays) + j + (i - get_first_comb ? 0 : 1) * sample_count. + Direction u (indexed with i) refers to the Fragment's grid 1st index + (from face->Vertex(0) to face->Vertex(1)). + Direction v (indexed with j) refers to the Fragment's grid 2nd index + (from face->Vertex(0) to face->Vertex(3)). + comb_count_arrays = comb_count_params - get_first_comb ? 1 : 0 + Returns: + Number of points sampled + */ + unsigned GetNormalCurvatures( + const unsigned sample_count, + const unsigned comb_count_params, + const bool get_first_comb, + const bool getKu, + const bool getKv, + ON_SimpleArray* P, + ON_SimpleArray* Kuv + ) const; + private: /////////////////////////////////////////////////////////////////////////////////// // @@ -11215,15 +11350,18 @@ private: // When m_C is not interlaced, m_C_stride is typically 1. If this is confusing, // please learn more about alignment and interlacing before working on this code. mutable ON_Color* m_C; - mutable size_t m_C_stride; // stride for m_C[] as an array of 4 bytes ON_Color elements (so 0 or >= 1). + mutable size_t m_C_stride; // stride for m_C[] as an array of 4 byte ON_Color elements (so 0 or >= 1). public: /* Returns: If grid vertex colors are available, then VertexCount() is returned. Otherwise 0 is returned. + Remarks: + Use ColorCapacity() to get the capacity of m_C[]. */ unsigned int ColorCount() const; + unsigned int ColorCapacity() const; const ON_Color* ColorArray(ON_SubDComponentLocation subd_appearance)const; @@ -11231,22 +11369,32 @@ public: unsigned ColorArrayCount(ON_SubDComponentLocation subd_appearance) const; /* - Returns: - True if vertex color values are set on this fragment. + Call ClearColors() if vertex colors do not exist or are no longer valid. */ - bool ColorsExist() const; + void ClearColors() const; + + /* + Returns: + True if vertex color exist bit is set. This bit is used + for control net and color array setting. + Remarks: + Use ColorCount() to determine if vertex colors are set. + */ + bool ColorsExistForExperts() const; /* Parameters: bSetColorsExist - [in] True if vertex colors exist. False vertex colors do not exist or are no longer valid. + SetColorsExist(false) and ClearColors() are two ways + to do the same thing. */ - void SetColorsExist(bool bSetColorsExist) const; + void SetColorsExistForExperts(bool bSetColorsExist) const; /* Description: - Set the vertex colors in m_C[] to color. + Set all vertex colors in m_C[] to color. Parameters: color - [in] */ @@ -11275,108 +11423,6 @@ public: ) )const; -private: - /////////////////////////////////////////////////////////////////////////////////// - // - // Principal curvatures - // - // If m_K is not nullptr and m_K_stride>0, then m_K[] can accommodate up to m_P_capacity - // principal curvatures (two doubles k1, k2). Otherwise there are no principal curvatures. - // At exceptional points, the curvature values may be nan. - // Never modify m_K_stride, m_K. - // Use m_grid functions to get principal curvature indices and quad face indices. - // - // m_K[] is rarely used and typically managed with ReserveManagedCurvatureCapacity() / DeleteManagedCurvatureCapacity(). - // NOTE WELL: - // If m_K[] is interlaced, the number of bytes between successive elements of m_K[] must be a multiple of 16 - // because sizeof(m_K) = 16 AND m_K_stride is the stride between elements of m_K[] - // This is different than m_P_stride, m_N_stride, and m_T_stride, which count the number of doubles between successive - // points/normals/texture points in m_P[]/m_N[]/m_T[]. - mutable ON_SurfaceCurvature* m_K; - mutable size_t m_K_stride; // stride for m_K[] as an array of 16 byte ON_SurfaceCurvature elements (so 0 or >= 1). - -public: - /* - Returns: - If grid vertex principal curvatures and sectional curvatures are available, then VertexCount() is returned. - Otherwise 0 is returned. - */ - unsigned int CurvatureCount() const; - unsigned int CurvatureCapacity() const; - - const ON_SurfaceCurvature* CurvatureArray(ON_SubDComponentLocation subd_appearance)const; - unsigned CurvatureArrayCount(ON_SubDComponentLocation subd_appearance) const; - - /* - Description: - Adds managed curvature capacity to store vertex curvatures. - */ - bool ReserveManagedCurvatureCapacity() const; - - /* - Description: - Deletes capacity added by ReserveManagedCurvatureCapacity(). - */ - void DeleteManagedCurvatureCapacity() const; - - - /* - Returns: - True if vertex curvature values are set on this fragment. - */ - bool CurvaturesExist() const; - - /* - Parameters: - bSetCurvaturesExist - [in] - True if vertex curvatures exist. - False vertex curvatures do not exist or are no longer valid. - */ - void SetCurvaturesExist(bool bSetCurvaturesExist) const; - - /* - Description: - Computes curvature values at grid points for this fragment. - */ - void SetCurvatures() const; - - /* - Description: - Computes normal curvature values for this fragment. Evaluation - points are uniformly spaced over the fragment to fill the N, Ku, Kv - arrays. - Parameters: - sample_count - [in] - How many samples to get in both directions. - comb_count_params - [in] - How many combs to get in both directions (+1 if get_first_comb is false). - get_first_comb - [in] - Wheter to skip combs at u = 0 and v = 0. The parameters at which to - get the combs are the same when: - - get_first_comb is true and comb_count is n - - get_first_comb is false and comb_count is n - getKu, getKv - [in] - Should the curvature be computed along u-isos, v-isos, or both. - P, Kuv - [out] - Arrays of size (getKu + getKv) * sample_count * comb_count_arrays where - Points and Curvatures along u-isos or along v-isos are stored. - Sample (i, j) in u direction, on u-dir comb j at sample i is stored - at index i + (j - get_first_comb ? 0 : 1) * sample_count. - Sample (i, j) in v direction, on v-dir comb i at sample j is stored - at index (getKu * sample_count * comb_count_arrays) + j + (i - get_first_comb ? 0 : 1) * sample_count. - Direction u (indexed with i) refers to the Fragment's grid 1st index - (from face->Vertex(0) to face->Vertex(1)). - Direction v (indexed with j) refers to the Fragment's grid 2nd index - (from face->Vertex(0) to face->Vertex(3)). - comb_count_arrays = comb_count_params - get_first_comb ? 1 : 0 - Returns: - Number of points sampled - */ - unsigned GetNormalCurvatures(const unsigned sample_count, - const unsigned comb_count_params, - const bool get_first_comb, const bool getKu, - const bool getKv, ON_SimpleArray* P, - ON_SimpleArray* Kuv) const; public: @@ -11398,18 +11444,19 @@ public: bCurvatureArray - [in] true to include room for the m_K[] array. Returns: - Amount of memory needed for the fragment, the m_P[], m_N[], m_T[], m_C[], - and optionally the m_K[] arrays. + Amount of memory needed for the fragment, the m_P[], m_N[], m_T[], m_C[], and m_K[] arrays. */ static size_t SizeofFragment( - unsigned int display_density, - bool bCurvatureArray + unsigned int display_density ); public: void Dump(ON_TextLog& text_log) const; }; +/// +/// ON_SubDManagedMeshFragment is a legacy class that should not be used. +/// class ON_CLASS ON_SubDManagedMeshFragment : public ON_SubDMeshFragment { public: @@ -11436,15 +11483,11 @@ public: unsigned int mesh_density ) ON_NOEXCEPT; - bool ReserveCapacity( - unsigned int mesh_density, - bool bWithCurvature - ) ON_NOEXCEPT; - private: void CopyHelper(const ON_SubDMeshFragment& src); - size_t m_storage_capacity = 0; - double* m_storage = nullptr; + + size_t m_obsolete1 = 0; + ON__UINT_PTR m_obsolete2 = 0; }; ////////////////////////////////////////////////////////////////////////// @@ -18775,7 +18818,14 @@ public: const ON_SimpleArray< ON_SubDEdgePtr >& unsorted_edges, unsigned int minimum_chain_length, ON_SimpleArray< ON_SubDEdgePtr >& edge_chains, - const bool bIgnoreCorners = false + const bool bIgnoreCorners + ); + + // 7.x SDK prservation - calls above with bIgnoreCorners = false + static unsigned int SortEdgesIntoEdgeChains( + const ON_SimpleArray< ON_SubDEdgePtr >& unsorted_edges, + unsigned int minimum_chain_length, + ON_SimpleArray< ON_SubDEdgePtr >& edge_chains ); /* @@ -18819,7 +18869,14 @@ public: const ON_SimpleArray< const ON_SubDEdge* >& unsorted_edges, unsigned int minimum_chain_length, ON_SimpleArray< ON_SubDEdgePtr >& edge_chains, - const bool bIgnoreCorners = false + const bool bIgnoreCorners + ); + + // 7.x SDK prservation - calls above with bIgnoreCorners = false + static unsigned int SortEdgesIntoEdgeChains( + const ON_SimpleArray< const ON_SubDEdge* >& unsorted_edges, + unsigned int minimum_chain_length, + ON_SimpleArray< ON_SubDEdgePtr >& edge_chains ); /* diff --git a/opennurbs_subd_fragment.cpp b/opennurbs_subd_fragment.cpp index 417a4d23..6585ceed 100644 --- a/opennurbs_subd_fragment.cpp +++ b/opennurbs_subd_fragment.cpp @@ -61,76 +61,26 @@ unsigned ON_SubDMeshFragment::VertexCapacity() const return (m_vertex_capacity_etc & ON_SubDMeshFragment::ValueMask); } -bool ON_SubDMeshFragment::Internal_ManagedArraysAreInterlaced() -{ - return ON_SubDMeshFragment::ManagedDoublesPerVertex == ON_SubDMeshFragment::Managed_3d_stride; -} - -size_t ON_SubDMeshFragment::Internal_Managed3dArrayOffset(size_t vertex_capacity) -{ - return (vertex_capacity > 0) - ? (3 * (ON_SubDMeshFragment::Internal_ManagedArraysAreInterlaced() ? 1 : vertex_capacity)) - : 0; -} - -size_t ON_SubDMeshFragment::Internal_ManagedColorArrayOffset(size_t vertex_capacity) -{ - return (vertex_capacity > 0) - // NB: 2 ON_Color floats in a double - ? (2 * (ON_SubDMeshFragment::Internal_ManagedArraysAreInterlaced() ? 1 : vertex_capacity)) - : 0; -} - void ON_SubDMeshFragment::Internal_LayoutArrays( - bool bManagedArray, - double* PNTC_array, - size_t vertex_capacity + size_t vertex_capacity, + double* PNTKC_array ) { - Internal_LayoutArrays(bManagedArray, false, PNTC_array, vertex_capacity); -} - -void ON_SubDMeshFragment::Internal_LayoutArrays( - bool bManagedArray, - bool bWithCurvature, - double* PNTCK_array, - size_t vertex_capacity -) -{ - - if (nullptr == PNTCK_array || vertex_capacity < 4 || vertex_capacity > ((size_t)ON_SubDMeshFragment::MaximumVertexCount) ) + const bool bManagedArray = (vertex_capacity >= 4 && nullptr == PNTKC_array); + if (bManagedArray) { - PNTCK_array = nullptr; - vertex_capacity = 0; - bManagedArray = false; - bWithCurvature = false; + const size_t double_capacity = ON_SubDMeshFragment::DoublesPerVertex * vertex_capacity; + // PNTKC_array will be deleted in ON_SubDMeshFragment::DeleteManagedArrays(). + PNTKC_array = new(std::nothrow) double[double_capacity]; } - const size_t offset_to_curvature = - 3 * ON_SubDMeshFragment::Internal_Managed3dArrayOffset(vertex_capacity) + - ON_SubDMeshFragment::Internal_ManagedColorArrayOffset(vertex_capacity) * - // NB: 2 ON_Color floats in a double - sizeof(ON_Color) / sizeof(double); - Internal_LayoutArrays( - bManagedArray, PNTCK_array, - bWithCurvature ? (ON_SurfaceCurvature*)(PNTCK_array + offset_to_curvature) - : nullptr, - vertex_capacity); -} -void ON_SubDMeshFragment::Internal_LayoutArrays( - bool bManagedArray, - double* PNTC_array, - ON_SurfaceCurvature* K_array, - size_t vertex_capacity -) -{ + this->SetVertexCount(0); - if (nullptr == PNTC_array || vertex_capacity < 4 || vertex_capacity > ((size_t)ON_SubDMeshFragment::MaximumVertexCount) ) + if (nullptr == PNTKC_array || vertex_capacity < 4 || vertex_capacity > ((size_t)ON_SubDMeshFragment::MaximumVertexCount) ) { - PNTC_array = nullptr; + PNTKC_array = nullptr; vertex_capacity = 0; - bManagedArray = false; } if (bManagedArray) { @@ -141,53 +91,78 @@ void ON_SubDMeshFragment::Internal_LayoutArrays( } else { - this->SetUnmanagedVertexCapacity(vertex_capacity); + this->SetUnmanagedVertexCapacityForExperts(vertex_capacity); } - const size_t offset_3d = (nullptr != PNTC_array) ? ON_SubDMeshFragment::Internal_Managed3dArrayOffset(vertex_capacity) : 0; - m_P = PNTC_array; - m_P_stride = ON_SubDMeshFragment::Managed_3d_stride; - m_N = m_P + offset_3d; - m_N_stride = ON_SubDMeshFragment::Managed_3d_stride; - m_T = m_N + offset_3d; - m_T_stride = ON_SubDMeshFragment::Managed_3d_stride; - m_C = (ON_Color*)(m_T + offset_3d); - m_C_stride = ON_SubDMeshFragment::Managed_color_stride; - if (nullptr != K_array) { - m_K = K_array; - m_K_stride = ON_SubDMeshFragment::Managed_curvature_stride; - } + // If needed, bInterlaced can become a parameter in this private function. + // bInterlaced - [in] + // True if the points, normals, textures, colors, and curvatures should be interlaced. + // False if the points, normals, textures, colors, and curvatures should be in + // contiguous memory. + const bool bInterlaced = false; + + // stride_PNT = number of double elements to get from m_P[i] to m_P[i+1] (dittof for m_N[] and m_T[]) + const size_t stride_PNT + = (nullptr != PNTKC_array) + ? (bInterlaced ? ON_SubDMeshFragment::DoublesPerVertex : 3) + : 0; + + // offset_PNT = offset between start of m_P, m_N, m_T, m_K + const size_t offset_PNT + = (nullptr != PNTKC_array) + ? 3 * (bInterlaced ? 1 : vertex_capacity) + : 0; + + // stride_K = number of ON_SubDSurfaceCurvature elements to get from m_K[i] to m_K[i+1] + const size_t stride_K + = (nullptr != PNTKC_array) + ? (bInterlaced ? (ON_SubDMeshFragment::DoublesPerVertex * sizeof(double)) / sizeof(m_K[0]) : 1) + : 0; + + // offset_K = offset bewteen m_K and m_C + const size_t offset_K + = (nullptr != PNTKC_array) + ? (bInterlaced ? 1 : vertex_capacity) + : 0; + + // stride_C = number of ON_Color elements to get from m_C[i] to m_C[i+1] + const size_t stride_C + = (nullptr != PNTKC_array) + ? (bInterlaced ? (ON_SubDMeshFragment::DoublesPerVertex * sizeof(double)) / sizeof(m_C[0]) : 1) + : 0; + + m_P = PNTKC_array; + m_P_stride = stride_PNT; + + m_N = m_P + offset_PNT; + m_N_stride = stride_PNT; + + m_T = m_N + offset_PNT; + m_T_stride = stride_PNT; + + m_K = (ON_SurfaceCurvature*)(m_T + offset_PNT); + m_K_stride = stride_K; + + m_C = (ON_Color*)(m_K + offset_K); + m_C_stride = stride_C; } bool ON_SubDMeshFragment::ManagedArrays() const { const size_t vertex_capacity = (ON_SubDMeshFragment::ValueMask & m_vertex_capacity_etc); - const size_t offset_3d = ON_SubDMeshFragment::Internal_Managed3dArrayOffset(vertex_capacity); - const size_t offset_color = ON_SubDMeshFragment::Internal_ManagedColorArrayOffset(vertex_capacity); return ( 0 != (ON_SubDMeshFragment::EtcManagedArraysBit & m_vertex_capacity_etc) && vertex_capacity > 0 - && ON_SubDMeshFragment::Managed_3d_stride == m_P_stride - && ON_SubDMeshFragment::Managed_3d_stride == m_N_stride - && ON_SubDMeshFragment::Managed_3d_stride == m_T_stride - && ON_SubDMeshFragment::Managed_color_stride == m_C_stride && nullptr != m_P - && m_N == m_P + offset_3d - && m_T == m_N + offset_3d - && m_C == (const ON_Color*)(m_T + offset_3d) - && ( - m_K == nullptr ? - m_K_stride == 0 : ( - m_K_stride == ON_SubDMeshFragment::Managed_curvature_stride - && m_K == (const ON_SurfaceCurvature*)(m_C + offset_color) - ) - ) - ) ? true : false; + && (ON__UINT_PTR)m_N > (ON__UINT_PTR)m_P + && (ON__UINT_PTR)m_T > (ON__UINT_PTR)m_N + && (ON__UINT_PTR)m_K > (ON__UINT_PTR)m_T + && (ON__UINT_PTR)m_C > (ON__UINT_PTR)m_K + ) ? true : false; } bool ON_SubDMeshFragment::DeleteManagedArrays() { - DeleteManagedCurvatureCapacity(); if (ManagedArrays()) { double* managed_array = m_P; @@ -197,12 +172,12 @@ bool ON_SubDMeshFragment::DeleteManagedArrays() m_N = nullptr; m_T = nullptr; m_C = nullptr; - // m_K = nullptr; // Deleted in DeleteManagedCurvatureCapacity() + m_K = nullptr; m_P_stride = 0; m_N_stride = 0; m_T_stride = 0; m_C_stride = 0; - // m_K_stride = 0; // Deleted in DeleteManagedCurvatureCapacity() + m_K_stride = 0; if (nullptr != managed_array) { // Allocated in ON_SubDMeshFragment::ReserveManagedVertexCapacity() @@ -215,14 +190,18 @@ bool ON_SubDMeshFragment::DeleteManagedArrays() bool ON_SubDMeshFragment::UnmanagedArrays() const { - return - (0 == (ON_SubDMeshFragment::EtcManagedArraysBit & m_vertex_capacity_etc) && 0 != (m_vertex_capacity_etc & ON_SubDMeshFragment::ValueMask) ) - ? true - : false; + const size_t vertex_capacity = (ON_SubDMeshFragment::ValueMask & m_vertex_capacity_etc); + return ( + 0 == (ON_SubDMeshFragment::EtcManagedArraysBit & m_vertex_capacity_etc) + && vertex_capacity > 0 + && nullptr != m_P + ) ? true : false; } -bool ON_SubDMeshFragment::SetUnmanagedVertexCapacity(size_t vertex_capacity) +bool ON_SubDMeshFragment::SetUnmanagedVertexCapacityForExperts(size_t vertex_capacity) { + // Do not check for a non-null m_P. + // This function is used in expert situations when m_P is null. if (vertex_capacity < 0 || vertex_capacity > (size_t)ON_SubDMeshFragment::MaximumVertexCount) return ON_SUBD_RETURN_ERROR(false); if (ManagedArrays()) @@ -237,11 +216,6 @@ bool ON_SubDMeshFragment::SetUnmanagedVertexCapacity(size_t vertex_capacity) } bool ON_SubDMeshFragment::ReserveManagedVertexCapacity(size_t vertex_capacity) -{ - return ReserveManagedVertexCapacity(vertex_capacity, false); -} - -bool ON_SubDMeshFragment::ReserveManagedVertexCapacity(size_t vertex_capacity, bool bWithCurvature) { if (vertex_capacity < 0 || vertex_capacity >(size_t)ON_SubDMeshFragment::MaximumVertexCount) return ON_SUBD_RETURN_ERROR(false); @@ -260,62 +234,10 @@ bool ON_SubDMeshFragment::ReserveManagedVertexCapacity(size_t vertex_capacity, b DeleteManagedArrays(); } - const size_t capacity = - (bWithCurvature - ? ON_SubDMeshFragment::ManagedDoublesPerVertexWithCurvature - : ON_SubDMeshFragment::ManagedDoublesPerVertex) * - vertex_capacity; - // p will be deleted in ON_SubDMeshFragment::DeleteManagedArrays(). - double* managed_doubles = new(std::nothrow) double[capacity]; - Internal_LayoutArrays(true, bWithCurvature, managed_doubles, vertex_capacity); + Internal_LayoutArrays( vertex_capacity, nullptr ); return (this->VertexCapacity() >= vertex_capacity); } -bool ON_SubDMeshFragment::ReserveManagedCurvatureCapacity() const -{ - if (UnmanagedArrays()) - { - // attempting to convert externally managed memory to internally managed memory. - return ON_SUBD_RETURN_ERROR(false); - } - const size_t current_capacity = (size_t)(ON_SubDMeshFragment::ValueMask & m_vertex_capacity_etc); - if (nullptr == m_K && current_capacity > 0) - { - m_K = new(std::nothrow) ON_SurfaceCurvature[current_capacity]; - m_vertex_capacity_etc &= ~ON_SubDMeshFragment::EtcCurvaturesExistBit; // m_K[] content is unset. - m_K_stride = ON_SubDMeshFragment::Managed_curvature_stride; - } - return (nullptr != m_K && current_capacity > 0); -} - - -void ON_SubDMeshFragment::DeleteManagedCurvatureCapacity() const -{ - if (UnmanagedArrays()) - { - // attempting to convert externally managed memory to internally managed memory. - return ON_SubDIncrementErrorCount(); - } - if (nullptr != m_K) - { - if (ManagedArrays()) { - // m_K was allocated as part of the PNTCK array, it's not safe to delete it here - memset(m_K, 0, - m_K_stride * (size_t)(ON_SubDMeshFragment::ValueMask & - m_vertex_capacity_etc)); - m_vertex_capacity_etc &= - ~ON_SubDMeshFragment::EtcCurvaturesExistBit; // m_K[] content is - // unset. - return; - } - // TODO: Should we ever get here? - delete[] m_K; - m_K = nullptr; - m_vertex_capacity_etc &= ~ON_SubDMeshFragment::EtcCurvaturesExistBit; // m_K[] content is unset. - m_K_stride = 0; - } -} - unsigned ON_SubDMeshFragment::VertexCount() const { return (m_vertex_count_etc & ON_SubDMeshFragment::ValueMask); @@ -323,52 +245,90 @@ unsigned ON_SubDMeshFragment::VertexCount() const bool ON_SubDMeshFragment::SetVertexCount(size_t vertex_count) { - if (vertex_count < 0 || vertex_count > VertexCapacity()) - return ON_SUBD_RETURN_ERROR(false); - const unsigned short etc = m_vertex_count_etc & ON_SubDMeshFragment::EtcMask; - m_vertex_count_etc = ((unsigned short)vertex_count) | etc; + if (0 == vertex_count) + { + Clear(); + } + else + { + // Do not check for non-null m_P. This function is called in situation where m_P is nullptr. + if (vertex_count < 0 || vertex_count > VertexCapacity()) + return ON_SUBD_RETURN_ERROR(false); + const unsigned short etc = m_vertex_count_etc & ON_SubDMeshFragment::EtcMask; + m_vertex_count_etc = ((unsigned short)vertex_count) | etc; + } + return true; } + +void ON_SubDMeshFragment::Clear() ON_NOEXCEPT +{ + m_face = nullptr; + m_face_vertex_index[0] = 0; + m_face_vertex_index[1] = 0; + m_face_vertex_index[2] = 0; + m_face_vertex_index[3] = 0; + + m_face_fragment_count = 0; + m_face_fragment_index = 0; + + // This line sets vertex count = 0 + m_vertex_count_etc &= ON_SubDMeshFragment::EtcMask; + + // Do NOT change vertex capacity. + // Do NOT delete managed arrays. + // The point is to be able to clear and reuse a fragment. + + ClearTextureCoordinates(); + ClearCurvatures(); + ClearColors(); + ClearControlNetQuad(); + ClearPackRect(); + m_grid = ON_SubDMeshFragmentGrid::Empty; + m_surface_bbox = ON_BoundingBox::NanBoundingBox; +} + + unsigned int ON_SubDMeshFragment::PointCount() const { - return (nullptr != m_P && m_P_stride >= ON_SubDMeshFragment::Managed_3d_stride) ? VertexCount() : 0U; + return (nullptr != m_P && m_P_stride >= 3) ? VertexCount() : 0U; } unsigned int ON_SubDMeshFragment::NormalCount() const { - return (nullptr != m_N && m_N_stride >= ON_SubDMeshFragment::Managed_3d_stride) ? VertexCount() : 0U; + return (nullptr != m_N && m_N_stride >= 3) ? VertexCount() : 0U; } unsigned int ON_SubDMeshFragment::CurvatureCount() const { - return (nullptr != m_K && m_K_stride >= ON_SubDMeshFragment::Managed_curvature_stride) ? VertexCount() : 0U; + return (CurvaturesExistForExperts() && nullptr != m_K && m_K_stride >= 1) ? VertexCount() : 0U; } unsigned int ON_SubDMeshFragment::ColorCount() const { - return (nullptr != m_C && m_C_stride >= ON_SubDMeshFragment::Managed_color_stride) ? VertexCount() : 0U; + return (ColorsExistForExperts() && nullptr != m_C && m_C_stride >= 1) ? VertexCount() : 0U; } unsigned int ON_SubDMeshFragment::PointCapacity() const { - return (nullptr != m_P && m_P_stride >= ON_SubDMeshFragment::Managed_3d_stride) ? VertexCapacity() : 0U; + return (nullptr != m_P && m_P_stride >= 3) ? VertexCapacity() : 0U; } unsigned int ON_SubDMeshFragment::NormalCapacity() const { - return (nullptr != m_N && m_N_stride >= ON_SubDMeshFragment::Managed_3d_stride) ? VertexCapacity() : 0U; + return (nullptr != m_N && m_N_stride >= 3) ? VertexCapacity() : 0U; } unsigned int ON_SubDMeshFragment::CurvatureCapacity() const { - return (nullptr != m_K && m_K_stride >= ON_SubDMeshFragment::Managed_curvature_stride) ? VertexCapacity() : 0U; + return (nullptr != m_K && m_K_stride >= 1) ? VertexCapacity() : 0U; } unsigned int ON_SubDMeshFragment::ColorCapacity() const { - return (nullptr != m_C && m_C_stride >= ON_SubDMeshFragment::Managed_color_stride) ? VertexCapacity() : 0U; + return (nullptr != m_C && m_C_stride >= 1) ? VertexCapacity() : 0U; } const double* ON_SubDMeshFragment::PointArray(ON_SubDComponentLocation subd_appearance)const @@ -408,6 +368,9 @@ const ON_SurfaceCurvature* ON_SubDMeshFragment::CurvatureArray(ON_SubDComponentL unsigned ON_SubDMeshFragment::CurvatureArrayCount(ON_SubDComponentLocation subd_appearance) const { + if (false == CurvaturesExistForExperts()) + return 0U; + return (ON_SubDComponentLocation::ControlNet == subd_appearance) ? 4U : CurvatureCount(); } @@ -423,63 +386,83 @@ size_t ON_SubDMeshFragment::ColorArrayStride(ON_SubDComponentLocation subd_appea unsigned ON_SubDMeshFragment::ColorArrayCount(ON_SubDComponentLocation subd_appearance) const { + if (false == ColorsExistForExperts()) + return 0U; return (ON_SubDComponentLocation::ControlNet == subd_appearance) ? 4U : ColorCount(); } -bool ON_SubDMeshFragment::ColorsExist() const +bool ON_SubDMeshFragment::ColorsExistForExperts() const { - return (nullptr != m_C && m_C_stride > 0 && 0 != (m_vertex_capacity_etc & ON_SubDMeshFragment::EtcColorsExistBit)); + return (0 != (m_vertex_capacity_etc & ON_SubDMeshFragment::EtcColorsExistBit)); } -void ON_SubDMeshFragment::SetColorsExist(bool bColorsExist) const +void ON_SubDMeshFragment::ClearColors() const +{ + m_vertex_capacity_etc &= ~ON_SubDMeshFragment::EtcColorsExistBit; + this->m_ctrlnetC[0] = ON_Color::UnsetColor; + this->m_ctrlnetC[1] = ON_Color::UnsetColor; + this->m_ctrlnetC[2] = ON_Color::UnsetColor; + this->m_ctrlnetC[3] = ON_Color::UnsetColor; +} + +void ON_SubDMeshFragment::SetColorsExistForExperts(bool bColorsExist) const { if (bColorsExist) m_vertex_capacity_etc |= ON_SubDMeshFragment::EtcColorsExistBit; else - m_vertex_capacity_etc &= ~ON_SubDMeshFragment::EtcColorsExistBit; + this->ClearColors(); } -bool ON_SubDMeshFragment::CurvaturesExist() const +bool ON_SubDMeshFragment::CurvaturesExistForExperts() const { - return (nullptr != m_K && 0 != (m_vertex_capacity_etc & ON_SubDMeshFragment::EtcCurvaturesExistBit)); + return (0 != (m_vertex_capacity_etc & ON_SubDMeshFragment::EtcCurvaturesExistBit)); } -void ON_SubDMeshFragment::SetCurvaturesExist(bool bSetCurvaturesExist) const +void ON_SubDMeshFragment::ClearCurvatures() const +{ + m_vertex_capacity_etc &= ~ON_SubDMeshFragment::EtcCurvaturesExistBit; + this->m_ctrlnetK[0] = ON_SurfaceCurvature::Nan; + this->m_ctrlnetK[1] = ON_SurfaceCurvature::Nan; + this->m_ctrlnetK[2] = ON_SurfaceCurvature::Nan; + this->m_ctrlnetK[3] = ON_SurfaceCurvature::Nan; +} + +void ON_SubDMeshFragment::SetCurvaturesExistForExperts(bool bSetCurvaturesExist) const { if (bSetCurvaturesExist) m_vertex_capacity_etc |= ON_SubDMeshFragment::EtcCurvaturesExistBit; else - m_vertex_capacity_etc &= ~ON_SubDMeshFragment::EtcCurvaturesExistBit; + ClearCurvatures(); } bool ON_SubDMeshFragment::SetColors(ON_Color color) const { - bool bColorsExist = false; - for (;;) + if (ON_Color::UnsetColor == color) + { + ClearColors(); + } + else { m_ctrlnetC[0] = color; m_ctrlnetC[1] = color; m_ctrlnetC[2] = color; m_ctrlnetC[3] = color; - const ON_SubDComponentLocation subd_appearance = ON_SubDComponentLocation::Surface; - const unsigned count = PointArrayCount(subd_appearance); - if (count <= 0) - break; - if (count != ColorArrayCount(subd_appearance)) - break; - - ON_Color* C = const_cast(ColorArray(subd_appearance)); - if (nullptr == C) - break; - - bColorsExist = (ON_Color::UnsetColor != color); - for (const ON_Color* C1 = C + count; C < C1; ++C) - *C = color; - break; + const size_t capacity = ColorCapacity(); + if (capacity > 0) + { + const size_t stride = m_C_stride; + ON_Color* c = m_C; + ON_Color* c1 = c + capacity * stride; + while (c < c1) + { + *c = color; + c += stride; + } + } + this->SetColorsExistForExperts(true); } - SetColorsExist(bColorsExist); - return ColorsExist(); + return ColorsExistForExperts(); } bool ON_SubDMeshFragment::SetColorsFromCallback( @@ -498,14 +481,9 @@ bool ON_SubDMeshFragment::SetColorsFromCallback( ) ) const { - bool bColorsExist = false; + ClearColors(); for (;;) { - m_ctrlnetC[0] = ON_Color::UnsetColor; - m_ctrlnetC[1] = ON_Color::UnsetColor; - m_ctrlnetC[2] = ON_Color::UnsetColor; - m_ctrlnetC[3] = ON_Color::UnsetColor; - if (nullptr == color_callback) { // removing vertex colors. @@ -513,6 +491,7 @@ bool ON_SubDMeshFragment::SetColorsFromCallback( } const ON_SubDComponentLocation subd_appearance = ON_SubDComponentLocation::Surface; + const unsigned count = PointArrayCount(subd_appearance); if (count <= 0) break; @@ -525,6 +504,7 @@ bool ON_SubDMeshFragment::SetColorsFromCallback( break; ON_Color* C = const_cast(ColorArray(subd_appearance)); + const size_t Cstride = ColorArrayStride(subd_appearance); if (nullptr == C) break; @@ -545,8 +525,9 @@ bool ON_SubDMeshFragment::SetColorsFromCallback( if (nullptr == K) K = &ON_SurfaceCurvature::Nan; + bool bColorsExist = false; const ON_SubDComponentPtr cptr = ON_SubDComponentPtr::Create(m_face); - for (const double* P1 = P + Pstride * count; P < P1; P += Pstride, ++C) + for (const double* P1 = P + Pstride * count; P < P1; P += Pstride, C += Cstride) { // Never give the callback access to fragment array pointers. const ON_3dPoint callbackP(P); @@ -561,19 +542,21 @@ bool ON_SubDMeshFragment::SetColorsFromCallback( T += Tstride; K += Kstride; } - break; - } - - SetColorsExist(bColorsExist); - if (bColorsExist) - { - m_ctrlnetC[0] = CornerColor(0); - m_ctrlnetC[1] = CornerColor(1); - m_ctrlnetC[2] = CornerColor(2); - m_ctrlnetC[3] = CornerColor(3); - } - return ColorsExist(); + if (bColorsExist) + { + m_ctrlnetC[0] = CornerColor(0); + m_ctrlnetC[1] = CornerColor(1); + m_ctrlnetC[2] = CornerColor(2); + m_ctrlnetC[3] = CornerColor(3); + } + + SetColorsExistForExperts(bColorsExist); + + break; + } + + return ColorsExistForExperts(); } bool ON_SubD::SetFragmentColorsFromCallback( @@ -786,15 +769,24 @@ void ON_SubDMeshFragment::SetControlNetQuad(bool bGridOrder, const ON_3dPoint qu } else { - UnsetControlNetQuad(); + ClearControlNetQuad(); } } + void ON_SubDMeshFragment::UnsetControlNetQuad() +{ + this->ClearControlNetQuad(); +} + +void ON_SubDMeshFragment::ClearControlNetQuad() { for (int i = 0; i < 4; ++i) { m_ctrlnetP[i][0] = m_ctrlnetP[i][1] = m_ctrlnetP[i][2] = ON_DBL_QNAN; + m_ctrlnetT[i][0] = m_ctrlnetT[i][1] = m_ctrlnetT[i][2] = ON_DBL_QNAN; + m_ctrlnetK[i] = ON_SurfaceCurvature::Nan; + m_ctrlnetC[i] = ON_UNSET_COLOR; } m_ctrlnetN[0] = m_ctrlnetN[1] = m_ctrlnetN[2] = ON_DBL_QNAN; m_vertex_count_etc &= ~ON_SubDMeshFragment::EtcControlNetQuadBit; @@ -805,6 +797,11 @@ const ON_BoundingBox ON_SubDMeshFragment::SurfaceBoundingBox() const return m_surface_bbox; } +void ON_SubDMeshFragment::ClearSurfaceBoundingBox() +{ + m_surface_bbox = ON_BoundingBox::NanBoundingBox; +} + const ON_BoundingBox ON_SubDMeshFragment::ControlNetQuadBoundingBox() const { ON_3dPoint P[4]; @@ -909,8 +906,6 @@ ON_SubDManagedMeshFragment& ON_SubDManagedMeshFragment::operator=(const ON_SubDM ON_SubDManagedMeshFragment::ON_SubDManagedMeshFragment( ON_SubDManagedMeshFragment&& src ) ON_NOEXCEPT { memcpy(this, &src, sizeof(*this)); - src.m_storage = nullptr; - src.m_storage_capacity = 0; } // rvalue assignment operator @@ -920,8 +915,6 @@ ON_SubDManagedMeshFragment& ON_SubDManagedMeshFragment::operator=( ON_SubDManage { Destroy(); memcpy(this, &src, sizeof(*this)); - src.m_storage = nullptr; - src.m_storage_capacity = 0; } return *this; } @@ -931,71 +924,27 @@ ON_SubDManagedMeshFragment& ON_SubDManagedMeshFragment::operator=( ON_SubDManage bool ON_SubDManagedMeshFragment::ReserveCapacity( unsigned int display_density ) ON_NOEXCEPT -{ - return ReserveCapacity(display_density, false); -} - -bool ON_SubDManagedMeshFragment::ReserveCapacity( - unsigned int display_density, - bool bWithCurvature -) ON_NOEXCEPT { Clear(); - if ( display_density > 8) + if ( display_density > ON_SubDDisplayParameters::MaximumDensity) return ON_SUBD_RETURN_ERROR(false); - unsigned int fragment_side_count = ON_SubDManagedMeshFragment::SideSegmentCountFromDisplayDensity(display_density); - if ( 0 == fragment_side_count ) - return true; - // Sanity check - if ( fragment_side_count > 0xFFU ) - return ON_SUBD_RETURN_ERROR(false); - - const unsigned int short_capacity_sanity_check = 0xFFFFU; - - const unsigned int V_capacity = ON_SubDManagedMeshFragment::PointCountFromDisplayDensity(display_density); - if (V_capacity >= short_capacity_sanity_check ) - return ON_SUBD_RETURN_ERROR(false); - - const unsigned int F_capacity = ON_SubDManagedMeshFragment::FaceCountFromDisplayDensity(display_density); - if ( F_capacity >= short_capacity_sanity_check) - return ON_SUBD_RETURN_ERROR(false); - - //const size_t P_stride = 3; - //const size_t N_stride = 3; - //const size_t T_stride = 3; - //const size_t C_stride = 1; - - // storage_capacity holds = 3 point coords + 3 normal coords + 3 texture point coords + an ON_Color + unused 4 bytes (+ a 16-byte ON_SurfaceCurvature). - size_t storage_capacity = - (bWithCurvature - ? ON_SubDMeshFragment::ManagedDoublesPerVertexWithCurvature - : ON_SubDMeshFragment::ManagedDoublesPerVertex) * - V_capacity; - if (storage_capacity > m_storage_capacity || nullptr == m_storage) + const unsigned int vertex_capacity = ON_SubDManagedMeshFragment::PointCountFromDisplayDensity(display_density); + if (vertex_capacity > this->VertexCapacity()) { - if (m_storage_capacity > 0 && nullptr != m_storage) - { - delete[] m_storage; - m_storage = nullptr; - } - - m_storage = new(std::nothrow) double[storage_capacity]; - if (nullptr == m_storage) - return ON_SUBD_RETURN_ERROR(false); - m_storage_capacity = storage_capacity; + this->DeleteManagedArrays(); + ClearControlNetQuad(); + // ON_SubDManagedMeshFragment manages m_storage and m_P[]/m_N[]/m_T[]/m_K[]/m_C[]) + // are not managed by ON_SubDMeshFragment. + // (ON_SubDManagedMeshFragment is a legacy class that should not be used + // and this confusing situation is an artifact from early code.) + Internal_LayoutArrays( vertex_capacity, nullptr ); } + SetVertexCount(vertex_capacity); - UnsetControlNetQuad(); - // ON_SubDManagedMeshFragment manages m_storage and m_P[]/m_N[]/m_T[]/m_C[](/m_K[]) are not managed by ON_SubDMeshFragment. - // (ON_SubDManagedMeshFragment is a legacy class that should not be used and this confusing situation is - // an artifact from early code.) - Internal_LayoutArrays(false, bWithCurvature, m_storage, V_capacity); - SetVertexCount(V_capacity); - - m_surface_bbox = ON_BoundingBox::NanBoundingBox; + ClearSurfaceBoundingBox(); m_grid = ON_SubDMeshFragmentGrid::QuadGridFromDisplayDensity(display_density,0U); if ( nullptr == m_grid.m_F) @@ -1006,105 +955,133 @@ bool ON_SubDManagedMeshFragment::ReserveCapacity( void ON_SubDManagedMeshFragment::Clear() ON_NOEXCEPT { - memset(this, 0, sizeof(ON_SubDMeshFragment)); + ON_SubDMeshFragment::ON_SubDMeshFragment::SetVertexCount(0); + this->SetVertexCount(0); } void ON_SubDManagedMeshFragment::Destroy() ON_NOEXCEPT { - double* p = const_cast(m_P); - memset(this, 0, sizeof(*this)); - if ( nullptr != p) - delete[] p; - this->DeleteManagedCurvatureCapacity(); + this->SetVertexCount(0); + this->DeleteManagedArrays(); } void ON_SubDManagedMeshFragment::CopyHelper(const ON_SubDMeshFragment& src) { - //TODO: Should this also work when src and dest do not have the same number of vertices? See ON_SubDMeshFragment::CopyFrom() + // This makes an exact copy. + // See ON_SubDMeshFragment::CopyFrom() can copy high density to low density if (this == &src) return; + + ON_SubDMeshFragment::Clear(); - m_vertex_capacity_etc = 0; - m_vertex_count_etc = 0; - m_P = nullptr; - m_P_stride = 0; - m_N = nullptr; - m_N_stride = 0; - m_T = nullptr; - m_T_stride = 0; - m_C = nullptr; - m_C_stride = 0; - m_surface_bbox = ON_BoundingBox::NanBoundingBox; - m_K = nullptr; - m_K_stride = 0; - const size_t V_count = src.VertexCount(); - if (0 == V_count) + const size_t vertex_capacity = src.VertexCount(); + if (0 == vertex_capacity) return; const unsigned P_count = src.PointCount(); - if (0 != P_count && V_count != P_count) + if (0 != P_count && vertex_capacity != P_count) { ON_SUBD_ERROR("invalid counts"); return; } - const unsigned N_count = src.NormalCount(); - if (0 != N_count && V_count != N_count) + unsigned N_count = src.NormalCount(); + if (0 != N_count && vertex_capacity != N_count) { - ON_SUBD_ERROR("invalid counts"); - return; + ON_SUBD_ERROR("invalid src.NormalCount()"); + N_count = 0; } - const unsigned T_count = src.TextureCoordinateCount(); - if (0 != T_count && V_count != T_count) + unsigned T_count = src.TextureCoordinateCount(); + if (0 != T_count && vertex_capacity != T_count) { - ON_SUBD_ERROR("invalid counts"); - return; + ON_SUBD_ERROR("invalid src.TextureCoordinateCount()"); + T_count = 0; } - const unsigned C_count = src.ColorCount(); - if (0 != C_count && V_count != C_count) + unsigned K_count = src.CurvatureCount(); + if (0 != K_count && vertex_capacity != K_count) { - ON_SUBD_ERROR("invalid counts"); - return; + ON_SUBD_ERROR("invalid src.CurvatureCount()"); + K_count; } - const unsigned K_count = src.CurvatureCount(); - if (0 != K_count && V_count != K_count) + unsigned C_count = src.ColorCount(); + if (0 != C_count && vertex_capacity != C_count) { - ON_SUBD_ERROR("invalid counts"); - return; + ON_SUBD_ERROR("invalid src.ColorCount()"); + C_count = 0; } - if (src.m_vertex_count_etc & ON_SubDMeshFragment::EtcControlNetQuadBit) { + + if (vertex_capacity > this->VertexCapacity()) + { + if (this->UnmanagedArrays() && this->VertexCapacity() > 0) + { + ON_SUBD_ERROR("unmanaged array capacity is too small."); + return; + } + + if (this->ManagedArrays()) + this->DeleteManagedArrays(); + + // allocate managed arrays + m_vertex_count_etc = 0; + m_vertex_capacity_etc = 0; + m_P = nullptr; + this->Internal_LayoutArrays(vertex_capacity, nullptr); + } + + if (this->TextureCoordinateCapacity() < vertex_capacity) + T_count = 0; + if (this->CurvatureCapacity() < vertex_capacity) + K_count = 0; + if (this->ColorCapacity() < vertex_capacity) + C_count = 0; + + SetVertexCount(vertex_capacity); + + if (src.m_vertex_count_etc & ON_SubDMeshFragment::EtcControlNetQuadBit) + { m_vertex_count_etc |= ON_SubDMeshFragment::EtcControlNetQuadBit; - } else { + } + else + { m_vertex_count_etc &= ~ON_SubDMeshFragment::EtcControlNetQuadBit; } - m_ctrlnetT[0][0] = src.m_ctrlnetT[0][0]; - m_ctrlnetT[0][1] = src.m_ctrlnetT[0][1]; - m_ctrlnetT[0][2] = src.m_ctrlnetT[0][2]; - m_ctrlnetT[1][0] = src.m_ctrlnetT[1][0]; - m_ctrlnetT[1][1] = src.m_ctrlnetT[1][1]; - m_ctrlnetT[1][2] = src.m_ctrlnetT[1][2]; - m_ctrlnetT[2][0] = src.m_ctrlnetT[2][0]; - m_ctrlnetT[2][1] = src.m_ctrlnetT[2][1]; - m_ctrlnetT[2][2] = src.m_ctrlnetT[2][2]; - m_ctrlnetT[3][0] = src.m_ctrlnetT[3][0]; - m_ctrlnetT[3][1] = src.m_ctrlnetT[3][1]; - m_ctrlnetT[3][2] = src.m_ctrlnetT[3][2]; + if (T_count > 0) + { + m_ctrlnetT[0][0] = src.m_ctrlnetT[0][0]; + m_ctrlnetT[0][1] = src.m_ctrlnetT[0][1]; + m_ctrlnetT[0][2] = src.m_ctrlnetT[0][2]; + m_ctrlnetT[1][0] = src.m_ctrlnetT[1][0]; + m_ctrlnetT[1][1] = src.m_ctrlnetT[1][1]; + m_ctrlnetT[1][2] = src.m_ctrlnetT[1][2]; + m_ctrlnetT[2][0] = src.m_ctrlnetT[2][0]; + m_ctrlnetT[2][1] = src.m_ctrlnetT[2][1]; + m_ctrlnetT[2][2] = src.m_ctrlnetT[2][2]; + m_ctrlnetT[3][0] = src.m_ctrlnetT[3][0]; + m_ctrlnetT[3][1] = src.m_ctrlnetT[3][1]; + m_ctrlnetT[3][2] = src.m_ctrlnetT[3][2]; + } - m_ctrlnetC[0] = src.m_ctrlnetC[0]; - m_ctrlnetC[1] = src.m_ctrlnetC[1]; - m_ctrlnetC[2] = src.m_ctrlnetC[2]; - m_ctrlnetC[3] = src.m_ctrlnetC[3]; + if (K_count > 0) + { + m_ctrlnetK[0] = src.m_ctrlnetK[0]; + m_ctrlnetK[1] = src.m_ctrlnetK[1]; + m_ctrlnetK[2] = src.m_ctrlnetK[2]; + m_ctrlnetK[3] = src.m_ctrlnetK[3]; + } - m_ctrlnetK[0] = src.m_ctrlnetK[0]; - m_ctrlnetK[1] = src.m_ctrlnetK[1]; - m_ctrlnetK[2] = src.m_ctrlnetK[2]; - m_ctrlnetK[3] = src.m_ctrlnetK[3]; + if (C_count > 0) + { + m_ctrlnetC[0] = src.m_ctrlnetC[0]; + m_ctrlnetC[1] = src.m_ctrlnetC[1]; + m_ctrlnetC[2] = src.m_ctrlnetC[2]; + m_ctrlnetC[3] = src.m_ctrlnetC[3]; + } m_pack_rect[0][0] = src.m_pack_rect[0][0]; m_pack_rect[0][1] = src.m_pack_rect[0][1]; @@ -1115,35 +1092,24 @@ void ON_SubDManagedMeshFragment::CopyHelper(const ON_SubDMeshFragment& src) m_pack_rect[3][0] = src.m_pack_rect[3][0]; m_pack_rect[3][1] = src.m_pack_rect[3][1]; - m_surface_bbox = src.m_surface_bbox; - m_grid = src.m_grid; + this->m_surface_bbox = src.m_surface_bbox; + this->m_grid = src.m_grid; - // 10 (12) = 3 point coordinates + 3 normal coordinates + 3 texture coordinates + a double to provide double aligned color memory (+ 2 doubles for an ON_SurfaceCurvature) - const size_t storage_capacity = - (K_count == 0 - ? ON_SubDMeshFragment::ManagedDoublesPerVertex - : ON_SubDMeshFragment::ManagedDoublesPerVertexWithCurvature) * - V_count; - m_storage = new(std::nothrow) double[storage_capacity]; - if (nullptr == m_storage) - { - ON_SubDIncrementErrorCount(); - return; - } - m_storage_capacity = storage_capacity; - SetUnmanagedVertexCapacity(V_count); - SetVertexCount(V_count); + ON_3dPoint quad_points[4]; + ON_3dVector quad_normal; + src.GetControlNetQuad(false, quad_points, quad_normal); + this->SetControlNetQuad(false, quad_points, quad_normal); - double buffer3[3]; + + const double nan3[3] = { ON_DBL_QNAN, ON_DBL_QNAN, ON_DBL_QNAN }; const double* src_p; size_t src_p_stride; double* p; double* p1; - m_P = m_storage; - m_P_stride = ON_SubDMeshFragment::Managed_3d_stride; + // copy src.m_P[] to m_P[] p = m_P; - p1 = p + (m_P_stride * V_count); + p1 = p + (m_P_stride * vertex_capacity); if ( P_count > 0 ) { src_p = src.m_P; @@ -1151,8 +1117,7 @@ void ON_SubDManagedMeshFragment::CopyHelper(const ON_SubDMeshFragment& src) } else { - buffer3[0] = buffer3[1] = buffer3[2] = ON_DBL_QNAN; - src_p = buffer3; + src_p = nan3; src_p_stride = 0; } while (p < p1) @@ -1164,6 +1129,7 @@ void ON_SubDManagedMeshFragment::CopyHelper(const ON_SubDMeshFragment& src) src_p += src_p_stride; } + // copy src.m_N[] to m_N[] if (N_count > 0) { src_p = src.m_N; @@ -1172,104 +1138,104 @@ void ON_SubDManagedMeshFragment::CopyHelper(const ON_SubDMeshFragment& src) else { // Pierre, 2023-04-13: Set to Nan when empty source, to stay similar to ON_SubDMeshFragment::CopyFrom() - buffer3[0] = buffer3[1] = buffer3[2] = ON_DBL_QNAN; - src_p = buffer3; + src_p = nan3; src_p_stride = 0; } - m_N = m_storage + Internal_Managed3dArrayOffset(V_count); - m_N_stride = ON_SubDMeshFragment::Managed_3d_stride; - p = m_N; - p1 = p + (m_N_stride * V_count); - while (p < p1) + if (this->NormalCapacity() >= vertex_capacity) { - p[0] = src_p[0]; - p[1] = src_p[1]; - p[2] = src_p[2]; - p += m_N_stride; - src_p += src_p_stride; + p = m_N; + p1 = p + (m_N_stride * vertex_capacity); + while (p < p1) + { + p[0] = src_p[0]; + p[1] = src_p[1]; + p[2] = src_p[2]; + p += m_N_stride; + src_p += src_p_stride; + } } + // copy src.m_T[] to m_T[] if (T_count > 0) { src_p = src.m_T; src_p_stride = src.m_T_stride; - SetTextureCoordinatesExist(src.TextureCoordinatesExist()); + SetTextureCoordinatesExistForExperts(true); } else { - buffer3[0] = buffer3[1] = buffer3[2] = ON_DBL_QNAN; - src_p = buffer3; + // set m_T[] to nans + src_p = nan3; src_p_stride = 0; - SetTextureCoordinatesExist(false); } - m_T = m_N + Internal_Managed3dArrayOffset(V_count); - m_T_stride = ON_SubDMeshFragment::Managed_3d_stride; - p = m_T; - p1 = p + (m_T_stride * V_count); - while (p < p1) + if (this->TextureCoordinateCapacity() >= vertex_capacity) { - p[0] = src_p[0]; - p[1] = src_p[1]; - p[2] = src_p[2]; - p += m_T_stride; - src_p += src_p_stride; - } - - const ON_Color* src_c; - size_t src_c_stride; - if (C_count > 0) - { - src_c = src.m_C; - src_c_stride = src.m_C_stride; - SetColorsExist(src.ColorsExist()); - } - else - { - src_c = &ON_Color::UnsetColor; - src_c_stride = 0; - SetColorsExist(false); - } - m_C = (ON_Color*)(m_T + Internal_Managed3dArrayOffset(V_count)); - m_C_stride = ON_SubDMeshFragment::Managed_color_stride; - ON_Color* c = m_C; - ON_Color* c1 = c + (m_C_stride * V_count); - while (c < c1) - { - *c = *src_c; - c += m_C_stride; - src_c += src_c_stride; + p = m_T; + p1 = p + (m_T_stride * vertex_capacity); + while (p < p1) + { + p[0] = src_p[0]; + p[1] = src_p[1]; + p[2] = src_p[2]; + p += m_T_stride; + src_p += src_p_stride; + } } + // copy src.m_K[] to m_K[] const ON_SurfaceCurvature* src_k; size_t src_k_stride; if (K_count > 0) { + // copy curvarure src_k = src.m_K; src_k_stride = src.m_K_stride; - m_K = (ON_SurfaceCurvature*)(m_C + Internal_ManagedColorArrayOffset(V_count)); - m_K_stride = ON_SubDMeshFragment::Managed_curvature_stride; + SetCurvaturesExistForExperts(true); + } + else + { + src_k = &ON_SurfaceCurvature::Nan; + src_k_stride = 0; + } + if (this->CurvatureCapacity() >= vertex_capacity) + { ON_SurfaceCurvature* k = m_K; - ON_SurfaceCurvature* k1 = k + (m_K_stride * V_count); + ON_SurfaceCurvature* k1 = k + (m_K_stride * vertex_capacity); while (k < k1) { *k = *src_k; k += m_K_stride; src_k += src_k_stride; } - SetCurvaturesExist(src.CurvaturesExist()); + } + + // copy src.m_C[] to m_C[] + const ON_Color* src_c; + size_t src_c_stride; + if (C_count > 0) + { + src_c = src.m_C; + src_c_stride = src.m_C_stride; + SetColorsExistForExperts(true); } else { - // No space for curvatures has been allocated in m_storage - m_K = nullptr; - m_K_stride = 0; - SetCurvaturesExist(false); + src_c = &ON_Color::UnsetColor; + src_c_stride = 0; + } + if (this->ColorCapacity() >= vertex_capacity) + { + ON_Color* c = m_C; + ON_Color* c1 = c + (m_C_stride * vertex_capacity); + while (c < c1) + { + *c = *src_c; + c += m_C_stride; + src_c += src_c_stride; + } } - ON_3dPoint quad_points[4]; - ON_3dVector quad_normal; - src.GetControlNetQuad(false, quad_points, quad_normal); - SetControlNetQuad(false, quad_points, quad_normal); + } ON_SubDManagedMeshFragment ON_SubDManagedMeshFragment::Create(const ON_SubDMeshFragment& src) ON_NOEXCEPT @@ -1734,6 +1700,14 @@ const ON_2dPoint ON_SubDMeshFragment::PackRectCenter() const ); } +void ON_SubDMeshFragment::ClearPackRect() +{ + double* p = &m_pack_rect[0][0]; + double* p1 = p + (sizeof(m_pack_rect) / sizeof(m_pack_rect[0][0])); + while (p < p1) + *p++ = ON_DBL_QNAN; +} + const ON_3dVector ON_SubDMeshFragment::CornerNormal(unsigned int grid_corner_index) const { @@ -2348,21 +2322,14 @@ bool ON_SubDMeshImpl::ReserveCapacity( if ( subd_fragment_count < 1 ) return ON_SUBD_RETURN_ERROR(false); - // note sizeof(double) = 2*sizeof(ON_Color) so we have - // room for 3d points, 3d normals, 3d texture points, a color array - // and a currently unused array of 32 bit elements, and 2d curvatures. - size_t sizeof_PNTCK = m_has_curvatures - ? ON_SubDMeshFragment::ManagedDoublesPerVertexWithCurvature * - fragment_point_count * sizeof(double) - : ON_SubDMeshFragment::ManagedDoublesPerVertex * - fragment_point_count * sizeof(double); + size_t sizeof_PNTKC = fragment_point_count * ON_SubDMeshFragment::DoublesPerVertex * sizeof(double); size_t sizeof_fragment = sizeof(ON_SubDMeshFragment); if (0 != sizeof_fragment % sizeof(double)) { sizeof_fragment = (1 + sizeof_fragment / sizeof(double))*sizeof(double); } - if( false == m_fsp.Create(sizeof_fragment + sizeof_PNTCK,subd_fragment_count,0)) + if( false == m_fsp.Create(sizeof_fragment + sizeof_PNTKC, subd_fragment_count, 0)) return ON_SUBD_RETURN_ERROR(false); m_absolute_subd_display_density = absolute_subd_display_density; @@ -2372,8 +2339,7 @@ bool ON_SubDMeshImpl::ReserveCapacity( } size_t ON_SubDMeshFragment::SizeofFragment( - unsigned int display_density, - bool bCurvatureArray + unsigned int display_density ) { if (display_density > ON_SubDDisplayParameters::MaximumDensity) @@ -2389,9 +2355,13 @@ size_t ON_SubDMeshFragment::SizeofFragment( ++sz; const size_t doubles_per_vertex - = 10 // 6 = 3+3 = 3d points in m_P[] and 3d vectors in m_N[] and 3d points in m_T[] and a color in m_C[] (sizeof(m_C[0]) <= sizeof(double)) - + (size_t)((bCurvatureArray ? sizeof(ON_SurfaceCurvature)/sizeof(double) : 0)) + = 3 // 3d points in m_P[] + + 3 // 3d vectors in m_N[] + + 3 // 3d points in m_T[] + + 1 // a color in m_C[] (note that sizeof(m_C[0]) <= sizeof(double) + + sizeof(ON_SurfaceCurvature)/sizeof(double) // 2 doubles in ON_SurfaceCurvature ; + const size_t sizeof_doubles = doubles_per_vertex * sizeof(double); sz += vertex_capacity * sizeof_doubles; return sz; @@ -2410,6 +2380,13 @@ bool ON_SubDMeshFragment::CopyFrom( unsigned int display_density ) { + if (this == &src_fragment) + { + return true; + } + + this->Clear(); + m_face = src_fragment.m_face; m_face_vertex_index[0] = src_fragment.m_face_vertex_index[0]; m_face_vertex_index[1] = src_fragment.m_face_vertex_index[1]; @@ -2417,39 +2394,44 @@ bool ON_SubDMeshFragment::CopyFrom( m_face_vertex_index[3] = src_fragment.m_face_vertex_index[3]; m_face_fragment_count = src_fragment.m_face_fragment_count; m_face_fragment_index = src_fragment.m_face_fragment_index; - m_vertex_count_etc = 0; - m_grid = ON_SubDMeshFragmentGrid::Empty; - m_surface_bbox = ON_BoundingBox::NanBoundingBox; - // Note well: Do not change capacity on this. - SetVertexCount(0); + ON_3dPoint quad_points[4]; ON_3dVector quad_normal; - src_fragment.GetControlNetQuad(false, quad_points, quad_normal); - SetControlNetQuad(false, quad_points, quad_normal); + if (src_fragment.GetControlNetQuad(false, quad_points, quad_normal)) + this->SetControlNetQuad(false, quad_points, quad_normal); - m_ctrlnetT[0][0] = src_fragment.m_ctrlnetT[0][0]; - m_ctrlnetT[0][1] = src_fragment.m_ctrlnetT[0][1]; - m_ctrlnetT[0][2] = src_fragment.m_ctrlnetT[0][2]; - m_ctrlnetT[1][0] = src_fragment.m_ctrlnetT[1][0]; - m_ctrlnetT[1][1] = src_fragment.m_ctrlnetT[1][1]; - m_ctrlnetT[1][2] = src_fragment.m_ctrlnetT[1][2]; - m_ctrlnetT[2][0] = src_fragment.m_ctrlnetT[2][0]; - m_ctrlnetT[2][1] = src_fragment.m_ctrlnetT[2][1]; - m_ctrlnetT[2][2] = src_fragment.m_ctrlnetT[2][2]; - m_ctrlnetT[3][0] = src_fragment.m_ctrlnetT[3][0]; - m_ctrlnetT[3][1] = src_fragment.m_ctrlnetT[3][1]; - m_ctrlnetT[3][2] = src_fragment.m_ctrlnetT[3][2]; + if (src_fragment.TextureCoordinatesExistForExperts()) + { + m_ctrlnetT[0][0] = src_fragment.m_ctrlnetT[0][0]; + m_ctrlnetT[0][1] = src_fragment.m_ctrlnetT[0][1]; + m_ctrlnetT[0][2] = src_fragment.m_ctrlnetT[0][2]; + m_ctrlnetT[1][0] = src_fragment.m_ctrlnetT[1][0]; + m_ctrlnetT[1][1] = src_fragment.m_ctrlnetT[1][1]; + m_ctrlnetT[1][2] = src_fragment.m_ctrlnetT[1][2]; + m_ctrlnetT[2][0] = src_fragment.m_ctrlnetT[2][0]; + m_ctrlnetT[2][1] = src_fragment.m_ctrlnetT[2][1]; + m_ctrlnetT[2][2] = src_fragment.m_ctrlnetT[2][2]; + m_ctrlnetT[3][0] = src_fragment.m_ctrlnetT[3][0]; + m_ctrlnetT[3][1] = src_fragment.m_ctrlnetT[3][1]; + m_ctrlnetT[3][2] = src_fragment.m_ctrlnetT[3][2]; + } - m_ctrlnetC[0] = src_fragment.m_ctrlnetC[0]; - m_ctrlnetC[1] = src_fragment.m_ctrlnetC[1]; - m_ctrlnetC[2] = src_fragment.m_ctrlnetC[2]; - m_ctrlnetC[3] = src_fragment.m_ctrlnetC[3]; + if (src_fragment.CurvaturesExistForExperts()) + { + m_ctrlnetK[0] = src_fragment.m_ctrlnetK[0]; + m_ctrlnetK[1] = src_fragment.m_ctrlnetK[1]; + m_ctrlnetK[2] = src_fragment.m_ctrlnetK[2]; + m_ctrlnetK[3] = src_fragment.m_ctrlnetK[3]; + } - m_ctrlnetK[0] = src_fragment.m_ctrlnetK[0]; - m_ctrlnetK[1] = src_fragment.m_ctrlnetK[1]; - m_ctrlnetK[2] = src_fragment.m_ctrlnetK[2]; - m_ctrlnetK[3] = src_fragment.m_ctrlnetK[3]; + if (src_fragment.ColorsExistForExperts()) + { + m_ctrlnetC[0] = src_fragment.m_ctrlnetC[0]; + m_ctrlnetC[1] = src_fragment.m_ctrlnetC[1]; + m_ctrlnetC[2] = src_fragment.m_ctrlnetC[2]; + m_ctrlnetC[3] = src_fragment.m_ctrlnetC[3]; + } m_pack_rect[0][0] = src_fragment.m_pack_rect[0][0]; m_pack_rect[0][1] = src_fragment.m_pack_rect[0][1]; @@ -2460,7 +2442,7 @@ bool ON_SubDMeshFragment::CopyFrom( m_pack_rect[3][0] = src_fragment.m_pack_rect[3][0]; m_pack_rect[3][1] = src_fragment.m_pack_rect[3][1]; - if ( display_density > 8 && ON_UNSET_UINT_INDEX != display_density) + if ( display_density > ON_SubDDisplayParameters::MaximumDensity && ON_UNSET_UINT_INDEX != display_density) return ON_SUBD_RETURN_ERROR(false); const unsigned src_V_count = src_fragment.VertexCount(); @@ -2478,21 +2460,11 @@ bool ON_SubDMeshFragment::CopyFrom( if (VertexCapacity() < V_count) { if (false == this->ReserveManagedVertexCapacity(V_count)) - //if (false == this->ReserveManagedVertexCapacity(V_count, src_fragment.CurvatureCapacity() > 0)) return ON_SUBD_RETURN_ERROR(false); } if (V_count > VertexCapacity() || V_count > src_fragment.VertexCount()) return ON_SUBD_RETURN_ERROR(false); - if (CurvatureCapacity() < src_fragment.CurvatureCount()) - { - if (false == this->ReserveManagedCurvatureCapacity()) - return ON_SUBD_RETURN_ERROR(false); - } - if ((CurvatureCapacity() > 0 && V_count > CurvatureCapacity()) || - (src_fragment.CurvaturesExist() && V_count > src_fragment.CurvatureCount())) - return ON_SUBD_RETURN_ERROR(false); - m_grid = grid; double* p = m_P; @@ -2505,16 +2477,20 @@ bool ON_SubDMeshFragment::CopyFrom( // Most common case where srf_fragment and target have the same density - faster way to copy. // copy m_P[] - while (src_p < src_p1) + if (V_count <= this->PointCapacity()) { - p[0] = src_p[0]; - p[1] = src_p[1]; - p[2] = src_p[2]; - p += p_stride; - src_p += src_p_stride; + while (src_p < src_p1) + { + p[0] = src_p[0]; + p[1] = src_p[1]; + p[2] = src_p[2]; + p += p_stride; + src_p += src_p_stride; + } + m_surface_bbox = src_fragment.m_surface_bbox; } - if (V_count <= NormalCapacity() ) + if (V_count <= this->NormalCapacity() ) { if (V_count == src_fragment.NormalCount()) { @@ -2539,12 +2515,12 @@ bool ON_SubDMeshFragment::CopyFrom( } } - if (V_count <= TextureCoordinateCapacity()) + if (V_count <= this->TextureCoordinateCapacity()) { if (V_count == src_fragment.TextureCoordinateCount()) { // copy m_T[] - SetTextureCoordinatesExist(true); + SetTextureCoordinatesExistForExperts(true); p = m_T; p_stride = m_T_stride; src_p = src_fragment.m_T; @@ -2565,39 +2541,12 @@ bool ON_SubDMeshFragment::CopyFrom( } } - if (V_count <= ColorCapacity()) + if (V_count <= this->CurvatureCapacity()) { - if (V_count == src_fragment.ColorCount() && src_fragment.ColorsExist()) - { - // copy m_C[] - SetColorsExist(true); - ON_Color* c = m_C; - const size_t c_stride = m_C_stride; - ON_Color* src_c = src_fragment.m_C; - size_t src_c_stride = src_fragment.m_C_stride; - ON_Color* src_c1 = src_c + src_c_stride * src_V_count; - while (src_c < src_c1) - { - c = src_c; - c += c_stride; - src_c += src_c_stride; - } - } - else - { - SetColorsExist(false); - ON_Color* c = m_C; - for (ON_Color* c1 = c + V_count * m_C_stride; c < c1; c += m_C_stride) - *c = ON_Color::UnsetColor; - } - } - - if (V_count <= CurvatureCapacity()) - { - if (V_count == src_fragment.CurvatureCount() && src_fragment.CurvaturesExist()) + if (V_count == src_fragment.CurvatureCount()) { // copy m_K[] - SetCurvaturesExist(true); + SetCurvaturesExistForExperts(true); ON_SurfaceCurvature* k = m_K; const size_t k_stride = m_K_stride; ON_SurfaceCurvature* src_k = src_fragment.m_K; @@ -2612,12 +2561,37 @@ bool ON_SubDMeshFragment::CopyFrom( } else { - SetCurvaturesExist(false); ON_SurfaceCurvature* k = m_K; for (ON_SurfaceCurvature* k1 = k + V_count * m_K_stride; k < k1; k += m_K_stride) *k = ON_SurfaceCurvature::Nan; } } + + if (V_count <= ColorCapacity()) + { + if (V_count == src_fragment.ColorCount()) + { + // copy m_C[] + SetColorsExistForExperts(true); + ON_Color* c = m_C; + const size_t c_stride = m_C_stride; + ON_Color* src_c = src_fragment.m_C; + size_t src_c_stride = src_fragment.m_C_stride; + ON_Color* src_c1 = src_c + src_c_stride * src_V_count; + while (src_c < src_c1) + { + c = src_c; + c += c_stride; + src_c += src_c_stride; + } + } + else + { + ON_Color* c = m_C; + for (ON_Color* c1 = c + V_count * m_C_stride; c < c1; c += m_C_stride) + *c = ON_Color::UnsetColor; + } + } } else { @@ -2637,20 +2611,25 @@ bool ON_SubDMeshFragment::CopyFrom( // copy from src_fragment.m_P[] to this->m_P[] size_t i_stride = di * src_fragment.m_P_stride; size_t j_stride = m * dj * src_fragment.m_P_stride; - for (unsigned int j = 0; j < m; j += dj) + + if (V_count <= this->PointCapacity()) { - src_p = src_fragment.m_P + j * j_stride; - for (unsigned int i = 0; i < m; i += di) + for (unsigned int j = 0; j < m; j += dj) { - p[0] = src_p[0]; - p[1] = src_p[1]; - p[2] = src_p[2]; - p += p_stride; - src_p += i_stride; + src_p = src_fragment.m_P + j * j_stride; + for (unsigned int i = 0; i < m; i += di) + { + p[0] = src_p[0]; + p[1] = src_p[1]; + p[2] = src_p[2]; + p += p_stride; + src_p += i_stride; + } } + m_surface_bbox = src_fragment.m_surface_bbox; } - if (V_count <= NormalCapacity()) + if (V_count <= this->NormalCapacity()) { // copy from src_fragment.m_N[] to this->m_N[] if (V_count <= src_fragment.NormalCount()) @@ -2678,12 +2657,12 @@ bool ON_SubDMeshFragment::CopyFrom( } } - if (V_count <= TextureCoordinateCapacity()) + if (V_count <= this->TextureCoordinateCapacity()) { // copy from src_fragment.m_T[] to this->m_T[] if (V_count <= src_fragment.TextureCoordinateCount()) { - SetTextureCoordinatesExist(true); + SetTextureCoordinatesExistForExperts(true); p = m_T; p_stride = m_T_stride; i_stride = di * src_fragment.m_T_stride; @@ -2707,12 +2686,41 @@ bool ON_SubDMeshFragment::CopyFrom( } } - if (V_count <= ColorCapacity()) + if (V_count <= this->CurvatureCapacity()) + { + // copy from src_fragment.m_K[] to this->m_K[] + if (V_count <= src_fragment.CurvatureCount()) + { + SetCurvaturesExistForExperts(true); + ON_SurfaceCurvature* k = m_K; + const size_t k_stride = m_K_stride; + i_stride = di * src_fragment.m_K_stride; + j_stride = m * dj * src_fragment.m_K_stride; + for (unsigned int j = 0; j < m; j += dj) + { + const ON_SurfaceCurvature* src_k = src_fragment.m_K + j * j_stride; + for (unsigned int i = 0; i < m; i += di) + { + *k = *src_k; + k += k_stride; + src_k += i_stride; + } + } + } + else + { + ON_SurfaceCurvature* k = m_K; + for (ON_SurfaceCurvature* k1 = k + V_count * m_K_stride; k < k1; k += m_K_stride) + *k = ON_SurfaceCurvature::Nan; + } + } + + if (V_count <= this->ColorCapacity()) { // copy from src_fragment.m_C[] to this->m_C[] if (V_count <= src_fragment.ColorCount()) { - SetColorsExist(true); + SetColorsExistForExperts(true); ON_Color*c = m_C; const size_t c_stride = m_C_stride; i_stride = di * src_fragment.m_C_stride; @@ -2735,40 +2743,9 @@ bool ON_SubDMeshFragment::CopyFrom( *c = ON_Color::UnsetColor; } } - - if (V_count <= CurvatureCapacity()) - { - // copy from src_fragment.m_K[] to this->m_K[] - if (V_count <= src_fragment.CurvatureCount() && src_fragment.CurvaturesExist()) - { - SetCurvaturesExist(true); - ON_SurfaceCurvature* k = m_K; - const size_t k_stride = m_K_stride; - i_stride = di * src_fragment.m_K_stride; - j_stride = m * dj * src_fragment.m_K_stride; - for (unsigned int j = 0; j < m; j += dj) - { - const ON_SurfaceCurvature* src_k = src_fragment.m_K + j * j_stride; - for (unsigned int i = 0; i < m; i += di) - { - *k = *src_k; - k += k_stride; - src_k += i_stride; - } - } - } - else - { - SetCurvaturesExist(false); - ON_SurfaceCurvature* k = m_K; - for (ON_SurfaceCurvature* k1 = k + V_count * m_K_stride; k < k1; k += m_K_stride) - *k = ON_SurfaceCurvature::Nan; - } - } } SetVertexCount(V_count); - m_surface_bbox = src_fragment.m_surface_bbox; return true; } @@ -2792,7 +2769,7 @@ ON_SubDMeshFragment* ON_SubDMeshImpl::CopyCallbackFragment( return ON_SUBD_RETURN_ERROR(nullptr); // The memory for the arrays in this case is managed by m_fsp[]. - fragment->Internal_LayoutArrays(false, m_has_curvatures, (double*)(fragment + 1), m_fragment_point_count); + fragment->Internal_LayoutArrays(m_fragment_point_count, (double*)(fragment + 1) ); fragment->CopyFrom(*callback_fragment); ChangeContentSerialNumber(); diff --git a/opennurbs_subd_heap.cpp b/opennurbs_subd_heap.cpp index 432de774..95117bac 100644 --- a/opennurbs_subd_heap.cpp +++ b/opennurbs_subd_heap.cpp @@ -23,25 +23,19 @@ #include "opennurbs_subd_data.h" - -enum -{ - // change bAllFragmentsHaveCurvature to true when principal and sectional curvatures are needed - // or delete this enum and always make room for curvatures. - ON_Internal_bAllFragmentsHaveCurvature = 0 -}; - - - const size_t ON_SubDHeap::g_sizeof_fragment[ON_SubDDisplayParameters::MaximumDensity + 1] = { - ON_SubDMeshFragment::SizeofFragment(0, ON_Internal_bAllFragmentsHaveCurvature), - ON_SubDMeshFragment::SizeofFragment(1, ON_Internal_bAllFragmentsHaveCurvature), - ON_SubDMeshFragment::SizeofFragment(2, ON_Internal_bAllFragmentsHaveCurvature), - ON_SubDMeshFragment::SizeofFragment(3, ON_Internal_bAllFragmentsHaveCurvature), - ON_SubDMeshFragment::SizeofFragment(4, ON_Internal_bAllFragmentsHaveCurvature), - ON_SubDMeshFragment::SizeofFragment(5, ON_Internal_bAllFragmentsHaveCurvature), - ON_SubDMeshFragment::SizeofFragment(ON_SubDDisplayParameters::MaximumDensity, ON_Internal_bAllFragmentsHaveCurvature) + // All densities >= 0 and <= ON_SubDDisplayParameters::MaximumDensity + // must be in the following list. The sizes must include room for + // textures, colors, and curvatures, even though those properties are + // often not set. + ON_SubDMeshFragment::SizeofFragment(0), + ON_SubDMeshFragment::SizeofFragment(1), + ON_SubDMeshFragment::SizeofFragment(2), + ON_SubDMeshFragment::SizeofFragment(3), + ON_SubDMeshFragment::SizeofFragment(4), + ON_SubDMeshFragment::SizeofFragment(5), + ON_SubDMeshFragment::SizeofFragment(ON_SubDDisplayParameters::MaximumDensity) }; static void* ON_SubD__Allocate(size_t sz) @@ -2068,6 +2062,12 @@ ON_SubDMeshFragment* ON_SubDHeap::AllocateMeshFragment( const size_t sizeof_fragment = ON_SubDHeap::g_sizeof_fragment[density]; for (p += sizeof_fragment; p + sizeof_fragment <= p1; p += sizeof_fragment) { + // This loop is rarely executed. + // It is used when an unusual small fragment is allocated from a pool + // providing large fragments (fsp.SizeofElement() > sizeof_fragment). + // If fsp.SizeofElement() is not an even multiple of sizeof_fragment, + // then some memory is wasted. Beause this situation is uncommon, + // the waste doesn't matter in the big scheme of things. ON_FixedSizePoolElement* ele = (ON_FixedSizePoolElement*)p; ele->m_next = m_unused_fragments[density]; m_unused_fragments[density] = ele; @@ -2077,13 +2077,14 @@ ON_SubDMeshFragment* ON_SubDHeap::AllocateMeshFragment( m_unused_fragments[density] = m_unused_fragments[density]->m_next; } - *fragment = src_fragment; + // NO // *fragment = src_fragment; + *fragment = ON_SubDMeshFragment::Empty; fragment->m_prev_fragment = nullptr; fragment->m_next_fragment = nullptr; // NOTE WELL: // fragment and fragment array memory are from a single fixed size pool allocation. - fragment->Internal_LayoutArrays(false, (double*)(fragment + 1), vertex_capacity); + fragment->Internal_LayoutArrays(vertex_capacity, (double*)(fragment + 1) ); if (src_fragment.VertexCount() > 0) fragment->CopyFrom(src_fragment,density); diff --git a/opennurbs_subd_texture.cpp b/opennurbs_subd_texture.cpp index cba7e47d..40100857 100644 --- a/opennurbs_subd_texture.cpp +++ b/opennurbs_subd_texture.cpp @@ -1077,23 +1077,35 @@ bool ON_SubD::HasPerFaceColorsFromSymmetryMotif() const #if 1 #pragma region ON_SubDMeshFragment - texture coordinates -bool ON_SubDMeshFragment::TextureCoordinatesExist() const + +void ON_SubDMeshFragment::ClearTextureCoordinates() const +{ + m_vertex_count_etc &= ~ON_SubDMeshFragment::EtcTextureCoordinatesExistBit; + const size_t count = sizeof(this->m_ctrlnetT) / sizeof(this->m_ctrlnetT[0][0]); + double* p = &this->m_ctrlnetT[0][0]; + double* p1 = p + count; + while (p < p1) + *p++ = ON_DBL_QNAN; +} + + +bool ON_SubDMeshFragment::TextureCoordinatesExistForExperts() const { return (0 != (m_vertex_count_etc & ON_SubDMeshFragment::EtcTextureCoordinatesExistBit)); } -void ON_SubDMeshFragment::SetTextureCoordinatesExist(bool bTextureCoordinatesExist) const +void ON_SubDMeshFragment::SetTextureCoordinatesExistForExperts(bool bTextureCoordinatesExist) const { if (bTextureCoordinatesExist) m_vertex_count_etc |= ON_SubDMeshFragment::EtcTextureCoordinatesExistBit; else - m_vertex_count_etc &= ~ON_SubDMeshFragment::EtcTextureCoordinatesExistBit; + ClearTextureCoordinates(); } unsigned int ON_SubDMeshFragment::TextureCoordinateCount() const { - return (TextureCoordinatesExist() && nullptr != m_T && (0 == m_T_stride || m_T_stride >= 3)) ? VertexCount() : 0U; + return (TextureCoordinatesExistForExperts() && nullptr != m_T && (0 == m_T_stride || m_T_stride >= 3)) ? VertexCount() : 0U; } unsigned int ON_SubDMeshFragment::TextureCoordinateCapacity() const @@ -1113,35 +1125,37 @@ size_t ON_SubDMeshFragment::TextureCoordinateArrayStride(ON_SubDComponentLocatio unsigned ON_SubDMeshFragment::TextureCoordinateArrayCount(ON_SubDComponentLocation subd_appearance) const { - return (ON_SubDComponentLocation::ControlNet == subd_appearance) ? (TextureCoordinatesExist()?4U:0U) : TextureCoordinateCount(); + if (false == TextureCoordinatesExistForExperts()) + return 0U; + return (ON_SubDComponentLocation::ControlNet == subd_appearance) ? 4U : TextureCoordinateCount(); } bool ON_SubDMeshFragment::GetTextureCoordinteCorners( bool bGridOrder, - ON_3dPoint texture_coordinate_coeners[4] + ON_3dPoint texture_coordinate_corners[4] ) const { // mutable double m_T_default_bbox[2][2]; - if (nullptr != texture_coordinate_coeners) + if (nullptr != texture_coordinate_corners) { int i; - texture_coordinate_coeners[0].x = m_ctrlnetT[0][0]; - texture_coordinate_coeners[0].y = m_ctrlnetT[0][1]; - texture_coordinate_coeners[0].z = m_ctrlnetT[0][2]; + texture_coordinate_corners[0].x = m_ctrlnetT[0][0]; + texture_coordinate_corners[0].y = m_ctrlnetT[0][1]; + texture_coordinate_corners[0].z = m_ctrlnetT[0][2]; - texture_coordinate_coeners[1].x = m_ctrlnetT[1][0]; - texture_coordinate_coeners[1].y = m_ctrlnetT[1][1]; - texture_coordinate_coeners[1].z = m_ctrlnetT[1][2]; + texture_coordinate_corners[1].x = m_ctrlnetT[1][0]; + texture_coordinate_corners[1].y = m_ctrlnetT[1][1]; + texture_coordinate_corners[1].z = m_ctrlnetT[1][2]; i = bGridOrder ? 2 : 3; - texture_coordinate_coeners[i].x = m_ctrlnetT[2][0]; - texture_coordinate_coeners[i].y = m_ctrlnetT[2][1]; - texture_coordinate_coeners[i].z = m_ctrlnetT[2][2]; + texture_coordinate_corners[i].x = m_ctrlnetT[2][0]; + texture_coordinate_corners[i].y = m_ctrlnetT[2][1]; + texture_coordinate_corners[i].z = m_ctrlnetT[2][2]; i = bGridOrder ? 3 : 2; - texture_coordinate_coeners[i].x = m_ctrlnetT[3][0]; - texture_coordinate_coeners[i].y = m_ctrlnetT[3][1]; - texture_coordinate_coeners[i].z = m_ctrlnetT[3][2]; + texture_coordinate_corners[i].x = m_ctrlnetT[3][0]; + texture_coordinate_corners[i].y = m_ctrlnetT[3][1]; + texture_coordinate_corners[i].z = m_ctrlnetT[3][2]; return true; } @@ -1803,7 +1817,12 @@ void ON_SubDMeshFragment::Internal_SetTextureCoordinatesFromCorners( return; if (corner_dim <= 0) return; - SetTextureCoordinatesExist(true); + if (corner_dim > 3) + corner_dim = 3; + if (nullptr == corner0 || nullptr == corner1 || nullptr == corner2 || nullptr == corner3) + return; + + SetTextureCoordinatesExistForExperts(true); double* T = m_T; const double d = (double)n; double s, t; @@ -1843,6 +1862,7 @@ void ON_SubDMeshFragment::Internal_SetTextureCoordinatesFromCorners( T += m_T_stride; } } + return; } @@ -1875,7 +1895,7 @@ bool ON_SubDMeshFragment::SetVertexTextureCoordinate( T[0] = texture_coordinate.x; T[1] = texture_coordinate.y; T[2] = texture_coordinate.z; - SetTextureCoordinatesExist(true); + SetTextureCoordinatesExistForExperts(true); return true; } diff --git a/opennurbs_xml.cpp b/opennurbs_xml.cpp index aa1edde6..0a901797 100644 --- a/opennurbs_xml.cpp +++ b/opennurbs_xml.cpp @@ -67,13 +67,11 @@ static void MyOutputDebugString(const wchar_t* s) #define OUTPUT_DEBUG_STRING_EOL(x) { } #endif -#define IMPL_CHECK { ON_ASSERT(sizeof(m_Impl) >= (sizeof(CImpl) + sizeof(void*))); } - std::atomic g_lNodeCount(0); std::atomic g_lPropertyCount(-1); // defaultProp below increments this to zero. -#define ON_NAME L"name" -#define ON_PARAMETER L"parameter" +#define ON_NAME L"name" +#define ON_PARAMETER L"parameter" static const wchar_t* wszBase64Prefix = L"base64:"; @@ -251,67 +249,67 @@ static time_t TimeFromString(const ON_wString& sTime) // ON_XMLVariant -class ON_XMLVariant::CImpl final +class ON_XMLVariantPrivate final { public: - CImpl() { } - ~CImpl() { ClearBuffers(); } + ON_XMLVariantPrivate() { } + ~ON_XMLVariantPrivate() { ClearBuffers(); } ON_Buffer& GetBuffer(void) const { - if (nullptr == m_pBuffer) - m_pBuffer = new ON_Buffer; + if (nullptr == _buffer) + _buffer = new ON_Buffer; else - m_pBuffer->SeekFromStart(0); + _buffer->SeekFromStart(0); - return *m_pBuffer; + return *_buffer; } void ClearBuffers(void) { - if (nullptr != m_pBuffer) + if (nullptr != _buffer) { - delete m_pBuffer; - m_pBuffer = nullptr; + delete _buffer; + _buffer = nullptr; } - if (nullptr != m_raw_buffer) + if (nullptr != _raw_buffer) { - delete[] m_raw_buffer; - m_raw_buffer = nullptr; + delete[] _raw_buffer; + _raw_buffer = nullptr; } } const ON_wString& ConvertDoubleToString(double d) const { - auto* buf = m_sVal.SetLength(30); + auto* buf = _string_val.SetLength(30); if (nullptr != buf) { const auto len = ON_wString::FormatIntoBuffer(buf, 24, L"%.15g", d); - m_sVal.SetLength(len); + _string_val.SetLength(len); } - return m_sVal; + return _string_val; } const ON_wString& ConvertDoubleArrayToString(int count) const { constexpr int maxCount = 16; if ((count == 0) || (count > maxCount)) - return m_sVal; + return _string_val; constexpr int maxLen = 30; const auto num_chars = maxLen * maxCount; - auto* buf = m_sVal.SetLength(num_chars); + auto* buf = _string_val.SetLength(num_chars); if (nullptr == buf) - return m_sVal; + return _string_val; int totalLen = 0; auto* p = buf; for (int i = 0; i < count; i++) { - const auto len = ON_wString::FormatIntoBuffer(p, maxLen, L"%.15g", m_aVal[i]); + const auto len = ON_wString::FormatIntoBuffer(p, maxLen, L"%.15g", _array_val[i]); p += len; *p++ = L','; totalLen += len + 1; @@ -324,182 +322,182 @@ public: buf[length] = 0; } - m_sVal.SetLength(length); + _string_val.SetLength(length); - return m_sVal; + return _string_val; } - mutable ON_Buffer* m_pBuffer = nullptr; - mutable ON_wString m_sVal; + mutable ON_Buffer* _buffer = nullptr; + mutable ON_wString _string_val; union { - bool m_bVal; - int m_iVal; - float m_fVal; - double m_dVal; - double m_aVal[16]; + bool _bool_val; + int _int_val; + float _float_val; + double _double_val; ON_Xform m_xform; - time_t m_timeVal; - ON_UUID m_uuidVal; + time_t _time_val; + ON_UUID _uuid_val; + double _array_val[16] = { 0 }; }; - ON::LengthUnitSystem m_units = ON::LengthUnitSystem::None; - ON__UINT8* m_raw_buffer = nullptr; - bool m_bTypePending = false; - bool m_bVaries = false; - Types m_type = Types::Null; + ON::LengthUnitSystem _units = ON::LengthUnitSystem::None; + ON__UINT8* _raw_buffer = nullptr; + bool _type_pending = false; + bool _varies = false; + ON_XMLVariant::Types _type = ON_XMLVariant::Types::Null; }; ON_XMLVariant::ON_XMLVariant() { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); } ON_XMLVariant::ON_XMLVariant(int iValue) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(iValue); } ON_XMLVariant::ON_XMLVariant(double dValue) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(dValue); } ON_XMLVariant::ON_XMLVariant(float fValue) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(fValue); } ON_XMLVariant::ON_XMLVariant(const ON_wString& s) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(s); } ON_XMLVariant::ON_XMLVariant(const double* point, ArrayTypes at) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(point, at); } ON_XMLVariant::ON_XMLVariant(const float* point, ArrayTypes at) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(point, at); } ON_XMLVariant::ON_XMLVariant(const wchar_t* wsz) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); ON_wString s(wsz); SetValue(s); } ON_XMLVariant::ON_XMLVariant(const ON_2dPoint& p) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(p); } ON_XMLVariant::ON_XMLVariant(const ON_3dPoint& p) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(p); } ON_XMLVariant::ON_XMLVariant(const ON_4fColor& c) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(c); } ON_XMLVariant::ON_XMLVariant(bool b) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(b); } ON_XMLVariant::ON_XMLVariant(const ON_UUID& uuid) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(uuid); } ON_XMLVariant::ON_XMLVariant(const ON_Xform& xform) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(xform); } ON_XMLVariant::ON_XMLVariant(time_t time) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(time); } ON_XMLVariant::ON_XMLVariant(const void* pBuffer, size_t size) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(pBuffer, size); } ON_XMLVariant::ON_XMLVariant(const ON_Buffer& buffer) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); SetValue(buffer); } ON_XMLVariant::ON_XMLVariant(const ON_XMLVariant& src) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLVariantPrivate; PRIVATE_CHECK(ON_XMLVariantPrivate); *this = src; } ON_XMLVariant::~ON_XMLVariant() { - m_impl->~CImpl(); - m_impl = nullptr; + _private->~ON_XMLVariantPrivate(); + _private = nullptr; } ON_Buffer& ON_XMLVariant::GetBuffer(void) const { - return m_impl->GetBuffer(); + return _private->GetBuffer(); } void ON_XMLVariant::ClearBuffers(void) { - m_impl->ClearBuffers(); + _private->ClearBuffers(); } const ON_XMLVariant& ON_XMLVariant::operator = (const ON_XMLVariant& src) { - m_impl->m_type = src.Type(); - m_impl->m_bTypePending = src.TypePending(); + _private->_type = src.Type(); + _private->_type_pending = src.TypePending(); - if (m_impl->m_type != Types::Buffer) + if (_private->_type != Types::Buffer) { ClearBuffers(); } - switch (m_impl->m_type) + switch (_private->_type) { - case Types::Null: break; - case Types::Bool: m_impl->m_bVal = src.AsBool(); break; - case Types::Integer: m_impl->m_iVal = src.AsInteger(); break; - case Types::Float: m_impl->m_fVal = src.AsFloat(); break; - case Types::Double: m_impl->m_dVal = src.AsDouble(); break; - case Types::String: m_impl->m_sVal = src.AsString(); break; - case Types::Uuid: m_impl->m_uuidVal = src.AsUuid(); break; - case Types::Time: m_impl->m_timeVal = src.AsTime(); break; - case Types::DoubleArray2: SetValue(src.As2dPoint()); break; - case Types::DoubleArray3: SetValue(src.As3dPoint()); break; - case Types::DoubleArray4: SetValue(src.As4dPoint()); break; - case Types::DoubleColor4: SetValue(src.AsColor()); break; - case Types::Matrix: SetValue(src.AsXform()) ; break; - case Types::Buffer: GetBuffer() = src.AsBuffer(); break; + case Types::Null: break; + case Types::Bool: _private->_bool_val = src.AsBool(); break; + case Types::Integer: _private->_int_val = src.AsInteger(); break; + case Types::Float: _private->_float_val = src.AsFloat(); break; + case Types::Double: _private->_double_val = src.AsDouble(); break; + case Types::String: _private->_string_val = src.AsString(); break; + case Types::Uuid: _private->_uuid_val = src.AsUuid(); break; + case Types::Time: _private->_time_val = src.AsTime(); break; + case Types::DoubleArray2: SetValue(src.As2dPoint()); break; + case Types::DoubleArray3: SetValue(src.As3dPoint()); break; + case Types::DoubleArray4: SetValue(src.As4dPoint()); break; + case Types::DoubleColor4: SetValue(src.AsColor()); break; + case Types::Matrix: SetValue(src.AsXform()) ; break; + case Types::Buffer: GetBuffer() = src.AsBuffer(); break; default: OUTPUT_DEBUG_STRING(L"ON_XMLVariant: Source has unknown type\n"); @@ -508,64 +506,65 @@ const ON_XMLVariant& ON_XMLVariant::operator = (const ON_XMLVariant& src) // The above calls can reset the type pending flag on the source. // Make sure the source is set back to the original condition. - src.SetTypePendingFlag(m_impl->m_bTypePending); + src.SetTypePendingFlag(_private->_type_pending); return *this; } bool ON_XMLVariant::operator == (const ON_XMLVariant& v) const { - if (m_impl->m_type != v.m_impl->m_type) + if (_private->_type != v._private->_type) return false; - if (m_impl->m_units != v.m_impl->m_units) + if (_private->_units != v._private->_units) return false; - switch (m_impl->m_type) + switch (_private->_type) { case Types::Bool: - return m_impl->m_bVal == v.m_impl->m_bVal; + return _private->_bool_val == v._private->_bool_val; case Types::Integer: - return m_impl->m_iVal == v.m_impl->m_iVal; + return _private->_int_val == v._private->_int_val; case Types::Float: - return IsFloatEqual(m_impl->m_fVal, v.m_impl->m_fVal) ? true : false; + return IsFloatEqual(_private->_float_val, v._private->_float_val) ? true : false; case Types::Double: - return IsDoubleEqual(m_impl->m_dVal, v.m_impl->m_dVal) ? true : false; + return IsDoubleEqual(_private->_double_val, v._private->_double_val) ? true : false; case Types::DoubleArray2: - return ((IsDoubleEqual(m_impl->m_aVal[0], v.m_impl->m_aVal[0])) && - (IsDoubleEqual(m_impl->m_aVal[1], v.m_impl->m_aVal[1]))) ? true : false; + return ((IsDoubleEqual(_private->_array_val[0], v._private->_array_val[0])) && + (IsDoubleEqual(_private->_array_val[1], v._private->_array_val[1]))) ? true : false; case Types::DoubleArray3: - return ((IsDoubleEqual(m_impl->m_aVal[0], v.m_impl->m_aVal[0])) && - (IsDoubleEqual(m_impl->m_aVal[1], v.m_impl->m_aVal[1])) && - (IsDoubleEqual(m_impl->m_aVal[2], v.m_impl->m_aVal[2]))) ? true : false; + return ((IsDoubleEqual(_private->_array_val[0], v._private->_array_val[0])) && + (IsDoubleEqual(_private->_array_val[1], v._private->_array_val[1])) && + (IsDoubleEqual(_private->_array_val[2], v._private->_array_val[2]))) ? true : false; case Types::DoubleColor4: case Types::DoubleArray4: - return ((IsDoubleEqual(m_impl->m_aVal[0], v.m_impl->m_aVal[0])) && - (IsDoubleEqual(m_impl->m_aVal[1], v.m_impl->m_aVal[1])) && - (IsDoubleEqual(m_impl->m_aVal[2], v.m_impl->m_aVal[2])) && - (IsDoubleEqual(m_impl->m_aVal[3], v.m_impl->m_aVal[3]))) ? true : false; + return ((IsDoubleEqual(_private->_array_val[0], v._private->_array_val[0])) && + (IsDoubleEqual(_private->_array_val[1], v._private->_array_val[1])) && + (IsDoubleEqual(_private->_array_val[2], v._private->_array_val[2])) && + (IsDoubleEqual(_private->_array_val[3], v._private->_array_val[3]))) ? true : false; case Types::String: - return m_impl->m_sVal.CompareNoCase(v.m_impl->m_sVal) == 0; + return _private->_string_val.CompareNoCase(v._private->_string_val) == 0; case Types::Uuid: - return (m_impl->m_uuidVal == v.m_impl->m_uuidVal) ? true : false; + return (_private->_uuid_val == v._private->_uuid_val) ? true : false; case Types::Time: - return m_impl->m_timeVal == v.m_impl->m_timeVal; + return _private->_time_val == v._private->_time_val; case Types::Matrix: for (int i = 0; i < 16; i++) { - if (m_impl->m_aVal[i] != v.m_impl->m_aVal[i]) + if (_private->_array_val[i] != v._private->_array_val[i]) return false; } + case Types::Null: return true; default: @@ -582,7 +581,7 @@ bool ON_XMLVariant::operator != (const ON_XMLVariant& v) const bool ON_XMLVariant::NeedsXMLEncode(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::Null: case Types::Bool: @@ -611,52 +610,52 @@ bool ON_XMLVariant::NeedsXMLEncode(void) const void ON_XMLVariant::SetNull() { - m_impl->m_type = Types::Null; + _private->_type = Types::Null; } void ON_XMLVariant::SetValue(int v) { ClearBuffers(); - m_impl->m_type = Types::Integer; - m_impl->m_iVal = v; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_type = Types::Integer; + _private->_int_val = v; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(double v) { ClearBuffers(); - m_impl->m_type = Types::Double; - m_impl->m_dVal = v; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_type = Types::Double; + _private->_double_val = v; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(float v) { ClearBuffers(); - m_impl->m_type = Types::Float; - m_impl->m_fVal = v; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_type = Types::Float; + _private->_float_val = v; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const wchar_t* s) { ClearBuffers(); - m_impl->m_type = Types::String; - m_impl->m_sVal = s; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_type = Types::String; + _private->_string_val = s; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const ON_wString& s) { ClearBuffers(); - m_impl->m_type = Types::String; - m_impl->m_sVal = s; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_type = Types::String; + _private->_string_val = s; + _private->_varies = false; + _private->_type_pending = false; } inline static void Fill(double* a, const double* b, int count) @@ -681,14 +680,14 @@ void ON_XMLVariant::SetValue(const double* p, ArrayTypes at) switch (at) { - case ArrayTypes::Array2: m_impl->m_type = Types::DoubleArray2; Fill(m_impl->m_aVal, p, 2); break; - case ArrayTypes::Array3: m_impl->m_type = Types::DoubleArray3; Fill(m_impl->m_aVal, p, 3); break; - case ArrayTypes::Array4: m_impl->m_type = Types::DoubleArray4; Fill(m_impl->m_aVal, p, 4); break; - case ArrayTypes::Array16: m_impl->m_type = Types::Matrix; Fill(m_impl->m_aVal, p, 16); break; + case ArrayTypes::Array2: _private->_type = Types::DoubleArray2; Fill(_private->_array_val, p, 2); break; + case ArrayTypes::Array3: _private->_type = Types::DoubleArray3; Fill(_private->_array_val, p, 3); break; + case ArrayTypes::Array4: _private->_type = Types::DoubleArray4; Fill(_private->_array_val, p, 4); break; + case ArrayTypes::Array16: _private->_type = Types::Matrix; Fill(_private->_array_val, p, 16); break; } - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const float* p, ArrayTypes at) @@ -697,124 +696,124 @@ void ON_XMLVariant::SetValue(const float* p, ArrayTypes at) switch (at) { - case ArrayTypes::Array2: m_impl->m_type = Types::DoubleArray2; Fill(m_impl->m_aVal, p, 2); break; - case ArrayTypes::Array3: m_impl->m_type = Types::DoubleArray3; Fill(m_impl->m_aVal, p, 3); break; - case ArrayTypes::Array4: m_impl->m_type = Types::DoubleArray4; Fill(m_impl->m_aVal, p, 4); break; - case ArrayTypes::Array16: m_impl->m_type = Types::Matrix; Fill(m_impl->m_aVal, p, 16); break; + case ArrayTypes::Array2: _private->_type = Types::DoubleArray2; Fill(_private->_array_val, p, 2); break; + case ArrayTypes::Array3: _private->_type = Types::DoubleArray3; Fill(_private->_array_val, p, 3); break; + case ArrayTypes::Array4: _private->_type = Types::DoubleArray4; Fill(_private->_array_val, p, 4); break; + case ArrayTypes::Array16: _private->_type = Types::Matrix; Fill(_private->_array_val, p, 16); break; } - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const ON_2dPoint& v) { ClearBuffers(); - m_impl->m_type = Types::DoubleArray2; + _private->_type = Types::DoubleArray2; - m_impl->m_aVal[0] = v.x; - m_impl->m_aVal[1] = v.y; + _private->_array_val[0] = v.x; + _private->_array_val[1] = v.y; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const ON_3dPoint& v) { ClearBuffers(); - m_impl->m_type = Types::DoubleArray3; + _private->_type = Types::DoubleArray3; - m_impl->m_aVal[0] = v.x; - m_impl->m_aVal[1] = v.y; - m_impl->m_aVal[2] = v.z; + _private->_array_val[0] = v.x; + _private->_array_val[1] = v.y; + _private->_array_val[2] = v.z; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const ON_4dPoint& p) { ClearBuffers(); - m_impl->m_type = Types::DoubleArray4; + _private->_type = Types::DoubleArray4; - m_impl->m_aVal[0] = p.x; - m_impl->m_aVal[1] = p.y; - m_impl->m_aVal[2] = p.z; - m_impl->m_aVal[3] = p.w; + _private->_array_val[0] = p.x; + _private->_array_val[1] = p.y; + _private->_array_val[2] = p.z; + _private->_array_val[3] = p.w; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const ON_4fColor& c) { ClearBuffers(); - m_impl->m_type = Types::DoubleColor4; + _private->_type = Types::DoubleColor4; - m_impl->m_aVal[0] = c.Red(); - m_impl->m_aVal[1] = c.Green(); - m_impl->m_aVal[2] = c.Blue(); - m_impl->m_aVal[3] = c.Alpha(); + _private->_array_val[0] = c.Red(); + _private->_array_val[1] = c.Green(); + _private->_array_val[2] = c.Blue(); + _private->_array_val[3] = c.Alpha(); - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(bool b) { ClearBuffers(); - m_impl->m_type = Types::Bool; + _private->_type = Types::Bool; - m_impl->m_bVal = b; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_bool_val = b; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const ON_UUID& uuid) { ClearBuffers(); - m_impl->m_type = Types::Uuid; + _private->_type = Types::Uuid; - m_impl->m_uuidVal = uuid; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_uuid_val = uuid; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(time_t time) { ClearBuffers(); - m_impl->m_type = Types::Time; + _private->_type = Types::Time; - m_impl->m_timeVal = time; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_time_val = time; + _private->_varies = false; + _private->_type_pending = false; } void ON_XMLVariant::SetValue(const void* pBuffer, size_t size) { ClearBuffers(); - m_impl->m_type = Types::Buffer; + _private->_type = Types::Buffer; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; GetBuffer().Write(size, pBuffer); } void ON_XMLVariant::SetValue(const ON_Buffer& buffer) { - m_impl->m_type = Types::Buffer; + _private->_type = Types::Buffer; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->_varies = false; + _private->_type_pending = false; GetBuffer() = buffer; } @@ -823,27 +822,27 @@ void ON_XMLVariant::SetValue(const ON_Xform& xform) { ClearBuffers(); - m_impl->m_type = Types::Matrix; + _private->_type = Types::Matrix; - m_impl->m_xform = xform; - m_impl->m_bVaries = false; - m_impl->m_bTypePending = false; + _private->m_xform = xform; + _private->_varies = false; + _private->_type_pending = false; } bool ON_XMLVariant::AsBool(void) const { - switch (m_impl->m_type) + switch (_private->_type) { - case Types::Bool: return m_impl->m_bVal; - case Types::Integer: return m_impl->m_iVal != 0; - case Types::Double: return m_impl->m_dVal != 0; - case Types::Float: return m_impl->m_fVal != 0; + case Types::Bool: return _private->_bool_val; + case Types::Integer: return _private->_int_val != 0; + case Types::Double: return _private->_double_val != 0; + case Types::Float: return _private->_float_val != 0; case Types::String: - if (m_impl->m_sVal.CompareNoCase(L"true") == 0) return true; - if (m_impl->m_sVal.CompareNoCase(L"t") == 0) return true; - return ON_wtoi(m_impl->m_sVal) != 0; - + if (_private->_string_val.CompareNoCase(L"true") == 0) return true; + if (_private->_string_val.CompareNoCase(L"t") == 0) return true; + return ON_wtoi(_private->_string_val) != 0; + default: return false; } @@ -851,17 +850,17 @@ bool ON_XMLVariant::AsBool(void) const int ON_XMLVariant::AsInteger(void) const { - switch (m_impl->m_type) + switch (_private->_type) { - case Types::Bool: return m_impl->m_bVal ? 1 : 0; - case Types::Integer: return m_impl->m_iVal; - case Types::Double: return int(m_impl->m_dVal); - case Types::Float: return int(m_impl->m_fVal); + case Types::Bool: return _private->_bool_val ? 1 : 0; + case Types::Integer: return _private->_int_val; + case Types::Double: return int(_private->_double_val); + case Types::Float: return int(_private->_float_val); case Types::String: - if (m_impl->m_sVal.CompareNoCase(L"true") == 0) return 1; - if (m_impl->m_sVal.CompareNoCase(L"t") == 0) return true; - return ON_wtoi(m_impl->m_sVal); + if (_private->_string_val.CompareNoCase(L"true") == 0) return 1; + if (_private->_string_val.CompareNoCase(L"t") == 0) return true; + return ON_wtoi(_private->_string_val); default: return 0; @@ -870,13 +869,13 @@ int ON_XMLVariant::AsInteger(void) const double ON_XMLVariant::AsDouble(void) const { - switch (m_impl->m_type) + switch (_private->_type) { - case Types::Bool: return m_impl->m_bVal ? 1.0 : 0.0; - case Types::Float: return m_impl->m_fVal; - case Types::Double: return m_impl->m_dVal; - case Types::Integer: return double (m_impl->m_iVal); - case Types::String: return ON_wtof(m_impl->m_sVal); + case Types::Bool: return _private->_bool_val ? 1.0 : 0.0; + case Types::Float: return _private->_float_val; + case Types::Double: return _private->_double_val; + case Types::Integer: return double (_private->_int_val); + case Types::String: return ON_wtof(_private->_string_val); default: return 0.0; @@ -885,13 +884,13 @@ double ON_XMLVariant::AsDouble(void) const float ON_XMLVariant::AsFloat(void) const { - switch (m_impl->m_type) + switch (_private->_type) { - case Types::Bool: return m_impl->m_bVal ? 1.0f : 0.0f; - case Types::Float: return m_impl->m_fVal; - case Types::Double: return float(m_impl->m_dVal); - case Types::Integer: return float(m_impl->m_iVal); - case Types::String: return float(ON_wtof(m_impl->m_sVal)); + case Types::Bool: return _private->_bool_val ? 1.0f : 0.0f; + case Types::Float: return _private->_float_val; + case Types::Double: return float(_private->_double_val); + case Types::Integer: return float(_private->_int_val); + case Types::String: return float(ON_wtof(_private->_string_val)); default: return 0.0f; @@ -900,7 +899,7 @@ float ON_XMLVariant::AsFloat(void) const ON_2dPoint ON_XMLVariant::As2dPoint(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::DoubleArray2: case Types::DoubleArray3: @@ -909,7 +908,7 @@ ON_2dPoint ON_XMLVariant::As2dPoint(void) const break; case Types::String: - if (m_impl->m_sVal.IsValid2dPoint()) + if (_private->_string_val.IsValid2dPoint()) StringToPoint(2); break; @@ -917,15 +916,15 @@ ON_2dPoint ON_XMLVariant::As2dPoint(void) const return ON_2dPoint::Origin; } - return ON_2dPoint(m_impl->m_aVal[0], m_impl->m_aVal[1]); + return ON_2dPoint(_private->_array_val[0], _private->_array_val[1]); } ON_3dPoint ON_XMLVariant::As3dPoint(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::DoubleArray2: - m_impl->m_aVal[2] = 0.0; + _private->_array_val[2] = 0.0; break; case Types::DoubleArray3: @@ -934,7 +933,7 @@ ON_3dPoint ON_XMLVariant::As3dPoint(void) const break; case Types::String: - if (m_impl->m_sVal.IsValid3dPoint()) + if (_private->_string_val.IsValid3dPoint()) StringToPoint(3); break; @@ -942,17 +941,17 @@ ON_3dPoint ON_XMLVariant::As3dPoint(void) const return ON_3dPoint::Origin; } - return ON_3dPoint(m_impl->m_aVal[0], m_impl->m_aVal[1], m_impl->m_aVal[2]); + return ON_3dPoint(_private->_array_val[0], _private->_array_val[1], _private->_array_val[2]); } ON_4dPoint ON_XMLVariant::As4dPoint(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::DoubleArray2: - m_impl->m_aVal[2] = 0.0; + _private->_array_val[2] = 0.0; case Types::DoubleArray3: - m_impl->m_aVal[3] = 0.0; + _private->_array_val[3] = 0.0; break; case Types::DoubleArray4: @@ -960,7 +959,7 @@ ON_4dPoint ON_XMLVariant::As4dPoint(void) const break; case Types::String: - if (m_impl->m_sVal.IsValid4dPoint()) + if (_private->_string_val.IsValid4dPoint()) StringToPoint(4); break; @@ -968,18 +967,18 @@ ON_4dPoint ON_XMLVariant::As4dPoint(void) const return ON_4dPoint::Zero; } - return ON_4dPoint(m_impl->m_aVal[0], m_impl->m_aVal[1], m_impl->m_aVal[2], m_impl->m_aVal[3]); + return ON_4dPoint(_private->_array_val[0], _private->_array_val[1], _private->_array_val[2], _private->_array_val[3]); } ON_Xform ON_XMLVariant::AsXform(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::Matrix: break; case Types::String: - if (m_impl->m_sVal.IsValidMatrix()) + if (_private->_string_val.IsValidMatrix()) StringToPoint(16); //////////////////////////////////// Risky break; @@ -987,21 +986,21 @@ ON_Xform ON_XMLVariant::AsXform(void) const return ON_Xform::Zero4x4; } - return m_impl->m_xform; + return _private->m_xform; } ON_4fColor ON_XMLVariant::AsColor(void) const { ON_4fColor col(ON_Color(0, 0, 0, 0)); - switch (m_impl->m_type) + switch (_private->_type) { case Types::String: StringToPoint(4); // No break... case Types::DoubleArray4: case Types::DoubleColor4: - col.SetRGBA(float(m_impl->m_aVal[0]), float(m_impl->m_aVal[1]), float(m_impl->m_aVal[2]), float(m_impl->m_aVal[3])); + col.SetRGBA(float(_private->_array_val[0]), float(_private->_array_val[1]), float(_private->_array_val[2]), float(_private->_array_val[3])); default: break; @@ -1012,13 +1011,13 @@ ON_4fColor ON_XMLVariant::AsColor(void) const ON_UUID ON_XMLVariant::AsUuid(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::String: - return ON_UuidFromString(m_impl->m_sVal); + return ON_UuidFromString(_private->_string_val); case Types::Uuid: - return m_impl->m_uuidVal; + return _private->_uuid_val; default: return ON_nil_uuid; @@ -1027,13 +1026,13 @@ ON_UUID ON_XMLVariant::AsUuid(void) const time_t ON_XMLVariant::AsTime(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::String: - return TimeFromString(m_impl->m_sVal); + return TimeFromString(_private->_string_val); case Types::Time: - return m_impl->m_timeVal; + return _private->_time_val; default: return 0; } @@ -1046,14 +1045,14 @@ ON_Buffer ON_XMLVariant::AsBuffer(void) const #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wswitch" #endif - switch (m_impl->m_type) + switch (_private->_type) { case Types::Buffer: buf = GetBuffer(); break; case Types::String: - auto& s = m_impl->m_sVal; + auto& s = _private->_string_val; if (s.StartsWithNoCase(wszBase64Prefix) && (s != wszBase64Prefix)) { // Base64 is about 33% bigger than the resulting data so the string length is always enough. @@ -1077,66 +1076,66 @@ void* ON_XMLVariant::AsBuffer(size_t& size_out) const auto buf = AsBuffer(); size_out = buf.Size(); - if (nullptr != m_impl->m_raw_buffer) - delete[] m_impl->m_raw_buffer; + if (nullptr != _private->_raw_buffer) + delete[] _private->_raw_buffer; - m_impl->m_raw_buffer = new ON__UINT8[size_out]; - buf.Read(size_out, m_impl->m_raw_buffer); + _private->_raw_buffer = new ON__UINT8[size_out]; + buf.Read(size_out, _private->_raw_buffer); - return m_impl->m_raw_buffer; + return _private->_raw_buffer; } ON_wString ON_XMLVariant::AsString(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::Integer: - return m_impl->ConvertDoubleToString(double(m_impl->m_iVal)); + return _private->ConvertDoubleToString(double(_private->_int_val)); case Types::Float: - return m_impl->ConvertDoubleToString(double(m_impl->m_fVal)); + return _private->ConvertDoubleToString(double(_private->_float_val)); case Types::Double: - return m_impl->ConvertDoubleToString(m_impl->m_dVal); + return _private->ConvertDoubleToString(_private->_double_val); case Types::DoubleArray3: - return m_impl->ConvertDoubleArrayToString(3); + return _private->ConvertDoubleArrayToString(3); case Types::DoubleArray4: case Types::DoubleColor4: - return m_impl->ConvertDoubleArrayToString(4); + return _private->ConvertDoubleArrayToString(4); case Types::DoubleArray2: - return m_impl->ConvertDoubleArrayToString(2); + return _private->ConvertDoubleArrayToString(2); case Types::Matrix: - return m_impl->ConvertDoubleArrayToString(16); + return _private->ConvertDoubleArrayToString(16); case Types::Bool: - m_impl->m_sVal = m_impl->m_bVal ? L"true" : L"false"; + _private->_string_val = _private->_bool_val ? L"true" : L"false"; // No break... case Types::String: - return m_impl->m_sVal; + return _private->_string_val; case Types::Uuid: - ON_UuidToString(m_impl->m_uuidVal, m_impl->m_sVal); - m_impl->m_sVal.MakeUpperOrdinal(); - return m_impl->m_sVal; + ON_UuidToString(_private->_uuid_val, _private->_string_val); + _private->_string_val.MakeUpperOrdinal(); + return _private->_string_val; case Types::Time: - m_impl->m_sVal = TimeToString(m_impl->m_timeVal); - return m_impl->m_sVal; + _private->_string_val = TimeToString(_private->_time_val); + return _private->_string_val; case Types::Buffer: { - m_impl->m_sVal = wszBase64Prefix; + _private->_string_val = wszBase64Prefix; auto& buffer = GetBuffer(); const auto buf_size = buffer.Size(); auto* buf = new char[buf_size]; buffer.Read(buf_size, buf); - ON_Base64::Encode(buf, buf_size, m_impl->m_sVal, true); + ON_Base64::Encode(buf, buf_size, _private->_string_val, true); delete[] buf; - return m_impl->m_sVal; + return _private->_string_val; } case Types::Null: @@ -1212,7 +1211,7 @@ void ON_XMLVariant::StringToPoint(int numValues) const if ((numValues < 0) || (numValues > 16)) return; - ON_wString s = m_impl->m_sVal + L",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"; + ON_wString s = _private->_string_val + L",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"; auto* p = s.Array(); for (int i = 0; i < numValues; i++) @@ -1222,7 +1221,7 @@ void ON_XMLVariant::StringToPoint(int numValues) const p++; } - m_impl->m_aVal[i] = ON_wtof(p); + _private->_array_val[i] = ON_wtof(p); while (*p != L',') { @@ -1235,12 +1234,12 @@ void ON_XMLVariant::StringToPoint(int numValues) const ON_XMLVariant::Types ON_XMLVariant::Type(void) const { - return m_impl->m_type; + return _private->_type; } bool ON_XMLVariant::IsNull(void) const { - return Types::Null == m_impl->m_type; + return Types::Null == _private->_type; } bool ON_XMLVariant::IsEmpty(void) const @@ -1250,7 +1249,7 @@ bool ON_XMLVariant::IsEmpty(void) const bool ON_XMLVariant::Varies(void) const { - return m_impl->m_bVaries; + return _private->_varies; } void ON_XMLVariant::SetVaries(void) @@ -1261,33 +1260,33 @@ void ON_XMLVariant::SetVaries(void) } else { - m_impl->m_bVaries = true; + _private->_varies = true; } } ON::LengthUnitSystem ON_XMLVariant::Units(void) const { - return m_impl->m_units; + return _private->_units; } void ON_XMLVariant::SetUnits(ON::LengthUnitSystem units) { - m_impl->m_units = units; + _private->_units = units; } bool ON_XMLVariant::TypePending(void) const { - return m_impl->m_bTypePending; + return _private->_type_pending; } void ON_XMLVariant::SetTypePendingFlag(bool bTypePending) const { - m_impl->m_bTypePending = bTypePending; + _private->_type_pending = bTypePending; } ON_wString ON_XMLVariant::TypeAsString(void) const { - switch (m_impl->m_type) + switch (_private->_type) { case Types::Bool: return L"bool"; case Types::Integer: return L"integer"; @@ -1323,28 +1322,28 @@ ON__UINT32 ON_XMLVariant::DataCRC(ON__UINT32 crc) const return crc; case Types::Double: - return CRCReal(crc, m_impl->m_dVal); + return CRCReal(crc, _private->_double_val); case Types::Float: - return CRCReal(crc, m_impl->m_fVal); + return CRCReal(crc, _private->_float_val); case Types::Integer: { - const auto x = m_impl->m_iVal; + const auto x = _private->_int_val; return ON_CRC32(crc, sizeof(x), &x); } case Types::DoubleArray2: { ON__INT64 x[2] = { 0 }; - for (int i = 0; i < 2; i++) x[i] = Integerize(m_impl->m_aVal[i]); + for (int i = 0; i < 2; i++) x[i] = Integerize(_private->_array_val[i]); return ON_CRC32(crc, sizeof(x), &x); } case Types::DoubleArray3: { ON__INT64 x[3] = { 0 }; - for (int i = 0; i < 3; i++) x[i] = Integerize(m_impl->m_aVal[i]); + for (int i = 0; i < 3; i++) x[i] = Integerize(_private->_array_val[i]); return ON_CRC32(crc, sizeof(x), &x); } @@ -1352,7 +1351,7 @@ ON__UINT32 ON_XMLVariant::DataCRC(ON__UINT32 crc) const case Types::DoubleColor4: { ON__INT64 x[4] = { 0 }; - for (int i = 0; i < 4; i++) x[i] = Integerize(m_impl->m_aVal[i]); + for (int i = 0; i < 4; i++) x[i] = Integerize(_private->_array_val[i]); return ON_CRC32(crc, sizeof(x), &x); } @@ -1362,25 +1361,25 @@ ON__UINT32 ON_XMLVariant::DataCRC(ON__UINT32 crc) const ON__INT64 x[16] = { 0 }; for (int j = 0; j < 4; j++) for (int i = 0; i < 4; i++) - x[index++] = Integerize(m_impl->m_xform.m_xform[i][j]); + x[index++] = Integerize(_private->m_xform.m_xform[i][j]); return ON_CRC32(crc, sizeof(x), &x); } case Types::Bool: { - const auto x = m_impl->m_bVal; + const auto x = _private->_bool_val; return ON_CRC32(crc, sizeof(x), &x); } case Types::Uuid: { - const auto u = m_impl->m_uuidVal; + const auto u = _private->_uuid_val; return ON_CRC32(crc, sizeof(u), &u); } case Types::Time: { - const auto t = m_impl->m_timeVal; + const auto t = _private->_time_val; return ON_CRC32(crc, sizeof(t), &t); } @@ -1398,7 +1397,7 @@ void ON_XMLVariant::Format(ON_wString& sOut) const { ON_wString sType; - switch (m_impl->m_type) + switch (_private->_type) { case Types::Null: sOut = "[null]"; @@ -1521,143 +1520,170 @@ void CPropertyData::SetHugeStringValue(const ON_wString& s) m_value.SetValue(s); } -class ON_XMLProperty::CImpl final +class ON_XMLPropertyPrivate final { public: - CImpl() { m_data = new CPropertyData; } - CImpl(const ON_XMLVariant& sValue) { m_data = new CPropertyData(sValue); } - CImpl(const ON_wString& sName, const ON_XMLVariant& value) { m_data = new CPropertyData(sName, value); } - CImpl(const ON_XMLProperty& prop) { prop.Impl().m_data->AddRef(); m_data = prop.Impl().m_data; } - ~CImpl() { m_data->Release(); } + ON_XMLPropertyPrivate(); + ON_XMLPropertyPrivate(const ON_XMLVariant& sValue); + ON_XMLPropertyPrivate(const ON_wString& sName, const ON_XMLVariant& value); + ON_XMLPropertyPrivate(const ON_XMLProperty& prop); + ~ON_XMLPropertyPrivate(); - const ON_wString& Name(void) const { return m_data->Name(); } - void SetName(const wchar_t* wsz) { CopyOnWrite(); m_data->SetName(wsz); } + const ON_wString& Name(void) const { return _data->Name(); } + void SetName(const wchar_t* wsz) { CopyOnWrite(); _data->SetName(wsz); } - ON__UINT32 DataCRC(ON__UINT32 crc) const { return m_data->DataCRC(crc); } + ON__UINT32 DataCRC(ON__UINT32 crc) const { return _data->DataCRC(crc); } - bool operator < (const ON_XMLProperty& prop) const { return m_data->operator < (*prop.Impl().m_data); } + bool operator < (const ON_XMLProperty& prop) const; + void operator = (const ON_XMLPropertyPrivate& pimpl); - void operator = (const ON_XMLProperty::CImpl& pimpl) - { - if (nullptr != pimpl.m_data) - { - pimpl.m_data->AddRef(); - } + bool IsDefaultProperty(void) const { return _data->IsDefaultProperty(); } + const ON_XMLVariant& GetValue(void) const { return _data->GetValue(); } + ON_XMLVariant& GetNonConstValue(void) { CopyOnWrite(); return _data->m_value; } + void SetValue(const ON_XMLVariant& value) { CopyOnWrite(); _data->SetValue(value); } + void SetHugeStringValue(const ON_wString& s) { CopyOnWrite(); _data->SetHugeStringValue(s); } + void CopyOnWrite(void); - if (nullptr != m_data) - { - m_data->Release(); - } - - m_data = pimpl.m_data; - } - - bool IsDefaultProperty(void) const { return m_data->IsDefaultProperty(); } - const ON_XMLVariant& GetValue(void) const { return m_data->GetValue(); } - ON_XMLVariant& GetNonConstValue(void) { CopyOnWrite(); return m_data->m_value; } - void SetValue(const ON_XMLVariant& value) { CopyOnWrite(); m_data->SetValue(value); } - void SetHugeStringValue(const ON_wString& s) { CopyOnWrite(); m_data->SetHugeStringValue(s); } - - void CopyOnWrite(void) - { - if (m_data->m_iRefCount > 1) - { - auto* pData = new CPropertyData(*m_data); - m_data->Release(); - m_data = pData; - } - } - - CPropertyData* m_data = nullptr; - ON_XMLNode* m_owner = nullptr; - ON_XMLProperty* m_pNext = nullptr; + CPropertyData* _data = nullptr; + ON_XMLNode* _owner = nullptr; + ON_XMLProperty* _next = nullptr; }; +ON_XMLPropertyPrivate::ON_XMLPropertyPrivate() +{ + _data = new CPropertyData; +} + +ON_XMLPropertyPrivate::ON_XMLPropertyPrivate(const ON_XMLVariant& sValue) +{ + _data = new CPropertyData(sValue); +} + +ON_XMLPropertyPrivate::ON_XMLPropertyPrivate(const ON_wString& sName, const ON_XMLVariant& value) +{ + _data = new CPropertyData(sName, value); +} + +ON_XMLPropertyPrivate::ON_XMLPropertyPrivate(const ON_XMLProperty& prop) +{ + prop._private->_data->AddRef(); + _data = prop._private->_data; +} + +ON_XMLPropertyPrivate::~ON_XMLPropertyPrivate() +{ + _data->Release(); +} + +bool ON_XMLPropertyPrivate::operator < (const ON_XMLProperty& prop) const +{ + return _data->operator < (*prop._private->_data); +} + +void ON_XMLPropertyPrivate::operator = (const ON_XMLPropertyPrivate& other) +{ + if (&other == this) + return; + + ON_ASSERT(nullptr != _data); + ON_ASSERT(nullptr != other._data); + + other._data->AddRef(); + _data->Release(); + _data = other._data; +} + +void ON_XMLPropertyPrivate::CopyOnWrite(void) +{ + if (_data->m_iRefCount > 1) + { + auto* pData = new CPropertyData(*_data); + _data->Release(); + _data = pData; + } +} + ON_XMLProperty::ON_XMLProperty() { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLPropertyPrivate; PRIVATE_CHECK(ON_XMLPropertyPrivate); } ON_XMLProperty::ON_XMLProperty(const ON_XMLVariant& sValue) { - m_impl = new (m_Impl) CImpl(sValue); IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLPropertyPrivate(sValue); PRIVATE_CHECK(ON_XMLPropertyPrivate); } ON_XMLProperty::ON_XMLProperty(const ON_wString& sName, const ON_XMLVariant& value) { - m_impl = new (m_Impl) CImpl(sName, value); IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLPropertyPrivate(sName, value); PRIVATE_CHECK(ON_XMLPropertyPrivate); } ON_XMLProperty::ON_XMLProperty(const ON_XMLProperty& prop) { - m_impl = new (m_Impl) CImpl(prop); IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLPropertyPrivate(prop); PRIVATE_CHECK(ON_XMLPropertyPrivate); } ON_XMLProperty::~ON_XMLProperty() { - m_impl->~CImpl(); - m_impl = nullptr; + _private->~ON_XMLPropertyPrivate(); + _private = nullptr; } const ON_wString& ON_XMLProperty::Name(void) const { - return m_impl->Name(); + return _private->Name(); } void ON_XMLProperty::SetName(const wchar_t* wsz) { - m_impl->SetName(wsz); + _private->SetName(wsz); } ON__UINT32 ON_XMLProperty::DataCRC(ON__UINT32 crc) const { - return m_impl->DataCRC(crc); + return _private->DataCRC(crc); } bool ON_XMLProperty::operator < (const ON_XMLProperty& prop) const { - return m_impl->operator < (prop); + return _private->operator < (prop); } const ON_XMLProperty& ON_XMLProperty::operator = (const ON_XMLProperty& prop) { - m_impl->operator = (prop.Impl()); + _private->operator = (*prop._private); + return *this; } bool ON_XMLProperty::IsDefaultProperty(void) const { - return m_impl->IsDefaultProperty(); + return _private->IsDefaultProperty(); } const ON_XMLVariant& ON_XMLProperty::GetValue(void) const { - return m_impl->GetValue(); + return _private->GetValue(); } void ON_XMLProperty::SetValue(const ON_XMLVariant& v) { - m_impl->SetValue(v); + _private->SetValue(v); } void ON_XMLProperty::SetHugeStringValue(const ON_wString& s) { - m_impl->SetHugeStringValue(s); -} - -ON_XMLProperty::CImpl& ON_XMLProperty::Impl(void) const -{ - return *m_impl; + _private->SetHugeStringValue(s); } ON_XMLVariant& ON_XMLProperty::GetNonConstValue(void) { - return m_impl->GetNonConstValue(); + return _private->GetNonConstValue(); } ON_XMLProperty* ON_XMLProperty::Next(void) const { - return m_impl->m_pNext; + return _private->_next; } void* ON_XMLProperty::EVF(const wchar_t*, void*) @@ -1667,7 +1693,7 @@ void* ON_XMLProperty::EVF(const wchar_t*, void*) // ON_XMLSegmentedStream -class ON_XMLSegmentedStream::CImpl +class ON_XMLSegmentedStreamPrivate { public: ON_SimpleArray m_a; @@ -1675,36 +1701,35 @@ public: ON_XMLSegmentedStream::ON_XMLSegmentedStream() { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new ON_XMLSegmentedStreamPrivate; } ON_XMLSegmentedStream::~ON_XMLSegmentedStream() { - for (int i = 0; i < m_impl->m_a.Count(); i++) + for (int i = 0; i < _private->m_a.Count(); i++) { - delete[] m_impl->m_a[i]; + delete[] _private->m_a[i]; } - m_impl->~CImpl(); - m_impl = nullptr; + delete _private; } int ON_XMLSegmentedStream::Count(void) const { - return m_impl->m_a.Count(); + return _private->m_a.Count(); } void ON_XMLSegmentedStream::Append(wchar_t* wsz) { - m_impl->m_a.Append(wsz); + _private->m_a.Append(wsz); } wchar_t* ON_XMLSegmentedStream::Segment(int index) const { - if ((index < 0) || (index >= m_impl->m_a.Count())) + if ((index < 0) || (index >= _private->m_a.Count())) return nullptr; - return m_impl->m_a[index]; + return _private->m_a[index]; } void* ON_XMLSegmentedStream::EVF(const wchar_t*, void*) @@ -1726,12 +1751,12 @@ private: bool m_bWarningsAsErrors; }; -class ON_XMLNode::CImpl final +class ON_XMLNodePrivate final { public: - CImpl(ON_XMLNode& n) : m_node(n) { g_lNodeCount++; } + ON_XMLNodePrivate(ON_XMLNode& n) : m_node(n) { g_lNodeCount++; } - ~CImpl() + ~ON_XMLNodePrivate() { RemoveAllProperties(); RemoveAllChildren(); @@ -1760,8 +1785,11 @@ public: static bool AssertValidTag(const ON_wString& sTag); static void AttemptToFixTag(ON_wString& tag); - static bool GetNextTag(ON_wString& tag, wchar_t*& pBuffer, bool bValidateTag); static bool RecoverProperty(const ON_wString& tag, int iEqualSign, ON_wString& sProp); + static bool GetNextTag(ON_wString& tag, wchar_t*& pBuffer, bool bValidateTag); + static ON_wString GetNameFromTag(const wchar_t* wszTag); + static bool IsValidXMLNameWithDebugging(const wchar_t* name); + static bool IsValidXMLName(const wchar_t* name); static bool m_bAutoTypePropValue; @@ -1777,16 +1805,92 @@ public: bool m_debug_auto_test_read = true; }; -bool ON_XMLNode::CImpl::m_bAutoTypePropValue = false; +bool ON_XMLNodePrivate::m_bAutoTypePropValue = false; -bool ON_XMLNode::AutoTypePropValue(void) +ON_wString ON_XMLNodePrivate::GetNameFromTag(const wchar_t* wszTag) // Static. { - return CImpl::m_bAutoTypePropValue; + ON_wString name = wszTag; + name.TrimLeft(L"/ "); + + const int pos = name.Find(L' '); + if (pos >= 0) + { + name.SetLength(pos); + } + + return name; } -void ON_XMLNode::SetAutoTypePropValue(bool b) +bool ON_XMLNodePrivate::IsValidXMLNameWithDebugging(const wchar_t* tag_name) // Static. { - CImpl::m_bAutoTypePropValue = b; + if (IsValidXMLName(tag_name)) + return true; + + OUTPUT_DEBUG_STRING(L"Invalid XML tag syntax - "); + OUTPUT_DEBUG_STRING_EOL(tag_name); + + ON_ASSERT(false); + + return false; +} + +bool ON_XMLNodePrivate::IsValidXMLName(const wchar_t* wszTagName) // Static. +{ + // https://www.xml.com/pub/a/2001/07/25/namingparts.html + // + // A 'Name' is a token beginning with a letter or one of a few punctuation characters, and continuing with + // letters, digits, hyphens, underscores, colons, or full stops, together known as name characters. + // This definition is formally expressed in Extended Backus-Naur Form (EBNF) notation as follows: + // + // NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender + // Name ::= (Letter | '_' | ':') (NameChar)* + + // We also simplify as follows: + // + // - ':' is not actually allowed in tags, it's reserved for XML namespaces, so we disallow it. + // - 'Letter' must be an ASCII letter: Letter ::= 'a' to 'z' or 'A' to 'Z'. + // - 'Digit' must be an ASCII digit: Digit ::= '0' to '9'. + // - 'CombiningChar' and 'Extender' are not supported (disallowed). + + const ON_wString sTagName = wszTagName; + if (sTagName.IsEmpty()) + return false; + + bool bad = false; + + const int len = sTagName.Length(); + for (int i = 0; i < len; i++) + { + const auto& ch = sTagName[i]; + + if ((ch >= L'a') && (ch <= L'z')) + continue; + + if ((ch >= L'A') && (ch <= L'Z')) + continue; + + if (ch == L'_') + continue; + + if (i > 0) + { + if ((ch >= L'0') && (ch <= L'9')) + continue; + + if ((ch == '-') || (ch == '.')) + continue; + } + + bad = true; + } + + if (bad) + { + return false; + } + + return true; } static const wchar_t* StringFromPropType(ON_XMLVariant::Types vt) @@ -1812,7 +1916,7 @@ static const wchar_t* StringFromPropType(ON_XMLVariant::Types vt) } } -ON__UINT32 ON_XMLNode::CImpl::DataCRC(ON__UINT32 crc, bool recursive) const +ON__UINT32 ON_XMLNodePrivate::DataCRC(ON__UINT32 crc, bool recursive) const { crc = TagName().DataCRCLower(crc); @@ -1829,21 +1933,21 @@ ON__UINT32 ON_XMLNode::CImpl::DataCRC(ON__UINT32 crc, bool recursive) const ON_XMLNode* child = nullptr; while (nullptr != (child = cit.GetNextChild())) { - crc = child->m_impl->DataCRC(crc, recursive); + crc = child->_private->DataCRC(crc, recursive); } } return crc; } -const ON_wString& ON_XMLNode::CImpl::TagName(void) const +const ON_wString& ON_XMLNodePrivate::TagName(void) const { std::lock_guard lg(m_mutex); return m_name; } -void ON_XMLNode::CImpl::SetTagName(const wchar_t* name) +void ON_XMLNodePrivate::SetTagName(const wchar_t* name) { std::lock_guard lg(m_mutex); @@ -1852,20 +1956,20 @@ void ON_XMLNode::CImpl::SetTagName(const wchar_t* name) m_name.TrimRight(); } -const ON_XMLNode& ON_XMLNode::CImpl::TopLevel(void) const +const ON_XMLNode& ON_XMLNodePrivate::TopLevel(void) const { std::lock_guard lg(m_mutex); const auto* pNode = &m_node; - while (nullptr != pNode->Impl().m_parent) + while (nullptr != pNode->_private->m_parent) { - pNode = pNode->Impl().m_parent; + pNode = pNode->_private->m_parent; } return *pNode; } -ON_XMLNode* ON_XMLNode::CImpl::AttachChildNode(ON_XMLNode* pNode) +ON_XMLNode* ON_XMLNodePrivate::AttachChildNode(ON_XMLNode* pNode) { if (nullptr == pNode) return nullptr; @@ -1880,22 +1984,22 @@ ON_XMLNode* ON_XMLNode::CImpl::AttachChildNode(ON_XMLNode* pNode) else { // There are children - add one to the end. - m_last_child->Impl().m_next_sibling = pNode; + m_last_child->_private->m_next_sibling = pNode; m_last_child = pNode; } - pNode->Impl().m_next_sibling = nullptr; - pNode->Impl().m_parent = &m_node; + pNode->_private->m_next_sibling = nullptr; + pNode->_private->m_parent = &m_node; return pNode; } -void ON_XMLNode::CImpl::AddEmptyDefaultProperty(void) +void ON_XMLNodePrivate::AddEmptyDefaultProperty(void) { AddProperty(ON_XMLProperty(L"")); } -void ON_XMLNode::CImpl::RemoveAllChildren(void) +void ON_XMLNodePrivate::RemoveAllChildren(void) { std::lock_guard lg(m_mutex); @@ -1914,16 +2018,16 @@ void ON_XMLNode::CImpl::RemoveAllChildren(void) m_last_child = nullptr; } -ON_XMLNode* ON_XMLNode::CImpl::DetachChild(ON_XMLNode& child) +ON_XMLNode* ON_XMLNodePrivate::DetachChild(ON_XMLNode& child) { std::lock_guard lg(m_mutex); - if (child.Impl().m_parent != &m_node) + if (child._private->m_parent != &m_node) return nullptr; ON_XMLNode* pChild = nullptr; - auto* pChildNextSibling = child.Impl().m_next_sibling; + auto* pChildNextSibling = child._private->m_next_sibling; if (m_first_child == &child) { @@ -1939,9 +2043,9 @@ ON_XMLNode* ON_XMLNode::CImpl::DetachChild(ON_XMLNode& child) auto* pNode = m_first_child; while (nullptr != pNode) { - if (pNode->Impl().m_next_sibling == &child) + if (pNode->_private->m_next_sibling == &child) { - pNode->Impl().m_next_sibling = pChildNextSibling; + pNode->_private->m_next_sibling = pChildNextSibling; if (nullptr == pChildNextSibling) m_last_child = pNode; @@ -1950,36 +2054,36 @@ ON_XMLNode* ON_XMLNode::CImpl::DetachChild(ON_XMLNode& child) break; } - pNode = pNode->Impl().m_next_sibling; + pNode = pNode->_private->m_next_sibling; } } if (nullptr != pChild) { - pChild->Impl().m_parent = nullptr; - pChild->Impl().m_next_sibling = nullptr; + pChild->_private->m_parent = nullptr; + pChild->_private->m_next_sibling = nullptr; } return pChild; } -ON_XMLNode* ON_XMLNode::CImpl::PrevSibling(void) const +ON_XMLNode* ON_XMLNodePrivate::PrevSibling(void) const { std::lock_guard lg(m_mutex); - auto* pPrev = m_parent->Impl().m_first_child; + auto* pPrev = m_parent->_private->m_first_child; if (pPrev == &m_node) return nullptr; - while (pPrev->Impl().m_next_sibling != &m_node) + while (pPrev->_private->m_next_sibling != &m_node) { - pPrev = pPrev->Impl().m_next_sibling; + pPrev = pPrev->_private->m_next_sibling; } return pPrev; } -void ON_XMLNode::CImpl::MoveBefore(ON_XMLNode& other) +void ON_XMLNodePrivate::MoveBefore(ON_XMLNode& other) { if (&other == &m_node) return; @@ -1993,12 +2097,12 @@ void ON_XMLNode::CImpl::MoveBefore(ON_XMLNode& other) auto* pPrev = PrevSibling(); if (nullptr != pPrev) { - pPrev->Impl().m_next_sibling = m_next_sibling; + pPrev->_private->m_next_sibling = m_next_sibling; } else { // 'this' was the head; redirect the parent's first child. - m_parent->Impl().m_first_child = m_next_sibling; + m_parent->_private->m_first_child = m_next_sibling; } m_next_sibling = &other; @@ -2006,15 +2110,15 @@ void ON_XMLNode::CImpl::MoveBefore(ON_XMLNode& other) if (nullptr == pBeforeOther) { // 'other' was the head; redirect the parent's first child. - m_parent->Impl().m_first_child = &m_node; + m_parent->_private->m_first_child = &m_node; } else { - pBeforeOther->Impl().m_next_sibling = &m_node; + pBeforeOther->_private->m_next_sibling = &m_node; } } -void ON_XMLNode::CImpl::MoveAfter(ON_XMLNode& other) +void ON_XMLNodePrivate::MoveAfter(ON_XMLNode& other) { if (&other == &m_node) return; @@ -2027,20 +2131,20 @@ void ON_XMLNode::CImpl::MoveAfter(ON_XMLNode& other) if (nullptr != pPrev) { - pPrev->Impl().m_next_sibling = m_next_sibling; + pPrev->_private->m_next_sibling = m_next_sibling; } else { // 'this' was the head; redirect the parent's first child. - m_parent->Impl().m_first_child = m_next_sibling; + m_parent->_private->m_first_child = m_next_sibling; } - m_next_sibling = other.Impl().m_next_sibling; + m_next_sibling = other._private->m_next_sibling; - other.Impl().m_next_sibling = &m_node; + other._private->m_next_sibling = &m_node; } -bool ON_XMLNode::CImpl::RecurseChildren(ON_XMLRecurseChildrenCallback callback, void* pv) const +bool ON_XMLNodePrivate::RecurseChildren(ON_XMLRecurseChildrenCallback callback, void* pv) const { std::lock_guard lg(m_mutex); @@ -2059,19 +2163,19 @@ bool ON_XMLNode::CImpl::RecurseChildren(ON_XMLRecurseChildrenCallback callback, return true; } -ON_XMLProperty* ON_XMLNode::CImpl::AddProperty(const ON_XMLProperty& prop) +ON_XMLProperty* ON_XMLNodePrivate::AddProperty(const ON_XMLProperty& prop) { std::lock_guard lg(m_mutex); auto* prop_copy = new ON_XMLProperty(prop); - prop_copy->Impl().m_owner = &m_node; - prop_copy->Impl().m_pNext = m_first_property; + prop_copy->_private->_owner = &m_node; + prop_copy->_private->_next = m_first_property; m_first_property = prop_copy; return prop_copy; } -ON_XMLProperty* ON_XMLNode::CImpl::AttachProperty(ON_XMLProperty* prop) +ON_XMLProperty* ON_XMLNodePrivate::AttachProperty(ON_XMLProperty* prop) { if (nullptr == prop) return nullptr; @@ -2080,14 +2184,14 @@ ON_XMLProperty* ON_XMLNode::CImpl::AttachProperty(ON_XMLProperty* prop) RemoveProperty(prop->Name()); - prop->Impl().m_pNext = m_first_property; + prop->_private->_next = m_first_property; m_first_property = prop; - m_first_property->Impl().m_owner = &m_node; + m_first_property->_private->_owner = &m_node; return prop; } -bool ON_XMLNode::CImpl::RemoveProperty(const wchar_t* name) +bool ON_XMLNodePrivate::RemoveProperty(const wchar_t* name) { ON_XMLProperty* pPrev = nullptr; @@ -2102,7 +2206,7 @@ bool ON_XMLNode::CImpl::RemoveProperty(const wchar_t* name) } else { - pPrev->Impl().m_pNext = pProp->Next(); + pPrev->_private->_next = pProp->Next(); } delete pProp; @@ -2110,13 +2214,13 @@ bool ON_XMLNode::CImpl::RemoveProperty(const wchar_t* name) } pPrev = pProp; - pProp = pProp->Impl().m_pNext; + pProp = pProp->_private->_next; } return false; } -void ON_XMLNode::CImpl::RemoveAllProperties(void) +void ON_XMLNodePrivate::RemoveAllProperties(void) { if (nullptr == m_first_property) return; @@ -2132,7 +2236,7 @@ void ON_XMLNode::CImpl::RemoveAllProperties(void) m_first_property = nullptr; } -ON_XMLNode* ON_XMLNode::CImpl::GetNodeAtPath(const wchar_t* wszPath, bool bCreate) +ON_XMLNode* ON_XMLNodePrivate::GetNodeAtPath(const wchar_t* wszPath, bool bCreate) { std::lock_guard lg(m_mutex); @@ -2189,20 +2293,20 @@ ON_XMLNode* ON_XMLNode::CImpl::GetNodeAtPath(const wchar_t* wszPath, bool bCreat { if (on_wcsicmp(wsz, pChild->TagName()) == 0) { - return pChild->Impl().GetNodeAtPath(pNext, bCreate); + return pChild->_private->GetNodeAtPath(pNext, bCreate); } } // The child was not found. if (bCreate) { - return AttachChildNode(new ON_XMLNode(wsz))->Impl().GetNodeAtPath(pNext, bCreate); + return AttachChildNode(new ON_XMLNode(wsz))->_private->GetNodeAtPath(pNext, bCreate); } return nullptr; } -bool ON_XMLNode::CImpl::RecoverProperty(const ON_wString& tag, int equalSign, ON_wString& sProp) // Static. +bool ON_XMLNodePrivate::RecoverProperty(const ON_wString& tag, int equalSign, ON_wString& sProp) // Static. { // Move left, looking for a space and ensuring every character is a valid name char. ON_ASSERT(tag[equalSign] == L'='); @@ -2237,7 +2341,7 @@ bool ON_XMLNode::CImpl::RecoverProperty(const ON_wString& tag, int equalSign, ON return true; } -void ON_XMLNode::CImpl::AttemptToFixTag(ON_wString& tag) // Static. +void ON_XMLNodePrivate::AttemptToFixTag(ON_wString& tag) // Static. { // We're going to rebuild the tag from the name and the number of valid properties we find. const ON_wString sName = GetNameFromTag(tag); @@ -2277,7 +2381,7 @@ void ON_XMLNode::CImpl::AttemptToFixTag(ON_wString& tag) // Static. tag = sNewTag; } -bool ON_XMLNode::CImpl::GetNextTag(ON_wString& tag, wchar_t*& pBuffer, bool bValidateTag) // Static. +bool ON_XMLNodePrivate::GetNextTag(ON_wString& tag, wchar_t*& pBuffer, bool bValidateTag) // Static. { auto* start = pBuffer; while (*start != L'<') @@ -2364,7 +2468,7 @@ bool ON_XMLNode::CImpl::GetNextTag(ON_wString& tag, wchar_t*& pBuffer, bool bVal return true; } -bool ON_XMLNode::CImpl::AssertValidTag(const ON_wString& tag) // Static. +bool ON_XMLNodePrivate::AssertValidTag(const ON_wString& tag) // Static. { // Check for an even number of quotes - odd means there are quotes in the strings. const int quoteCount = tag.Count(L'\"'); @@ -2413,24 +2517,23 @@ bool ON_XMLNode::CImpl::AssertValidTag(const ON_wString& tag) // Static. ON_XMLNode::ON_XMLNode(const wchar_t* name) { - m_impl = new (m_Impl) CImpl(*this); IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLNodePrivate(*this); PRIVATE_CHECK(ON_XMLNodePrivate); SetTagName(name); - m_impl->AddEmptyDefaultProperty(); + _private->AddEmptyDefaultProperty(); } ON_XMLNode::ON_XMLNode(const ON_XMLNode& src) { - m_impl = new (m_Impl) CImpl(*this); IMPL_CHECK; - + _private = new (_PRIVATE) ON_XMLNodePrivate(*this); PRIVATE_CHECK(ON_XMLNodePrivate); *this = src; } ON_XMLNode::~ON_XMLNode() { - m_impl->~CImpl(); - m_impl = nullptr; + _private->~ON_XMLNodePrivate(); + _private = nullptr; } const ON_XMLNode& ON_XMLNode::operator = (const ON_XMLNode& src) @@ -2438,20 +2541,20 @@ const ON_XMLNode& ON_XMLNode::operator = (const ON_XMLNode& src) if (this == &src) return *this; - std::lock_guard lg1(m_impl->m_mutex); - std::lock_guard lg2(src.Impl().m_mutex); + std::lock_guard lg1(_private->m_mutex); + std::lock_guard lg2(src._private->m_mutex); - m_impl->RemoveAllProperties(); - m_impl->RemoveAllChildren(); + _private->RemoveAllProperties(); + _private->RemoveAllChildren(); - m_impl->m_name = src.Impl().m_name; + _private->m_name = src._private->m_name; // Copy in the properties. ON_XMLProperty* pProperty = nullptr; auto pi = src.GetPropertyIterator(); while (nullptr != (pProperty = pi.GetNextProperty())) { - m_impl->AddProperty(*pProperty); + _private->AddProperty(*pProperty); } // Copy in the children. @@ -2499,12 +2602,22 @@ bool ON_XMLNode::operator != (const ON_XMLNode& node) const return !(operator == (node)); } +bool ON_XMLNode::AutoTypePropValue(void) +{ + return ON_XMLNodePrivate::m_bAutoTypePropValue; +} + +void ON_XMLNode::SetAutoTypePropValue(bool b) +{ + ON_XMLNodePrivate::m_bAutoTypePropValue = b; +} + bool ON_XMLNode::MergeFrom(const ON_XMLNode& src) { - std::lock_guard lg1(m_impl->m_mutex); - std::lock_guard lg2(src.Impl().m_mutex); + std::lock_guard lg1(_private->m_mutex); + std::lock_guard lg2(src._private->m_mutex); - if (m_impl->m_name != src.TagName()) + if (_private->m_name != src.TagName()) return false; // Copy in the parameters. @@ -2547,20 +2660,20 @@ void ON_XMLNode::Clear(void) void ON_XMLNode::RemoveAllChildren(void) { - m_impl->RemoveAllChildren(); + _private->RemoveAllChildren(); } void ON_XMLNode::RemoveAllProperties(void) { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); - m_impl->RemoveAllProperties(); - m_impl->AddEmptyDefaultProperty(); + _private->RemoveAllProperties(); + _private->AddEmptyDefaultProperty(); } ON_XMLProperty* ON_XMLNode::SetProperty(const ON_XMLProperty& prop) { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); if (g_iWarningsFlagCounter > 0) { @@ -2578,118 +2691,47 @@ ON_XMLProperty* ON_XMLNode::SetProperty(const ON_XMLProperty& prop) } } - m_impl->RemoveProperty(prop.Name()); + _private->RemoveProperty(prop.Name()); // Copy the property, then add it to the tree. - return m_impl->AddProperty(prop); + return _private->AddProperty(prop); } const ON_wString& ON_XMLNode::TagName(void) const { - return m_impl->TagName(); + return _private->TagName(); } void ON_XMLNode::SetTagName(const wchar_t* name) { - m_impl->SetTagName(name); -} - -bool ON_XMLNode::IsValidXMLNameWithDebugging(const wchar_t* tag_name) // Static. -{ - if (IsValidXMLName(tag_name)) - return true; - - OUTPUT_DEBUG_STRING(L"Invalid XML tag syntax - "); - OUTPUT_DEBUG_STRING_EOL(tag_name); - - ON_ASSERT(false); - - return false; -} - -bool ON_XMLNode::IsValidXMLName(const wchar_t* wszTagName) // Static. -{ - // https://www.xml.com/pub/a/2001/07/25/namingparts.html - // - // A 'Name' is a token beginning with a letter or one of a few punctuation characters, and continuing with - // letters, digits, hyphens, underscores, colons, or full stops, together known as name characters. - // This definition is formally expressed in Extended Backus-Naur Form (EBNF) notation as follows: - // - // NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender - // Name ::= (Letter | '_' | ':') (NameChar)* - - // We also simplify as follows: - // - // - ':' is not actually allowed in tags, it's reserved for XML namespaces, so we disallow it. - // - 'Letter' must be an ASCII letter: Letter ::= 'a' to 'z' or 'A' to 'Z'. - // - 'Digit' must be an ASCII digit: Digit ::= '0' to '9'. - // - 'CombiningChar' and 'Extender' are not supported (disallowed). - - const ON_wString sTagName = wszTagName; - if (sTagName.IsEmpty()) - return false; - - bool bad = false; - - const int len = sTagName.Length(); - for (int i = 0; i < len; i++) - { - const auto& ch = sTagName[i]; - - if ((ch >= L'a') && (ch <= L'z')) - continue; - - if ((ch >= L'A') && (ch <= L'Z')) - continue; - - if (ch == L'_') - continue; - - if (i > 0) - { - if ((ch >= L'0') && (ch <= L'9')) - continue; - - if ((ch == '-') || (ch == '.')) - continue; - } - - bad = true; - } - - if (bad) - { - return false; - } - - return true; + _private->SetTagName(name); } ON_XMLNode* ON_XMLNode::Parent(void) const { - return m_impl->m_parent; + return _private->m_parent; } const ON_XMLNode& ON_XMLNode::TopLevel(void) const { - return m_impl->TopLevel(); + return _private->TopLevel(); } ON_XMLNode* ON_XMLNode::AttachChildNode(ON_XMLNode* pNode) { - return m_impl->AttachChildNode(pNode); + return _private->AttachChildNode(pNode); } ON_XMLProperty* ON_XMLNode::AttachProperty(ON_XMLProperty* pProp) { - return m_impl->AttachProperty(pProp); + return _private->AttachProperty(pProp); } bool ON_XMLNode::RemoveProperty(const wchar_t* wszPropertyName) { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); - return m_impl->RemoveProperty(wszPropertyName); + return _private->RemoveProperty(wszPropertyName); } void ON_XMLNode::Remove(void) @@ -2707,7 +2749,7 @@ void ON_XMLNode::Remove(void) ON_XMLNode* ON_XMLNode::DetachChild(ON_XMLNode& child) { - return m_impl->DetachChild(child); + return _private->DetachChild(child); } bool ON_XMLNode::RemoveChild(ON_XMLNode* child) @@ -2715,7 +2757,7 @@ bool ON_XMLNode::RemoveChild(ON_XMLNode* child) if (nullptr == child) return false; - ON_XMLNode* detach = m_impl->DetachChild(*child); + ON_XMLNode* detach = _private->DetachChild(*child); if (nullptr != detach) { delete detach; @@ -2737,7 +2779,7 @@ ON_XMLNode::PropertyIterator ON_XMLNode::GetPropertyIterator(bool bAlphabetized) int ON_XMLNode::PropertyCount(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); int count = 0; auto it = GetPropertyIterator(); @@ -2751,7 +2793,7 @@ int ON_XMLNode::PropertyCount(void) const int ON_XMLNode::ChildCount(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); int count = 0; auto it = GetChildIterator(); @@ -2765,14 +2807,14 @@ int ON_XMLNode::ChildCount(void) const int ON_XMLNode::GetNestedDepth(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); int depth = 0; const auto* pNode = this; - while (nullptr != pNode->Impl().m_parent) + while (nullptr != pNode->_private->m_parent) { - pNode = pNode->Impl().m_parent; + pNode = pNode->_private->m_parent; depth++; } @@ -2800,7 +2842,7 @@ static bool PrependNodeToStringAndRecurseParents(const ON_XMLNode* pNode, ON_wSt ON_wString ON_XMLNode::GetPathFromRoot(void) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); ON_wString sPath = TagName(); PrependNodeToStringAndRecurseParents(Parent(), sPath); @@ -2819,7 +2861,7 @@ ON_XMLProperty& ON_XMLNode::GetDefaultProperty(void) const ON_XMLProperty* ON_XMLNode::GetNamedProperty(const wchar_t* name) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); auto it = GetPropertyIterator(); ON_XMLProperty* pProp = nullptr; @@ -2835,7 +2877,7 @@ ON_XMLProperty* ON_XMLNode::GetNamedProperty(const wchar_t* name) const ON_XMLNode* ON_XMLNode::GetNamedChild(const wchar_t* name) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); ON_XMLNode* node = nullptr; @@ -2851,10 +2893,10 @@ ON_XMLNode* ON_XMLNode::GetNamedChild(const wchar_t* name) const void* ON_XMLNode::LastReadBufferPointer(void) const { - return m_impl->m_last_read_buf_ptr; + return _private->m_last_read_buf_ptr; } -bool ON_XMLNode::CImpl::GetPropertiesFromTag(const ON_wString& sTag) +bool ON_XMLNodePrivate::GetPropertiesFromTag(const ON_wString& sTag) { SetTagName(GetNameFromTag(sTag)); @@ -2930,7 +2972,7 @@ bool ON_XMLNode::CImpl::GetPropertiesFromTag(const ON_wString& sTag) return true; } -bool ON_XMLNode::CImpl::IsClosingTag(const ON_wString& sTag) const +bool ON_XMLNodePrivate::IsClosingTag(const ON_wString& sTag) const { if (sTag.Length() < 3) return false; @@ -2981,12 +3023,12 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteHeaderToStream(wchar_t* stream, ON_ if (write) { - ON_ASSERT(m_impl->m_name.IsNotEmpty()); + ON_ASSERT(_private->m_name.IsNotEmpty()); header = L"<"; - header += m_impl->m_name; + header += _private->m_name; } - auto logical_header_length = ON__UINT32(m_impl->m_name.Length()) + 1; // +1 for '<'. + auto logical_header_length = ON__UINT32(_private->m_name.Length()) + 1; // +1 for '<'. if (includeFormatting) { @@ -3049,7 +3091,7 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteHeaderToStream(wchar_t* stream, ON_ const auto& vValue = pProp->GetValue(); - if (CImpl::m_bAutoTypePropValue) + if (ON_XMLNodePrivate::m_bAutoTypePropValue) { const ON_wString sType = StringFromPropType(pProp->GetValue().Type()); if (write) @@ -3089,7 +3131,7 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteHeaderToStream(wchar_t* stream, ON_ { ON_wString sType; - const bool bType = CImpl::m_bAutoTypePropValue && (nullptr != psDefaultProperty); + const bool bType = ON_XMLNodePrivate::m_bAutoTypePropValue && (nullptr != psDefaultProperty); if (bType) sType = StringFromPropType(GetDefaultProperty().GetValue().Type()); @@ -3121,14 +3163,14 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteHeaderToStream(wchar_t* stream, ON_ } CharacterCounts counts; - counts.m_logical = logical_header_length; + counts._logical = logical_header_length; if (0 != max_chars) { const auto physical_header_length = ON__UINT32(header.Length()); const auto chars_to_copy = std::min(max_chars, physical_header_length + 1); memcpy(stream, static_cast(header), chars_to_copy * sizeof(wchar_t)); - counts.m_physical = std::min(max_chars, physical_header_length); + counts._physical = std::min(max_chars, physical_header_length); ON_ASSERT(logical_header_length == physical_header_length); } @@ -3148,8 +3190,8 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteChildrenToStream(wchar_t* stream, O const auto cc = pChild->WriteToStreamEx(stream, max_chars, includeFormatting, forceLongFormat, sortedProperties); counts += cc; if (nullptr != stream) - stream += cc.m_physical; - max_chars = std::max(0, int(max_chars - cc.m_logical)); + stream += cc._physical; + max_chars = std::max(0, int(max_chars - cc._logical)); } return counts; @@ -3165,7 +3207,7 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteFooterToStream(wchar_t* stream, ON_ if (hasDefaultProp || (child_count > 0) || forceLongFormat) { footer = L"m_name; footer += L'>'; if (includeFormatting) @@ -3190,13 +3232,13 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteFooterToStream(wchar_t* stream, ON_ } CharacterCounts counts; - counts.m_logical = ON__UINT32(footer.Length()); + counts._logical = ON__UINT32(footer.Length()); if (0 != max_chars) { - const auto chars_to_copy = std::min(max_chars, counts.m_logical + 1); + const auto chars_to_copy = std::min(max_chars, counts._logical + 1); memcpy(stream, static_cast(footer), chars_to_copy * sizeof(wchar_t)); - counts.m_physical = std::min(max_chars, counts.m_logical); + counts._physical = std::min(max_chars, counts._logical); } return counts; @@ -3204,13 +3246,13 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteFooterToStream(wchar_t* stream, ON_ void ON_XMLNode::SetInternalDebuggingFlags(ON__UINT64 flags) { - m_impl->m_debug_auto_test_read = (flags & 1); + _private->m_debug_auto_test_read = (flags & 1); } void ON_XMLNode::CharacterCounts::operator += (const CharacterCounts& cw) { - m_logical += cw.m_logical; - m_physical += cw.m_physical; + _logical += cw._logical; + _physical += cw._physical; } ON__UINT32 ON_XMLNode::WriteToStream(wchar_t* stream, ON__UINT32 max_chars, bool include_formatting, @@ -3219,23 +3261,23 @@ ON__UINT32 ON_XMLNode::WriteToStream(wchar_t* stream, ON__UINT32 max_chars, bool const auto cc = WriteToStreamEx(stream, max_chars, include_formatting, force_long_format, sorted_props); #ifdef _DEBUG - if (m_impl->m_debug_auto_test_read && (nullptr != stream)) + if (_private->m_debug_auto_test_read && (nullptr != stream)) { ON_XMLNode test(TagName()); const auto read = test.ReadFromStream(stream, true, true); - if (read != cc.m_logical) + if (read != cc._logical) { ON_ERROR("CRITICAL: Could not read back what was written"); } } #endif - return cc.m_logical; + return cc._logical; } ON_XMLNode::CharacterCounts ON_XMLNode::WriteToStreamEx(wchar_t* stream, ON__UINT32 max_chars, bool includeFormatting, bool forceLongFormat, bool sortedProperties) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); CharacterCounts counts; @@ -3248,16 +3290,16 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteToStreamEx(wchar_t* stream, ON__UIN auto cc = WriteHeaderToStream(stream, max_chars, includeFormatting, forceLongFormat, sortedProperties); counts += cc; if (nullptr != stream) - stream += cc.m_physical; + stream += cc._physical; - max_chars = std::max(0, int(max_chars - cc.m_logical)); + max_chars = std::max(0, int(max_chars - cc._logical)); cc = WriteChildrenToStream(stream, max_chars, includeFormatting, forceLongFormat, sortedProperties); counts += cc; if (nullptr != stream) - stream += cc.m_physical; + stream += cc._physical; - max_chars = std::max(0, int(max_chars - cc.m_logical)); + max_chars = std::max(0, int(max_chars - cc._logical)); cc = WriteFooterToStream(stream, max_chars, includeFormatting, forceLongFormat); counts += cc; @@ -3267,11 +3309,11 @@ ON_XMLNode::CharacterCounts ON_XMLNode::WriteToStreamEx(wchar_t* stream, ON__UIN bool ON_XMLNode::WriteToSegmentedStream(ON_XMLSegmentedStream& segs, bool includeFormatting, bool forceLongFormat, bool sortedProperties) const { - std::lock_guard lg(m_impl->m_mutex); + std::lock_guard lg(_private->m_mutex); const auto header_cw = WriteHeaderToStream(nullptr, 0, includeFormatting, forceLongFormat, sortedProperties); - auto* pHeader = new wchar_t[size_t(header_cw.m_logical) + 1]; - WriteHeaderToStream(pHeader, header_cw.m_logical + 1, includeFormatting, forceLongFormat, sortedProperties); + auto* pHeader = new wchar_t[size_t(header_cw._logical) + 1]; + WriteHeaderToStream(pHeader, header_cw._logical + 1, includeFormatting, forceLongFormat, sortedProperties); segs.Append(pHeader); auto it = GetChildIterator(); @@ -3282,61 +3324,46 @@ bool ON_XMLNode::WriteToSegmentedStream(ON_XMLSegmentedStream& segs, bool includ } const auto footer_cw = WriteFooterToStream(nullptr, 0, includeFormatting, forceLongFormat); - auto* pFooter = new wchar_t[size_t(footer_cw.m_logical) + 1]; - WriteFooterToStream(pFooter, footer_cw.m_logical + 1, includeFormatting, forceLongFormat); + auto* pFooter = new wchar_t[size_t(footer_cw._logical) + 1]; + WriteFooterToStream(pFooter, footer_cw._logical + 1, includeFormatting, forceLongFormat); segs.Append(pFooter); return true; } -ON_wString ON_XMLNode::GetNameFromTag(const wchar_t* wszTag) // Static. -{ - ON_wString name = wszTag; - name.TrimLeft(L"/ "); - - const int pos = name.Find(L' '); - if (pos >= 0) - { - name.SetLength(pos); - } - - return name; -} - ON_XMLNode* ON_XMLNode::FirstChild(void) const { - return m_impl->m_first_child; + return _private->m_first_child; } ON_XMLNode* ON_XMLNode::PrevSibling(void) const { - return m_impl->PrevSibling(); + return _private->PrevSibling(); } void ON_XMLNode::MoveBefore(ON_XMLNode& other) { - m_impl->MoveBefore(other); + _private->MoveBefore(other); } void ON_XMLNode::MoveAfter(ON_XMLNode& other) { - m_impl->MoveAfter(other); + _private->MoveAfter(other); } bool ON_XMLNode::RecurseChildren(ON_XMLRecurseChildrenCallback callback, void* pv) const { - return m_impl->RecurseChildren(callback, pv); + return _private->RecurseChildren(callback, pv); } ON_XMLNode* ON_XMLNode::NextSibling(void) const { - return m_impl->m_next_sibling; + return _private->m_next_sibling; } ON__UINT32 ON_XMLNode::DataCRC(ON__UINT32 crc, bool recursive) const { - return m_impl->DataCRC(crc, 0); + return _private->DataCRC(crc, 0); } void* ON_XMLNode::EVF(const wchar_t*, void*) @@ -3346,12 +3373,12 @@ void* ON_XMLNode::EVF(const wchar_t*, void*) ON_XMLNode* ON_XMLNode::GetNodeAtPath(const wchar_t* wszPath) const { - return m_impl->GetNodeAtPath(wszPath, false); + return _private->GetNodeAtPath(wszPath, false); } ON_XMLNode* ON_XMLNode::CreateNodeAtPath(const wchar_t* wszPath) { - return m_impl->GetNodeAtPath(wszPath, true); + return _private->GetNodeAtPath(wszPath, true); } void ON_XMLNode::OnNodeReadFromStream(const ON_XMLNode*) const @@ -3379,15 +3406,15 @@ ON__UINT32 ON_XMLNode::ReadFromStream(const wchar_t* stream, bool bWarningsAsErr // The original code was not checking GetNextTag() for failure and blindly continuing with an empty tag. // Then in some places it assumed that the tag was not empty. This is confusing because I thought // this was causing RH-66795, but it couldn't be because this bug was not in 7.x, and RH-66795 is 7.13. - if (!m_impl->GetNextTag(tag, pBuffer, bValidateTags)) + if (!_private->GetNextTag(tag, pBuffer, bValidateTags)) return ReadError; if (tag.IsEmpty()) return ReadError; - m_impl->m_last_read_buf_ptr = (void*)stream; + _private->m_last_read_buf_ptr = (void*)stream; - m_impl->GetPropertiesFromTag(tag); + _private->GetPropertiesFromTag(tag); const auto pos1 = tag.Length() - 2; // Assumes the tag is not empty. if (tag[pos1] != L'/') @@ -3428,10 +3455,10 @@ ON__UINT32 ON_XMLNode::ReadFromStream(const wchar_t* stream, bool bWarningsAsErr // an empty tag. This caused continuous child recursion because the buffer pointer was // still pointing at the same (bad) XML. This is confusing because I thought this was causing // RH-66795, but it couldn't be because this bug was not in 7.x, and RH-66795 is 7.13. - if (!m_impl->GetNextTag(tag, pBuffer, bValidateTags)) + if (!_private->GetNextTag(tag, pBuffer, bValidateTags)) return ReadError; - bClosingTag = m_impl->IsClosingTag(tag); + bClosingTag = _private->IsClosingTag(tag); if (!bClosingTag) { @@ -3456,7 +3483,7 @@ ON__UINT32 ON_XMLNode::ReadFromStream(const wchar_t* stream, bool bWarningsAsErr auto* pProp = new ON_XMLProperty; AttachProperty(pProp); - const int pos2 = CImpl::m_bAutoTypePropValue ? sDefaultProperty.Find(L":") : -1; + const int pos2 = ON_XMLNodePrivate::m_bAutoTypePropValue ? sDefaultProperty.Find(L":") : -1; if (pos2 > 0) { auto& v = pProp->GetNonConstValue(); @@ -3465,8 +3492,8 @@ ON__UINT32 ON_XMLNode::ReadFromStream(const wchar_t* stream, bool bWarningsAsErr } else { - pProp->Impl().SetHugeStringValue(sDefaultProperty); - pProp->Impl().GetNonConstValue().SetTypePendingFlag(true); + pProp->_private->SetHugeStringValue(sDefaultProperty); + pProp->_private->GetNonConstValue().SetTypePendingFlag(true); } } } @@ -3479,55 +3506,64 @@ ON__UINT32 ON_XMLNode::ReadFromStream(const wchar_t* stream, bool bWarningsAsErr return ON__UINT32(pBuffer - stream); } -ON_XMLNode::CImpl& ON_XMLNode::Impl(void) const +ON_wString ON_XMLNode::GetNameFromTag(const wchar_t* wszTag) // Static. { - return *m_impl; + return ON_XMLNodePrivate::GetNameFromTag(wszTag); } -class ON_XMLNode::ChildIterator::CImpl final +bool ON_XMLNode::IsValidXMLNameWithDebugging(const wchar_t* name) // Static. +{ + return ON_XMLNodePrivate::IsValidXMLNameWithDebugging(name); +} + +bool ON_XMLNode::IsValidXMLName(const wchar_t* name) // Static. +{ + return ON_XMLNodePrivate::IsValidXMLName(name); +} + +class ON_XMLNodeChildIteratorPrivate final { public: - ON_XMLNode* m_pCurrent = nullptr; + ON_XMLNode* _current = nullptr; }; -ON_XMLNode::ChildIterator::ChildIterator(const ON_XMLNode* pParent) +ON_XMLNode::ChildIterator::ChildIterator(const ON_XMLNode* parent) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new ON_XMLNodeChildIteratorPrivate; - if (nullptr != pParent) + if (nullptr != parent) { - m_impl->m_pCurrent = pParent->Impl().m_first_child; + _private->_current = parent->_private->m_first_child; } } ON_XMLNode::ChildIterator::ChildIterator(const ChildIterator& other) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new ON_XMLNodeChildIteratorPrivate; operator = (other); } ON_XMLNode::ChildIterator::~ChildIterator() { - m_impl->~CImpl(); - m_impl = nullptr; + delete _private; } const ON_XMLNode::ChildIterator& ON_XMLNode::ChildIterator::operator = (const ChildIterator& other) { - m_impl->m_pCurrent = other.m_impl->m_pCurrent; + _private->_current = other._private->_current; return *this; } ON_XMLNode* ON_XMLNode::ChildIterator::GetNextChild(void) { - auto* pNode = m_impl->m_pCurrent; - if (nullptr != pNode) + ON_XMLNode* node = _private->_current; + if (nullptr != node) { - m_impl->m_pCurrent = pNode->Impl().m_next_sibling; + _private->_current = node->_private->m_next_sibling; } - return pNode; + return node; } void* ON_XMLNode::ChildIterator::EVF(const wchar_t*, void*) @@ -3537,10 +3573,10 @@ void* ON_XMLNode::ChildIterator::EVF(const wchar_t*, void*) // ON_XMLNode::PropertyIterator -class ON_XMLNode::PropertyIterator::CImpl final +class ON_XMLNodePropertyIteratorPrivate final { public: - ~CImpl(); + ~ON_XMLNodePropertyIteratorPrivate(); ON_XMLProperty* GetNextPropertySorted(void) { @@ -3548,9 +3584,9 @@ public: if (m_iIndex == 0) { // While sorting properties, don't allow anything else to access the parent node. - std::lock_guard lg(m_pNode->Impl().m_mutex); + std::lock_guard lg(m_pNode->_private->m_mutex); - PropertyIterator pi(m_pNode, false); + ON_XMLNode::PropertyIterator pi(m_pNode, false); ON_ASSERT(m_paSortedProperties == nullptr); m_paSortedProperties = new std::vector; @@ -3580,7 +3616,7 @@ public: bool m_bSorted = false; }; -ON_XMLNode::PropertyIterator::CImpl::~CImpl() +ON_XMLNodePropertyIteratorPrivate::~ON_XMLNodePropertyIteratorPrivate() { delete m_paSortedProperties; m_paSortedProperties = nullptr; @@ -3588,67 +3624,66 @@ ON_XMLNode::PropertyIterator::CImpl::~CImpl() ON_XMLNode::PropertyIterator::PropertyIterator(const ON_XMLNode* pNode, bool bSorted) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new ON_XMLNodePropertyIteratorPrivate; - m_impl->m_bSorted = bSorted; + _private->m_bSorted = bSorted; - if (m_impl->m_bSorted) + if (_private->m_bSorted) { if (pNode->PropertyCount() > 1) { - m_impl->m_pNode = pNode; - m_impl->m_iIndex = 0; + _private->m_pNode = pNode; + _private->m_iIndex = 0; } else { - m_impl->m_bSorted = false; + _private->m_bSorted = false; } } - if (!m_impl->m_bSorted) + if (!_private->m_bSorted) { if (nullptr != pNode) { - m_impl->m_pCurrent = pNode->Impl().m_first_property; + _private->m_pCurrent = pNode->_private->m_first_property; } } } ON_XMLNode::PropertyIterator::PropertyIterator(const PropertyIterator& other) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new ON_XMLNodePropertyIteratorPrivate; operator = (other); } ON_XMLNode::PropertyIterator::~PropertyIterator() { - m_impl->~CImpl(); - m_impl = nullptr; + delete _private; } const ON_XMLNode::PropertyIterator& ON_XMLNode::PropertyIterator::operator = (const PropertyIterator& other) { - m_impl->m_pCurrent = other.m_impl->m_pCurrent; - m_impl->m_pNode = other.m_impl->m_pNode; - m_impl->m_iIndex = other.m_impl->m_iIndex; - m_impl->m_bSorted = other.m_impl->m_bSorted; - m_impl->m_paSortedProperties = other.m_impl->m_paSortedProperties; + _private->m_pCurrent = other._private->m_pCurrent; + _private->m_pNode = other._private->m_pNode; + _private->m_iIndex = other._private->m_iIndex; + _private->m_bSorted = other._private->m_bSorted; + _private->m_paSortedProperties = other._private->m_paSortedProperties; return *this; } ON_XMLProperty* ON_XMLNode::PropertyIterator::GetNextProperty(void) { - if (m_impl->m_bSorted) - return m_impl->GetNextPropertySorted(); + if (_private->m_bSorted) + return _private->GetNextPropertySorted(); - auto* pProp = m_impl->m_pCurrent; - if (nullptr != pProp) + ON_XMLProperty* prop = _private->m_pCurrent; + if (nullptr != prop) { - m_impl->m_pCurrent = pProp->Impl().m_pNext; + _private->m_pCurrent = prop->_private->_next; } - return pProp; + return prop; } void* ON_XMLNode::PropertyIterator::EVF(const wchar_t*, void*) @@ -3659,28 +3694,26 @@ void* ON_XMLNode::PropertyIterator::EVF(const wchar_t*, void*) // ON_XMLRootNode // TODO: Somehow I managed to port the non-rc version of the root node. -// We really need the rc version. +// TODO: We really need the rc version. static const ON_wString sXMLRootNodeName(L"xml"); -class ON_XMLRootNode::CImpl final -{ -public: -}; +//class ON_XMLRootNodePrivate final // For future use. +//{ +//}; ON_XMLRootNode::ON_XMLRootNode() : ON_XMLNode(sXMLRootNodeName) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = nullptr; //new ON_XMLRootNodePrivate; } ON_XMLRootNode::ON_XMLRootNode(const ON_XMLNode& src) : ON_XMLNode(sXMLRootNodeName) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; - + _private = nullptr; //new ON_XMLRootNodePrivate; *this = src; } @@ -3688,15 +3721,13 @@ ON_XMLRootNode::ON_XMLRootNode(const ON_XMLRootNode& src) : ON_XMLNode(sXMLRootNodeName) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; - + _private = nullptr; //new ON_XMLRootNodePrivate; *this = src; } ON_XMLRootNode::~ON_XMLRootNode() { - m_impl->~CImpl(); - m_impl = nullptr; + //delete _private; } const ON_XMLRootNode& ON_XMLRootNode::operator = (const ON_XMLNode& src) @@ -3793,27 +3824,17 @@ void ON_XMLRootNode::Clear(void) SetTagName(sXMLRootNodeName); } -ON_XMLRootNode::CImpl& ON_XMLRootNode::Impl(void) const -{ - return *m_impl; -} - // ON_XMLUserData -- Specializes ON_UserData for XML use. -class ON_XMLUserData::CImpl final +class ON_XMLUserDataPrivate final { public: ON_XMLRootNode m_XMLRoot; }; -ON_XMLUserData::CImpl& ON_XMLUserData::Impl(void) const -{ - return *m_impl; -} - ON_XMLUserData::ON_XMLUserData() { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLUserDataPrivate; PRIVATE_CHECK(ON_XMLUserDataPrivate); m_userdata_copycount = 1; m_userdata_uuid = ON_nil_uuid; @@ -3823,7 +3844,7 @@ ON_XMLUserData::ON_XMLUserData(const ON_XMLUserData& ud) : ON_UserData(ud) { - m_impl = new (m_Impl) CImpl; IMPL_CHECK; + _private = new (_PRIVATE) ON_XMLUserDataPrivate; PRIVATE_CHECK(ON_XMLUserDataPrivate); m_userdata_copycount = ud.m_userdata_copycount; m_userdata_uuid = ud.m_userdata_uuid; @@ -3831,8 +3852,8 @@ ON_XMLUserData::ON_XMLUserData(const ON_XMLUserData& ud) ON_XMLUserData::~ON_XMLUserData() { - m_impl->~CImpl(); - m_impl = nullptr; + _private->~ON_XMLUserDataPrivate(); + _private = nullptr; } const ON_XMLUserData& ON_XMLUserData::operator = (const ON_XMLUserData& ud) @@ -3841,19 +3862,19 @@ const ON_XMLUserData& ON_XMLUserData::operator = (const ON_XMLUserData& ud) m_userdata_uuid = ud.m_userdata_uuid; - m_impl->m_XMLRoot = ud.m_impl->m_XMLRoot; + _private->m_XMLRoot = ud._private->m_XMLRoot; return *this; } const ON_XMLRootNode& ON_XMLUserData::XMLRootForRead(void) const { - return m_impl->m_XMLRoot.NodeForRead(); + return _private->m_XMLRoot.NodeForRead(); } ON_XMLRootNode& ON_XMLUserData::XMLRootForWrite(void) const { - return m_impl->m_XMLRoot.NodeForWrite(); + return _private->m_XMLRoot.NodeForWrite(); } ON_XMLProperty* ON_XMLUserData::Property(const wchar_t* wszXMLPath, const wchar_t* wszPropertyName) const @@ -3902,7 +3923,7 @@ void ON_XMLUserData::SetValue(const wchar_t* wszXMLPath, const ON_XMLVariant& va void ON_XMLUserData::Clear(void) const { - m_impl->m_XMLRoot.Clear(); + _private->m_XMLRoot.Clear(); } int ON_XMLUserData::Version(void) const @@ -3912,7 +3933,7 @@ int ON_XMLUserData::Version(void) const ON_XMLProperty* ON_XMLUserData::InternalProperty(const wchar_t* wszXMLPath, const wchar_t* wszPropertyName) const { - const auto* pNode = m_impl->m_XMLRoot.NodeForRead().GetNodeAtPath(wszXMLPath); + const auto* pNode = _private->m_XMLRoot.NodeForRead().GetNodeAtPath(wszXMLPath); if (nullptr == pNode) return nullptr; @@ -4015,7 +4036,7 @@ bool ON_XMLUserData::Write(ON_BinaryArchive& archive) const void ON_XMLUserData::_Dump(const wchar_t* wszFileName) const { - m_impl->m_XMLRoot.WriteToFile(wszFileName); + _private->m_XMLRoot.WriteToFile(wszFileName); } void* ON_XMLUserData::EVF(const wchar_t*, void*) @@ -4025,14 +4046,14 @@ void* ON_XMLUserData::EVF(const wchar_t*, void*) // ON_XMLParameters -class ON_XMLParameters::CImpl +class ON_XMLParametersPrivate { public: - CImpl(ON_XMLNode& n) : m_node(n) { } + ON_XMLParametersPrivate(ON_XMLNode& n) : _node(n) { } - ON_XMLNode& m_node; - ON_wString m_sDefaultType; - bool m_bWriteTypeProperty = true; + ON_XMLNode& _node; + ON_wString _default_type; + bool _write_type_property = true; }; ON_XMLNode* ON_XMLParameters::ObtainChildNodeForWrite(ON_XMLNode& node, const wchar_t* wszParamName) const @@ -4054,38 +4075,37 @@ ON_XMLNode* ON_XMLParameters::ObtainChildNodeForWrite(ON_XMLNode& node, const wc ON_XMLParameters::ON_XMLParameters(ON_XMLNode& node) { - m_impl = new CImpl(node); + _private = new ON_XMLParametersPrivate(node); } ON_XMLParameters::ON_XMLParameters(const ON_XMLNode& node) { - m_impl = new CImpl(const_cast(node)); + _private = new ON_XMLParametersPrivate(const_cast(node)); } ON_XMLParameters::~ON_XMLParameters() { - delete m_impl; - m_impl = nullptr; + delete _private; } void ON_XMLParameters::SetWriteTypeProperty(bool b) { - m_impl->m_bWriteTypeProperty = b; + _private->_write_type_property = b; } void ON_XMLParameters::SetDefaultReadType(const wchar_t* wszType) { - m_impl->m_sDefaultType = wszType; + _private->_default_type = wszType; } ON_wString ON_XMLParameters::AsString(void) const { - return m_impl->m_node.String(); + return _private->_node.String(); } void ON_XMLParameters::SetAsString(const wchar_t* wsz) { - m_impl->m_node.ReadFromStream(wsz); + _private->_node.ReadFromStream(wsz); } bool ON_XMLParameters::GetParam(const wchar_t* wszParamName, ON_XMLVariant& vValueOut) const @@ -4093,7 +4113,7 @@ bool ON_XMLParameters::GetParam(const wchar_t* wszParamName, ON_XMLVariant& vVal // This expects the legacy format where the param name is the XML tag. // If you want to use the new system, you should be using ON_XMLParametersV8. - const auto* pNode = m_impl->m_node.GetNodeAtPath(wszParamName); + const auto* pNode = _private->_node.GetNodeAtPath(wszParamName); if (nullptr == pNode) return false; @@ -4109,7 +4129,7 @@ ON_XMLNode* ON_XMLParameters::SetParam(const wchar_t* wszParamName, const ON_XML return nullptr; // Set the parameter node. - return SetParamNode(m_impl->m_node, wszParamName, value); + return SetParamNode(_private->_node, wszParamName, value); } ON_XMLVariant ON_XMLParameters::GetParam(const wchar_t* param_name, const ON_XMLVariant& default_value) const @@ -4162,7 +4182,7 @@ ON_XMLNode* ON_XMLParameters::SetParamNode(ON_XMLNode& node, const wchar_t* wszP pChildNode->SetProperty(prop); } - if (m_impl->m_bWriteTypeProperty) + if (_private->_write_type_property) { // Set type. prop.SetName(L"type"); @@ -4175,12 +4195,12 @@ ON_XMLNode* ON_XMLParameters::SetParamNode(ON_XMLNode& node, const wchar_t* wszP ON_XMLNode& ON_XMLParameters::Node(void) { - return m_impl->m_node; + return _private->_node; } const ON_XMLNode& ON_XMLParameters::Node(void) const { - return m_impl->m_node; + return _private->_node; } bool ON_XMLParameters::GetParamNode(const ON_XMLNode& node, ON_XMLVariant& vValueOut) const @@ -4189,12 +4209,12 @@ bool ON_XMLParameters::GetParamNode(const ON_XMLNode& node, ON_XMLVariant& vValu const auto& v = node.GetDefaultProperty().GetValue(); - ON_wString sType = m_impl->m_sDefaultType; + ON_wString sType = _private->_default_type; - auto* pProp = node.GetNamedProperty(L"type"); - if (nullptr != pProp) + ON_XMLProperty* prop = node.GetNamedProperty(L"type"); + if (nullptr != prop) { - sType = pProp->GetValue().AsString(); + sType = prop->GetValue().AsString(); } else if (sType.IsEmpty()) @@ -4329,10 +4349,10 @@ bool ON_XMLParameters::GetParamNode(const ON_XMLNode& node, ON_XMLVariant& vValu vValueOut = v.AsBuffer(); } - pProp = node.GetNamedProperty(L"units"); - if (nullptr != pProp) + prop = node.GetNamedProperty(L"units"); + if (nullptr != prop) { - const auto sUnits = pProp->GetValue().AsString(); + const auto sUnits = prop->GetValue().AsString(); vValueOut.SetUnits(UnitsFromString(sUnits)); } @@ -4349,10 +4369,11 @@ void* ON_XMLParameters::EVF(const wchar_t*, void*) return nullptr; } -class ON_XMLParameters::CIterator::CImpl +class ON_XMLParametersIteratorPrivate { public: - CImpl(const ON_XMLParameters& p) : m_Params(p), m_XMLIterator(&p.m_impl->m_node) { } + ON_XMLParametersIteratorPrivate(const ON_XMLParameters& p) + : m_Params(p), m_XMLIterator(&p._private->_node) { } const ON_XMLParameters& m_Params; ON_XMLNode::ChildIterator m_XMLIterator; @@ -4360,24 +4381,23 @@ public: ON_XMLParameters::CIterator::CIterator(const ON_XMLParameters& p) { - m_impl = new CImpl(p); + _private = new ON_XMLParametersIteratorPrivate(p); } ON_XMLParameters::CIterator::~CIterator() { - delete m_impl; - m_impl = nullptr; + delete _private; } bool ON_XMLParameters::CIterator::Next(ON_wString& sParamNameOut, ON_XMLVariant& vParamValueOut) const { - const auto* pNode = m_impl->m_XMLIterator.GetNextChild(); + const auto* pNode = _private->m_XMLIterator.GetNextChild(); if (nullptr == pNode) return false; sParamNameOut = pNode->TagName(); - m_impl->m_Params.GetParamNode(*pNode, vParamValueOut); + _private->m_Params.GetParamNode(*pNode, vParamValueOut); return true; } diff --git a/opennurbs_xml.h b/opennurbs_xml.h index cec2f4e6..65d63edd 100644 --- a/opennurbs_xml.h +++ b/opennurbs_xml.h @@ -280,13 +280,16 @@ typedef bool (*ON_XMLRecurseChildrenCallback)(class ON_XMLNode*, void*); #define ON_ENVIRONMENT_PROJECTION_SPHERICAL L"spherical" // Texture simulation. -#define ON_TEXTURE_SIMULATION_FILENAME L"filename" -#define ON_TEXTURE_SIMULATION_REPEAT L"repeat" -#define ON_TEXTURE_SIMULATION_OFFSET L"offset" -#define ON_TEXTURE_SIMULATION_ROTATION L"rotation" -#define ON_TEXTURE_SIMULATION_WRAP_TYPE L"wrap-type" -#define ON_TEXTURE_SIMULATION_MAPPING_CHANNEL L"mapping-channel" -#define ON_TEXTURE_SIMULATION_PROJECTION_MODE L"projection-mode" +#define ON_TEXTURE_SIMULATION_FILENAME L"filename" +#define ON_TEXTURE_SIMULATION_REPEAT L"repeat" +#define ON_TEXTURE_SIMULATION_OFFSET L"offset" +#define ON_TEXTURE_SIMULATION_ROTATION L"rotation" +#define ON_TEXTURE_SIMULATION_WRAP_TYPE L"wrap-type" +#define ON_TEXTURE_SIMULATION_MAPPING_CHANNEL L"mapping-channel" +#define ON_TEXTURE_SIMULATION_PROJECTION_MODE L"projection-mode" +#define ON_TEXTURE_SIMULATION_HAS_TRANSPARENT_COLOR L"has-trans-color" +#define ON_TEXTURE_SIMULATION_TRANSPARENT_COLOR L"trans-color" +#define ON_TEXTURE_SIMULATION_TRANSPARENT_COLOR_SENSITIVITY L"trans-color-sensitivity" #define ON_RDK_POSTFIX_SECTION L"-section" @@ -412,9 +415,8 @@ protected: virtual void StringToPoint(int iValues) const; private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[176]; + class ON_XMLVariantPrivate* _private; + ON__UINT8 _PRIVATE[168+64]; }; class ON_CLASS ON_XMLProperty @@ -449,12 +451,11 @@ public: virtual void* EVF(const wchar_t* func, void* data); private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[32]; - -public: - CImpl& Impl(void) const; + class ON_XMLPropertyPrivate* _private; + ON__UINT8 _PRIVATE[24+64]; + friend class ON_XMLNode; + friend class ON_XMLNodePrivate; + friend class ON_XMLPropertyPrivate; }; class ON_CLASS ON_XMLSegmentedStream @@ -475,9 +476,7 @@ protected: const ON_XMLSegmentedStream& operator = (const ON_XMLSegmentedStream&) = delete; private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[32]; + class ON_XMLSegmentedStreamPrivate* _private; }; class ON_CLASS ON_XMLNode @@ -594,14 +593,14 @@ public: // Serialization. // Number of characters that would have been written if the buffer was big enough. // This value does not include the terminator. - ON__UINT32 m_logical = 0; + ON__UINT32 _logical = 0; // Number of characters that were physically written. Always zero if max_chars is zero. // It is otherwise usually the same as m_logical, but less when the buffer is too small. // This value does not include the terminator. - ON__UINT32 m_physical = 0; + ON__UINT32 _physical = 0; - ON__UINT64 m_reserved = 0; + ON__UINT64 _reserved = 0; }; virtual CharacterCounts WriteToStreamEx (wchar_t* stream, ON__UINT32 max_chars, bool include_formatting = true, bool force_long_format = false, bool sorted_props = false) const; @@ -664,9 +663,7 @@ public: // Iteration. virtual void* EVF(const wchar_t* func, void* data); private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[24]; + class ON_XMLNodeChildIteratorPrivate* _private; }; class ON_CLASS PropertyIterator @@ -682,9 +679,7 @@ public: // Iteration. virtual void* EVF(const wchar_t* func, void* data); private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[64]; + class ON_XMLNodePropertyIteratorPrivate* _private; }; virtual ChildIterator GetChildIterator(void) const; @@ -697,10 +692,10 @@ public: // Iteration. virtual void SetInternalDebuggingFlags(ON__UINT64); private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[168]; - CImpl& Impl(void) const; + class ON_XMLNodePrivate* _private; + ON__UINT8 _PRIVATE[152+64]; + friend class ON_XMLNodePrivate; + friend class ON_XMLNodePropertyIteratorPrivate; }; class ON_CLASS ON_XMLRootNode : public ON_XMLNode @@ -723,10 +718,7 @@ public: virtual void Clear(void) override; private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[24]; - CImpl& Impl(void) const; + class ON_XMLRootNodePrivate* _private; }; class ON_CLASS ON_XMLUserData : public ON_UserData @@ -771,10 +763,8 @@ public: virtual void SetToDefaultsImpl(int) const; private: - class CImpl; - CImpl* m_impl; - ON__UINT8 m_Impl[224]; - CImpl& Impl(void) const; + class ON_XMLUserDataPrivate* _private; + ON__UINT8 _PRIVATE[240+64]; }; class ON_CLASS ON_XMLParameters @@ -815,8 +805,7 @@ public: virtual void* EVF(const wchar_t*, void*); private: - class CImpl; - CImpl* m_impl; + class ON_XMLParametersIteratorPrivate* _private; }; CIterator* NewIterator(void) const; @@ -827,8 +816,8 @@ protected: virtual ON_XMLNode* ObtainChildNodeForWrite(ON_XMLNode& node, const wchar_t* param_name) const; private: - class CImpl; - CImpl* m_impl; + class ON_XMLParametersPrivate* _private; + friend class ON_XMLParametersIteratorPrivate; }; class ON_CLASS ON_XMLParametersV8 : public ON_XMLParameters