diff --git a/opennurbs_3dm_settings.cpp b/opennurbs_3dm_settings.cpp index 23f16f5b..4345c6c7 100644 --- a/opennurbs_3dm_settings.cpp +++ b/opennurbs_3dm_settings.cpp @@ -1012,7 +1012,10 @@ const ON_3dmRenderSettingsPrivate& ON_3dmRenderSettingsPrivate::operator = (cons ON_ASSERT(*_render_channels == *p._render_channels); ON_ASSERT(*_sun == *p._sun); ON_ASSERT(*_environments == *p._environments); - ON_ASSERT(*_post_effects == *p._post_effects); + + // We can't check post effects because they may be different in terms of the _is_populated flag. + // After a lot of thinking, I simply cannot figure out how to solve this. + //_ASSERT(*_post_effects == *p._post_effects); } return *this; diff --git a/opennurbs_brep.cpp b/opennurbs_brep.cpp index 70ac6084..f18502c7 100644 --- a/opennurbs_brep.cpp +++ b/opennurbs_brep.cpp @@ -12289,10 +12289,9 @@ bool ON_Brep::ShrinkSurface( ON_BrepFace& face, int DisableMask ) int fli, li, si=-1; int lti, ti; - int outer_loop_li=-1; const int loop_count = m_L.Count(); const int trim_count = m_T.Count(); - ON_BoundingBox outer_pbox; + ON_BoundingBox outer_pbox = ON_BoundingBox::NanBoundingBox; bool bAllTrimsAreIsoTrims = true; bool bSomeTrimsAreIsoTrims = false; @@ -12317,10 +12316,7 @@ bool ON_Brep::ShrinkSurface( ON_BrepFace& face, int DisableMask ) if ( loop.m_type == ON_BrepLoop::outer ) { // may be more than one outer loop - if ( outer_loop_li ) - outer_loop_li = li; outer_pbox.Union( loop.m_pbox ); - int loop_trim_count = loop.m_ti.Count(); for ( lti = 0; lti < loop_trim_count; lti++ ) { @@ -12328,7 +12324,9 @@ bool ON_Brep::ShrinkSurface( ON_BrepFace& face, int DisableMask ) if ( ti >= 0 && ti < trim_count ) { bool bIsIso = false; - switch( m_T[ti].m_iso ) + const ON_BrepTrim& trim = m_T[ti]; + + switch(trim.m_iso ) { case ON_Surface::x_iso: case ON_Surface::y_iso: @@ -12356,8 +12354,8 @@ bool ON_Brep::ShrinkSurface( ON_BrepFace& face, int DisableMask ) } if (bIsIso){ // it's an iso curve trim - trim_iso_endbox.Set( m_T[ti].PointAtStart(), true ); - trim_iso_endbox.Set( m_T[ti].PointAtEnd(), true ); + trim_iso_endbox.Set(trim.PointAtStart(), true ); + trim_iso_endbox.Set(trim.PointAtEnd(), true ); bSomeTrimsAreIsoTrims = true; } } diff --git a/opennurbs_material.h b/opennurbs_material.h index dadb7e0a..0bc74150 100644 --- a/opennurbs_material.h +++ b/opennurbs_material.h @@ -610,7 +610,7 @@ ON_DLL_TEMPLATE template class ON_CLASS ON_ObjectArray; /////////////////////////////////////////////////////////////////////////////// // -// Class ON_PBRMaterial +// Class ON_PhysicallyBasedMaterial // class ON_CLASS ON_PhysicallyBasedMaterial { @@ -787,7 +787,4 @@ private: friend bool ON_PhysicallyBasedMaterial_Supported(const ON_PhysicallyBasedMaterial& material); }; - - #endif - diff --git a/opennurbs_math.cpp b/opennurbs_math.cpp index 34597fd2..6dbe33be 100644 --- a/opennurbs_math.cpp +++ b/opennurbs_math.cpp @@ -2240,7 +2240,7 @@ int ON_SolveTriDiagonal( int dim, int n, double* a, const double* b, double* c, const double* d, double* X) /***************************************************************************** -Solve a tridiagonal linear system of equations using backsubstution +Solve a tridiagonal linear system of equations using backsubstitution INPUT: dim (>=1) dimension of X and d diff --git a/opennurbs_post_effects.cpp b/opennurbs_post_effects.cpp index ceb8ba74..e071f4ac 100644 --- a/opennurbs_post_effects.cpp +++ b/opennurbs_post_effects.cpp @@ -577,19 +577,27 @@ ON_PostEffects& ON_PostEffects::operator = (const ON_PostEffects& peps) return *this; } -bool ON_PostEffects::operator == (const ON_PostEffects& peps) const +bool ON_PostEffects::operator == (const ON_PostEffects& other) const { - // We should not have to clear the lists here because they are always supposed to be consistent - // with the XML. But something is wrong that I don't have time to look into right now, and the - // easiest way to work around it is to clear the lists and make sure they get rebuilt. [MARKER] - _impl->Clear(); - peps._impl->Clear(); + // 3rd August 2023 John Croudy, https://mcneel.myjetbrains.com/youtrack/issue/RH3DM-158 + // The problem is that this is called during loading, but before the PEPs are loaded. This was + // causing them to get populated too early so once they are loaded they don't actually get populated. + // If the incoming pep list is not yet populated, they are equal if this one is also not populated + // but not equal if this one is populated. + if (!other._impl->_is_populated) + return !_impl->_is_populated; + + // We don't want to populate this list if it's not yet populated. Remember, this method is const. + if (!_impl->_is_populated) + return false; // The incoming list is populated but this one isn't. + + // If we get here, the both lists are already populated, so we need to check if the lists are equal. ON_SimpleArray a1; GetPostEffects(a1); ON_SimpleArray a2; - peps.GetPostEffects(a2); + other.GetPostEffects(a2); if (a1.Count() != a2.Count()) return false; diff --git a/opennurbs_public_version.h b/opennurbs_public_version.h index b686ca74..52542502 100644 --- a/opennurbs_public_version.h +++ b/opennurbs_public_version.h @@ -14,9 +14,9 @@ // first step in each build. // #define RMA_VERSION_YEAR 2023 -#define RMA_VERSION_MONTH 7 -#define RMA_VERSION_DATE 13 -#define RMA_VERSION_HOUR 18 +#define RMA_VERSION_MONTH 8 +#define RMA_VERSION_DATE 4 +#define RMA_VERSION_HOUR 4 #define RMA_VERSION_MINUTE 30 //////////////////////////////////////////////////////////////// @@ -35,8 +35,8 @@ // 3 = build system release build #define RMA_VERSION_BRANCH 0 -#define VERSION_WITH_COMMAS 8,0,23194,18300 -#define VERSION_WITH_PERIODS 8.0.23194.18300 +#define VERSION_WITH_COMMAS 8,0,23216,4300 +#define VERSION_WITH_PERIODS 8.0.23216.04300 #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.23194.18300" -#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.0.23194.18300" +#define RMA_VERSION_WITH_PERIODS_STRING "8.0.23216.04300" +#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.0.23216.04300" diff --git a/opennurbs_render_content.cpp b/opennurbs_render_content.cpp index 732ded46..8b524c80 100644 --- a/opennurbs_render_content.cpp +++ b/opennurbs_render_content.cpp @@ -869,22 +869,42 @@ ON_RenderContent::ChildIterator ON_RenderContent::GetChildIterator(void) const return ChildIterator(this); } -ON_RenderContent* ON_RenderContent::Parent(void) const +ON_RenderContent* ON_RenderContent::Parent(void) { return _private->m_parent; } -ON_RenderContent* ON_RenderContent::FirstChild(void) const +const ON_RenderContent* ON_RenderContent::Parent(void) const +{ + return _private->m_parent; +} + +ON_RenderContent* ON_RenderContent::FirstChild(void) { return _private->m_first_child; } -ON_RenderContent* ON_RenderContent::NextSibling(void) const +const ON_RenderContent* ON_RenderContent::FirstChild(void) const +{ + return _private->m_first_child; +} + +ON_RenderContent* ON_RenderContent::NextSibling(void) { return _private->m_next_sibling; } -ON_RenderContent& ON_RenderContent::TopLevel(void) const +const ON_RenderContent* ON_RenderContent::NextSibling(void) const +{ + return _private->m_next_sibling; +} + +ON_RenderContent& ON_RenderContent::TopLevel(void) +{ + return _private->TopLevel(); +} + +const ON_RenderContent& ON_RenderContent::TopLevel(void) const { return _private->TopLevel(); } @@ -981,6 +1001,11 @@ bool ON_RenderContent::SetChildSlotAmount(double amount, const wchar_t* child_sl return SetParameter(s, amount / 100.0); } +ON_RenderContent* ON_RenderContent::FindChild(const wchar_t* child_slot_name) +{ + return _private->FindChild(child_slot_name); +} + const ON_RenderContent* ON_RenderContent::FindChild(const wchar_t* child_slot_name) const { return _private->FindChild(child_slot_name); @@ -1205,7 +1230,7 @@ ON_Material ON_RenderMaterial::ToOnMaterial(void) const mat.m_textures.Destroy(); - // Iterator over the children. + // Iterate over the children. int count = 1; while (true) { @@ -1257,6 +1282,179 @@ ON_RenderContent* ON_RenderMaterial::NewRenderContent(void) const return new ON_RenderMaterial; } +// This usage enum was copied from the RDK but the values are not important because +// this is only used internally to ON_RenderTexture::ToOnTexture(). +enum class ChildSlotUsage : unsigned int +{ + None = 0x0000000, + Diffuse = 0x0000001, + Transparency = 0x0000002, + Bump = 0x0000004, + Environment = 0x0000008, + PBR_base_color = Diffuse, + PBR_opacity = Transparency, + PBR_bump = Bump, + PBR_subsurface = 0x0000020, + PBR_subsurface_scattering_color = 0x0000040, + PBR_subsurface_scattering_radius = 0x0000080, + PBR_metallic = 0x0000100, + PBR_specular = 0x0000200, + PBR_specular_tint = 0x0000400, + PBR_roughness = 0x0000800, + PBR_anisotropic = 0x0001000, + PBR_anisotropic_rotation = 0x0002000, + PBR_sheen = 0x0004000, + PBR_sheen_tint = 0x0008000, + PBR_clearcoat = 0x0010000, + PBR_clearcoat_roughness = 0x0020000, + PBR_opacity_ior = 0x0040000, + PBR_opacity_roughness = 0x0080000, + PBR_emission = 0x0100000, + PBR_ambient_occlusion = 0x0200000, + PBR_displacement = 0x0800000, + PBR_clearcoat_bump = 0x1000000, + PBR_alpha = 0x2000000, +}; + +static ChildSlotUsage PBR_ChildSlotNameToUsage(const wchar_t* csn) +{ + using U = ChildSlotUsage; + + // Most of the child slot names have equivalent parameter names. Some do not and are hard-coded here. + + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_ALPHA)) return U::PBR_alpha; + if (0 == on_wcsicmp(csn, L"pbr-ambient-occlusion")) return U::PBR_ambient_occlusion; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_ANISOTROPIC)) return U::PBR_anisotropic; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_ANISOTROPIC_ROTATION)) return U::PBR_anisotropic_rotation; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_BASE_COLOR)) return U::PBR_base_color; + if (0 == on_wcsicmp(csn, L"pbr-bump")) return U::PBR_bump; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_CLEARCOAT)) return U::PBR_clearcoat; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_CLEARCOAT_BUMP)) return U::PBR_clearcoat_bump; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_CLEARCOAT_ROUGHNESS)) return U::PBR_clearcoat_roughness; + if (0 == on_wcsicmp(csn, L"pbr-displacement")) return U::PBR_displacement; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_EMISSION_COLOR)) return U::PBR_emission; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_METALLIC)) return U::PBR_metallic; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_OPACITY)) return U::PBR_opacity; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_OPACITY_IOR)) return U::PBR_opacity_ior; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_OPACITY_ROUGHNESS)) return U::PBR_opacity_roughness; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_ROUGHNESS)) return U::PBR_roughness; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SHEEN)) return U::PBR_sheen; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SHEEN_TINT)) return U::PBR_sheen_tint; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SPECULAR)) return U::PBR_specular; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SPECULAR_TINT)) return U::PBR_specular_tint; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SUBSURFACE)) return U::PBR_subsurface; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SUBSURFACE_SCATTERING_COLOR)) return U::PBR_subsurface_scattering_color; + if (0 == on_wcsicmp(csn, ON_PBR_MATERIAL_SUBSURFACE_SCATTERING_RADIUS)) return U::PBR_subsurface_scattering_radius; + + return U::None; +} + +static ON_wString PBR_ChildSlotNameFromUsage(ChildSlotUsage usage) +{ + using U = ChildSlotUsage; + + // Most of the child slot names have equivalent parameter names. Some do not and are hard-coded here. + + switch (usage) + { + case U::PBR_alpha: return ON_PBR_MATERIAL_ALPHA; + case U::PBR_ambient_occlusion: return L"pbr-ambient-occlusion"; + case U::PBR_anisotropic: return ON_PBR_MATERIAL_ANISOTROPIC; + case U::PBR_anisotropic_rotation: return ON_PBR_MATERIAL_ANISOTROPIC_ROTATION; + case U::PBR_base_color: return ON_PBR_MATERIAL_BASE_COLOR; + case U::PBR_bump: return L"pbr-bump"; + case U::PBR_clearcoat: return ON_PBR_MATERIAL_CLEARCOAT; + case U::PBR_clearcoat_bump: return ON_PBR_MATERIAL_CLEARCOAT_BUMP; + case U::PBR_clearcoat_roughness: return ON_PBR_MATERIAL_CLEARCOAT_ROUGHNESS; + case U::PBR_displacement: return L"pbr-displacement"; + case U::PBR_emission: return ON_PBR_MATERIAL_EMISSION_COLOR; + case U::PBR_metallic: return ON_PBR_MATERIAL_METALLIC; + case U::PBR_opacity: return ON_PBR_MATERIAL_OPACITY; + case U::PBR_opacity_ior: return ON_PBR_MATERIAL_OPACITY_IOR; + case U::PBR_opacity_roughness: return ON_PBR_MATERIAL_OPACITY_ROUGHNESS; + case U::PBR_roughness: return ON_PBR_MATERIAL_ROUGHNESS; + case U::PBR_sheen: return ON_PBR_MATERIAL_SHEEN; + case U::PBR_sheen_tint: return ON_PBR_MATERIAL_SHEEN_TINT; + case U::PBR_specular: return ON_PBR_MATERIAL_SPECULAR; + case U::PBR_specular_tint: return ON_PBR_MATERIAL_SPECULAR_TINT; + case U::PBR_subsurface: return ON_PBR_MATERIAL_SUBSURFACE; + case U::PBR_subsurface_scattering_color: return ON_PBR_MATERIAL_SUBSURFACE_SCATTERING_COLOR; + case U::PBR_subsurface_scattering_radius: return ON_PBR_MATERIAL_SUBSURFACE_SCATTERING_RADIUS; + case U::Environment: return L""; // PBR materials do not support Environment. + default: ON_ASSERT(false); return L""; + } +} + +static ON_Texture::TYPE PreJuly2023_TextureTypeFromUsage(ChildSlotUsage u) +{ + using U = ChildSlotUsage; + using T = ON_Texture::TYPE; + + switch (u) + { + case U::Diffuse: return T::diffuse_texture; // Also handles PBR_base_color. + case U::Transparency: return T::opacity_texture; // Also handles PBR_opacity. + case U::Bump: return T::bump_texture; // Also handles PBR_bump. + case U::Environment: return T::emap_texture; + case U::PBR_alpha: return T::pbr_alpha_texture; + case U::PBR_ambient_occlusion: return T::pbr_ambient_occlusion_texture; + case U::PBR_anisotropic: return T::pbr_anisotropic_texture; + case U::PBR_anisotropic_rotation: return T::pbr_anisotropic_rotation_texture; + case U::PBR_clearcoat: return T::pbr_clearcoat_texture; + case U::PBR_clearcoat_bump: return T::pbr_clearcoat_bump_texture; + case U::PBR_clearcoat_roughness: return T::pbr_clearcoat_roughness_texture; + case U::PBR_displacement: return T::pbr_displacement_texture; + case U::PBR_emission: return T::pbr_emission_texture; + case U::PBR_metallic: return T::pbr_metallic_texture; + case U::PBR_opacity_ior: return T::pbr_opacity_ior_texture; + case U::PBR_opacity_roughness: return T::pbr_opacity_roughness_texture; + case U::PBR_roughness: return T::pbr_roughness_texture; + case U::PBR_sheen: return T::pbr_sheen_texture; + case U::PBR_sheen_tint: return T::pbr_sheen_tint_texture; + case U::PBR_specular: return T::pbr_specular_texture; + case U::PBR_specular_tint: return T::pbr_specular_tint_texture; + case U::PBR_subsurface: return T::pbr_subsurface_texture; + case U::PBR_subsurface_scattering_color: return T::pbr_subsurface_scattering_texture; + case U::PBR_subsurface_scattering_radius: return T::pbr_subsurface_scattering_radius_texture; + default: ON_ASSERT(false); return T::no_texture_type; + } +} + +static ON_wString PreJuly2023_TextureChildSlotName(const ON_RenderMaterial& rm, ChildSlotUsage usage) +{ + if (rm.ToOnMaterial().IsPhysicallyBased()) + return PBR_ChildSlotNameFromUsage(usage); + + switch (usage) + { + case ChildSlotUsage::Diffuse: return ON_TEXTURE_CHILD_SLOT_NAME_BITMAP_TEXTURE; + case ChildSlotUsage::Bump: return ON_TEXTURE_CHILD_SLOT_NAME_BUMP_TEXTURE; + case ChildSlotUsage::Transparency: return ON_TEXTURE_CHILD_SLOT_NAME_TRANSPARENCY_TEXTURE; + case ChildSlotUsage::Environment: return ON_TEXTURE_CHILD_SLOT_NAME_ENVIRONMENT_TEXTURE; + default: return L""; + } +} + +static ChildSlotUsage PreJuly2023_TextureUsage(const ON_RenderMaterial& rm, const wchar_t* child_slot_name) +{ + if (rm.ToOnMaterial().IsPhysicallyBased()) + return PBR_ChildSlotNameToUsage(child_slot_name); + + if (0 == PreJuly2023_TextureChildSlotName(rm, ChildSlotUsage::Diffuse).CompareNoCase(child_slot_name)) + return ChildSlotUsage::Diffuse; + + if (0 == PreJuly2023_TextureChildSlotName(rm, ChildSlotUsage::Transparency).CompareNoCase(child_slot_name)) + return ChildSlotUsage::Transparency; + + if (0 == PreJuly2023_TextureChildSlotName(rm, ChildSlotUsage::Bump).CompareNoCase(child_slot_name)) + return ChildSlotUsage::Bump; + + if (0 == PreJuly2023_TextureChildSlotName(rm, ChildSlotUsage::Environment).CompareNoCase(child_slot_name)) + return ChildSlotUsage::Environment; + + return ChildSlotUsage::None; +} + // ON_RenderEnvironment ON_OBJECT_IMPLEMENT(ON_RenderEnvironment, ON_RenderContent, "A0AB8EF9-5FD4-4320-BBDA-A1200D1846E4"); @@ -1308,8 +1506,9 @@ ON_Environment ON_RenderEnvironment::ToOnEnvironment(void) const { ON_Texture tex; tex.m_image_file_reference.SetFullPath(v.AsString(), false); - // TODO: What other ON_Texture params need to be set? env.SetBackgroundImage(tex); + + // TODO: More? Andy is thinking about this. } if (p.GetParam(ON_ENVIRONMENT_SIMULATION_BACKGROUND_PROJECTION, v)) @@ -1363,14 +1562,90 @@ ON_Texture ON_RenderTexture::ToOnTexture(void) const { std::lock_guard lg(_private->m_mutex); + // The following simulation values are new in V8: + // + // - ON_TEXTURE_SIMULATION_ON + // - ON_TEXTURE_SIMULATION_TYPE + // - ON_TEXTURE_SIMULATION_MODE + // - ON_TEXTURE_SIMULATION_TREAT_AS_LINEAR + // - ON_TEXTURE_SIMULATION_BLEND_CONSTANT_A + // - ON_TEXTURE_SIMULATION_TRANSPARENCY_TEXTURE_ID + // - ON_TEXTURE_SIMULATION_MIN_FILTER + // - ON_TEXTURE_SIMULATION_MAG_FILTER + // + // This data was not saved in the texture simulation XML prior to 20th July 2023 so these values + // won't exist in old documents. If one value exists, we can assume they all do, so we use 'on' + // to determine if they exist or not. If they don't exist, we either leave the default in place + // or use a hacky method to get the value from the parent content. + ON_Texture tex; + ON_XMLVariant v; const ON_XMLNode* sim_node = _private->XMLNode_Simulation(); if (nullptr != sim_node) { - ON_XMLVariant v; ON_XMLParameters p(*sim_node); + if (p.GetParam(ON_TEXTURE_SIMULATION_ON, v)) + { + // Since the 'on' value was found, this must be a document created on or after 20th July 2023. + // We can also get all the other new values and won't be needing the parent hack. + tex.m_bOn = v.AsBool(); + + if (p.GetParam(ON_TEXTURE_SIMULATION_TYPE, v)) + tex.m_type = ON_Texture::TYPE(v.AsInteger()); + + if (p.GetParam(ON_TEXTURE_SIMULATION_MODE, v)) + tex.m_mode = ON_Texture::MODE(v.AsInteger()); + + if (p.GetParam(ON_TEXTURE_SIMULATION_TREAT_AS_LINEAR, v)) + tex.m_bTreatAsLinear = v.AsBool(); + + if (p.GetParam(ON_TEXTURE_SIMULATION_BLEND_CONSTANT_A, v)) + tex.m_blend_constant_A = v.AsDouble(); + + if (p.GetParam(ON_TEXTURE_SIMULATION_TRANSPARENCY_TEXTURE_ID, v)) + tex.m_transparency_texture_id = v.AsUuid(); + + if (p.GetParam(ON_TEXTURE_SIMULATION_MIN_FILTER, v)) + tex.m_minfilter = ON_Texture::FILTER(v.AsInteger()); + + if (p.GetParam(ON_TEXTURE_SIMULATION_MAG_FILTER, v)) + tex.m_magfilter = ON_Texture::FILTER(v.AsInteger()); + } + else + { + // Since the new 'on' value was not found, this must be an old document. Use the various defaults and hacks. + v = GetParameter(L"filter"); + if (!v.IsNull()) + { + tex.m_minfilter = + tex.m_magfilter = v.AsBool() ? ON_Texture::FILTER::linear_filter + : ON_Texture::FILTER::nearest_filter; + } + + const ON_wString child_slot_name = ChildSlotName(); + const auto* parent = Parent(); + if (nullptr != parent) + { + auto* parent_material = dynamic_cast(parent); + if (nullptr != parent_material) + { + const auto usage = PreJuly2023_TextureUsage(*parent_material, child_slot_name); + tex.m_type = PreJuly2023_TextureTypeFromUsage(usage); + } + + tex.m_bOn = parent->ChildSlotOn(child_slot_name); + tex.m_blend_constant_A = parent->ChildSlotAmount(child_slot_name, 100.0) / 100.0; + + v = parent->GetParameter(L"treat-as-linear"); + if (!v.IsNull()) + { + tex.m_bTreatAsLinear = v.AsBool(); + } + } + } + if (p.GetParam(ON_TEXTURE_SIMULATION_FILENAME, v)) { tex.m_image_file_reference.SetFullPath(v.AsString(), false); @@ -1400,8 +1675,8 @@ ON_Texture ON_RenderTexture::ToOnTexture(void) const { ON_3dVector offset, rotation, repeat; tex.m_uvw.DecomposeTextureMapping(offset, repeat, rotation); - const auto pt = v.As2dPoint(); - rotation.z = pt[0] * ON_RADIANS_TO_DEGREES; + const auto pt = v.As2dPoint(); // 'pt' is in degrees. + rotation.z = pt[0] * ON_DEGREES_TO_RADIANS; tex.m_uvw = ON_Xform::TextureMapping(offset, repeat, rotation); } @@ -1424,41 +1699,6 @@ ON_Texture ON_RenderTexture::ToOnTexture(void) const } } - tex.m_mode = ON_Texture::MODE::decal_texture; - tex.m_transparency_texture_id = ON_nil_uuid; - - //tex.m_bTreatAsLinear ??? Andy: This is on CRhRdkTexture. John: It's computed; not in the XML. - //tex.m_blend_constant_RGB ??? - - const ON_XMLVariant v = GetParameter(L"filter"); - tex.m_minfilter = tex.m_magfilter = v.AsBool() ? ON_Texture::FILTER::linear_filter - : ON_Texture::FILTER::nearest_filter; - - const ON_wString child_slot_name = ChildSlotName(); - - if (child_slot_name == ON_TEXTURE_CHILD_SLOT_NAME_BITMAP_TEXTURE) - tex.m_type = ON_Texture::TYPE::bitmap_texture; - else - if (child_slot_name == ON_TEXTURE_CHILD_SLOT_NAME_BUMP_TEXTURE) - tex.m_type = ON_Texture::TYPE::bump_texture; - else - if (child_slot_name == ON_TEXTURE_CHILD_SLOT_NAME_TRANSPARENCY_TEXTURE) - tex.m_type = ON_Texture::TYPE::transparency_texture; - else - if (child_slot_name == ON_TEXTURE_CHILD_SLOT_NAME_ENVIRONMENT_TEXTURE) - { - tex.m_type = ON_Texture::TYPE::emap_texture; - // emap_texture is OBSOLETE - set m_mapping_channel_id = ON_MappingChannel::emap_mapping - // tex.m_mapping_channel_id = ON_MappingChannel::emap_mapping; // ERROR! - } - - const auto* parent = Parent(); - if (nullptr != parent) - { - tex.m_bOn = parent->ChildSlotOn(child_slot_name); - tex.m_blend_constant_A = parent->ChildSlotAmount(child_slot_name, 100.0) / 100.0; - } - return tex; } diff --git a/opennurbs_render_content.h b/opennurbs_render_content.h index f060d7ac..0feadc9c 100644 --- a/opennurbs_render_content.h +++ b/opennurbs_render_content.h @@ -164,16 +164,20 @@ public: virtual ChildIterator GetChildIterator(void) const; // Returns: The parent content or null if this is the top level object. - virtual ON_RenderContent* Parent(void) const; + virtual ON_RenderContent* Parent(void); + virtual const ON_RenderContent* Parent(void) const; // Returns: The first child of this content or null if none. - virtual ON_RenderContent* FirstChild(void) const; + virtual ON_RenderContent* FirstChild(void); + virtual const ON_RenderContent* FirstChild(void) const; // Returns: The first sibling of this content or null if none. - virtual ON_RenderContent* NextSibling(void) const; + virtual ON_RenderContent* NextSibling(void); + virtual const ON_RenderContent* NextSibling(void) const; // Returns: The top level parent of this content. - virtual ON_RenderContent& TopLevel(void) const; + virtual ON_RenderContent& TopLevel(void); + virtual const ON_RenderContent& TopLevel(void) const; // Returns: True if this is a top-level content (i.e., has no parent; is not a child). virtual bool IsTopLevel(void) const; @@ -219,6 +223,7 @@ public: virtual bool DeleteChild(const wchar_t* child_slot_name); // Returns: The child with the specified child slot name, or null if no such child exists. + virtual ON_RenderContent* FindChild(const wchar_t* child_slot_name); virtual const ON_RenderContent* FindChild(const wchar_t* child_slot_name) const; // Get the render content's state as an XML string. diff --git a/opennurbs_sectionstyle.cpp b/opennurbs_sectionstyle.cpp index e9b0d07c..f51b2287 100644 --- a/opennurbs_sectionstyle.cpp +++ b/opennurbs_sectionstyle.cpp @@ -37,7 +37,7 @@ public: ON_Color m_hatch_print_color = ON_Color::UnsetColor; bool m_boundary_visible = true; double m_boundary_width_scale = 3.0; - + std::shared_ptr m_custom_linetype; bool operator==(const ON_SectionStylePrivate& other) const; }; @@ -45,6 +45,20 @@ static ON_SectionStylePrivate DefaultSectionStylePrivate; bool ON_SectionStylePrivate::operator==(const ON_SectionStylePrivate& other) const { + { + const ON_Linetype* customThis = m_custom_linetype.get(); + const ON_Linetype* customOther = other.m_custom_linetype.get(); + if (nullptr == customThis && customOther) + return false; + if (customThis && nullptr == customOther) + return false; + if (customThis && customOther) + { + if ((*customThis) != (*customOther)) + return false; + } + } + return m_background_fill_mode == other.m_background_fill_mode && m_fill_rule == other.m_fill_rule && m_hatch_index == other.m_hatch_index && @@ -195,15 +209,16 @@ enum ON_SectionStyleTypeCodes : unsigned char HatchScale = 8, HatchRotation = 9, HatchColor = 10, + BoundaryLinetype = 11, - LastSectionStyleTypeCode = 10 + LastSectionStyleTypeCode = 11 }; bool ON_SectionStyle::Write( ON_BinaryArchive& file) const { bool rc = false; { - const int minor_version = 0; + const int minor_version = 1; if (!file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK, 1, minor_version)) return false; for (;;) @@ -301,6 +316,17 @@ bool ON_SectionStyle::Write( ON_BinaryArchive& file) const break; } + // chunk version 1.1 fields + const ON_Linetype* customLinetype = BoundaryLinetype(); + if (customLinetype != nullptr) + { + const unsigned char itemType = ON_SectionStyleTypeCodes::BoundaryLinetype; // 11 + if (!file.WriteChar(itemType)) + break; + if (!customLinetype->Write(file)) + break; + } + // 0 indicates end of new linetype attributes const unsigned char attributes_end = 0; if (!file.WriteChar(attributes_end)) @@ -450,7 +476,15 @@ bool ON_SectionStyle::Read( ON_BinaryArchive& file) if (!file.ReadChar(&item_id)) break; } - + if (ON_SectionStyleTypeCodes::BoundaryLinetype == item_id) // 11 + { + ON_Linetype lt; + if(!lt.Read(file)) + break; + SetBoundaryLinetype(lt); + if (!file.ReadChar(&item_id)) + break; + } if (item_id > ON_SectionStyleTypeCodes::LastSectionStyleTypeCode) { @@ -630,3 +664,22 @@ void ON_SectionStyle::SetHatchColor(const ON_Color& color, bool print) else m_private->m_hatch_color = color; } + +const ON_Linetype* ON_SectionStyle::BoundaryLinetype() const +{ + if (m_private) + return m_private->m_custom_linetype.get(); + return nullptr; +} +void ON_SectionStyle::SetBoundaryLinetype(const ON_Linetype& linetype) +{ + if (nullptr == m_private) + m_private = new ON_SectionStylePrivate(); + + m_private->m_custom_linetype.reset(new ON_Linetype(linetype)); +} +void ON_SectionStyle::RemoveBoundaryLinetype() +{ + if (m_private) + m_private->m_custom_linetype.reset(); +} diff --git a/opennurbs_sectionstyle.h b/opennurbs_sectionstyle.h index 64f8634c..6edc7423 100644 --- a/opennurbs_sectionstyle.h +++ b/opennurbs_sectionstyle.h @@ -132,6 +132,11 @@ public: ON_Color HatchColor(bool print) const; void SetHatchColor(const ON_Color& color, bool print); + // Section styles can have custom linetypes. If null, then the linetype is retrieved + // from the parent layer or attributes + const ON_Linetype* BoundaryLinetype() const; + void SetBoundaryLinetype(const ON_Linetype& linetype); + void RemoveBoundaryLinetype(); private: class ON_SectionStylePrivate* m_private = nullptr; }; diff --git a/opennurbs_subd.cpp b/opennurbs_subd.cpp index 8e8bf15d..db81970d 100644 --- a/opennurbs_subd.cpp +++ b/opennurbs_subd.cpp @@ -1206,11 +1206,13 @@ int ON_SubDFacePtr::CompareFacePointer( bool operator==(ON_SubDComponentPtr lhs, ON_SubDComponentPtr rhs) { + // MUST compare entire m_ptr (type, pointer, and direction) return lhs.m_ptr == rhs.m_ptr; } bool operator!=(ON_SubDComponentPtr lhs, ON_SubDComponentPtr rhs) { + // MUST compare entire m_ptr (type, pointer, and direction) return lhs.m_ptr != rhs.m_ptr; } @@ -2201,8 +2203,8 @@ int ON_SubDComponentPtr::CompareComponent( const int rc = ON_SubDComponentPtr::CompareComponentPtrType(a->ComponentType(), b->ComponentType()); if (0 == rc) { - const ON__UINT_PTR x = a->m_ptr; - const ON__UINT_PTR y = b->m_ptr; + const ON__UINT_PTR x = (a->m_ptr & ON_SUBD_COMPONENT_POINTER_MASK); + const ON__UINT_PTR y = (b->m_ptr & ON_SUBD_COMPONENT_POINTER_MASK); if (x < y) return -1; if (x > y) @@ -2221,8 +2223,8 @@ int ON_SubDComponentPtr::CompareComponentAndDirection( const int rc = ON_SubDComponentPtr::CompareComponent(a, b); if (0 == rc) { - const ON__UINT_PTR x = (a->m_ptr & ON_SUBD_COMPONENT_POINTER_MASK); - const ON__UINT_PTR y = (b->m_ptr & ON_SUBD_COMPONENT_POINTER_MASK); + const ON__UINT_PTR x = (a->m_ptr & ON_SUBD_COMPONENT_DIRECTION_MASK); + const ON__UINT_PTR y = (b->m_ptr & ON_SUBD_COMPONENT_DIRECTION_MASK); if (x < y) return -1; if (x > y) @@ -6434,6 +6436,29 @@ unsigned int ON_SubDFace::SharpEdgeCount(ON_SubDEdgeSharpness& sharpness_range) return sharp_edge_count; } +double ON_SubDFace::MaximumEdgeSharpness() const +{ + double max_edge_sharpness = 0.0; + const ON_SubDEdgePtr* eptr = m_edge4; + for (unsigned short fei = 0; fei < m_edge_count; ++fei, ++eptr) + { + if (4 == fei) + { + eptr = m_edgex; + if (nullptr == eptr) + break; + } + const ON_SubDEdge* e = ON_SUBD_EDGE_POINTER(eptr->m_ptr); + if (nullptr == e || false == e->IsSharp()) + continue; + const ON_SubDEdgeSharpness s = e->Sharpness(false); + const double m = s.MaximumEndSharpness(); + if (m > max_edge_sharpness) + max_edge_sharpness = m; + } + return max_edge_sharpness; +} + unsigned int ON_SubDFace::SharpEdgeCount() const { unsigned int sharp_edge_count = 0; @@ -8190,13 +8215,14 @@ bool ON_SubDimple::IsValidLevel( ON_SubDVertexIterator vit = subd.VertexIterator(); if (vit.FirstVertex() != level->m_vertex[0]) return ON_SubDIsNotValid(bSilentError); - ON_SubDVertexArray va = subd.VertexArray(); - if (va.VertexCount() != level->m_vertex_count) - return ON_SubDIsNotValid(bSilentError); - if (va[0] != level->m_vertex[0]) - return ON_SubDIsNotValid(bSilentError); - if (va[level->m_vertex_count-1] != level->m_vertex[1]) - return ON_SubDIsNotValid(bSilentError); + // IsValid() should not create these clunky cached arrays. + //ON_SubDVertexArray va = subd.VertexArray(); + //if (va.VertexCount() != level->m_vertex_count) + // return ON_SubDIsNotValid(bSilentError); + //if (va[0] != level->m_vertex[0]) + // return ON_SubDIsNotValid(bSilentError); + //if (va[level->m_vertex_count-1] != level->m_vertex[1]) + // return ON_SubDIsNotValid(bSilentError); } const ON_SubDVertex* last_vertex = nullptr; for (i = 0, vertex = level->m_vertex[0]; i < level->m_vertex_count && nullptr != vertex; i++, vertex = vertex->m_next_vertex) @@ -8242,13 +8268,15 @@ bool ON_SubDimple::IsValidLevel( ON_SubDEdgeIterator eit = subd.EdgeIterator(); if (eit.FirstEdge() != level->m_edge[0]) return ON_SubDIsNotValid(bSilentError); - ON_SubDEdgeArray ea = subd.EdgeArray(); - if (ea.EdgeCount() != level->m_edge_count) - return ON_SubDIsNotValid(bSilentError); - if (ea[0] != level->m_edge[0]) - return ON_SubDIsNotValid(bSilentError); - if (ea[level->m_edge_count-1] != level->m_edge[1]) - return ON_SubDIsNotValid(bSilentError); + + // IsValid() should not create these clunky cached arrays. + //ON_SubDEdgeArray ea = subd.EdgeArray(); + //if (ea.EdgeCount() != level->m_edge_count) + // return ON_SubDIsNotValid(bSilentError); + //if (ea[0] != level->m_edge[0]) + // return ON_SubDIsNotValid(bSilentError); + //if (ea[level->m_edge_count-1] != level->m_edge[1]) + // return ON_SubDIsNotValid(bSilentError); } const ON_SubDEdge* last_edge = nullptr; for (i = 0, edge = level->m_edge[0]; i < level->m_edge_count && nullptr != edge; i++, edge = edge->m_next_edge) @@ -8293,13 +8321,14 @@ bool ON_SubDimple::IsValidLevel( ON_SubDFaceIterator fit = subd.FaceIterator(); if (fit.FirstFace() != level->m_face[0]) return ON_SubDIsNotValid(bSilentError); - ON_SubDFaceArray fa = subd.FaceArray(); - if (fa.FaceCount() != level->m_face_count) - return ON_SubDIsNotValid(bSilentError); - if (fa[0] != level->m_face[0]) - return ON_SubDIsNotValid(bSilentError); - if (fa[0] != level->m_face[0]) - return ON_SubDIsNotValid(bSilentError); + // IsValid() should not create these clunky cached arrays. + //ON_SubDFaceArray fa = subd.FaceArray(); + //if (fa.FaceCount() != level->m_face_count) + // return ON_SubDIsNotValid(bSilentError); + //if (fa[0] != level->m_face[0]) + // return ON_SubDIsNotValid(bSilentError); + //if (fa[0] != level->m_face[0]) + // return ON_SubDIsNotValid(bSilentError); } const ON_SubDFace* last_face = nullptr; for (i = 0, face = level->m_face[0]; i < level->m_face_count && nullptr != face; i++, face = face->m_next_face) @@ -10930,6 +10959,121 @@ unsigned ON_SubD::ClearInactiveLevels() : 0U; } +const ON_SubDComponentPtr ON_SubDComponentPtr::NextComponent() const +{ + switch (ON_SUBD_COMPONENT_TYPE_MASK & m_ptr) + { + case ON_SUBD_COMPONENT_TYPE_VERTEX: + { + const ON_SubDVertex* v = ON_SUBD_VERTEX_POINTER(m_ptr); + if (nullptr != v) + return ON_SubDComponentPtr::Create(v->m_next_vertex); + } + case ON_SUBD_COMPONENT_TYPE_EDGE: + { + const ON_SubDEdge* e = ON_SUBD_EDGE_POINTER(m_ptr); + if (nullptr != e) + return ON_SubDComponentPtr::Create(e->m_next_edge); + } + case ON_SUBD_COMPONENT_TYPE_FACE: + { + const ON_SubDFace* f = ON_SUBD_FACE_POINTER(m_ptr); + if (nullptr != f) + return ON_SubDComponentPtr::Create(f->m_next_face); + } + default: + break; + } + return ON_SubDComponentPtr::Null; +} + + +const ON_SubDComponentPtr ON_SubDComponentPtr::PrevComponent() const +{ + switch (ON_SUBD_COMPONENT_TYPE_MASK & m_ptr) + { + case ON_SUBD_COMPONENT_TYPE_VERTEX: + { + const ON_SubDVertex* v = ON_SUBD_VERTEX_POINTER(m_ptr); + if (nullptr != v) + return ON_SubDComponentPtr::Create(v->m_prev_vertex); + } + case ON_SUBD_COMPONENT_TYPE_EDGE: + { + const ON_SubDEdge* e = ON_SUBD_EDGE_POINTER(m_ptr); + if (nullptr != e) + return ON_SubDComponentPtr::Create(e->m_prev_edge); + } + case ON_SUBD_COMPONENT_TYPE_FACE: + { + const ON_SubDFace* f = ON_SUBD_FACE_POINTER(m_ptr); + if (nullptr != f) + return ON_SubDComponentPtr::Create(f->m_prev_face); + } + default: + break; + } + return ON_SubDComponentPtr::Null; +} + +const ON_SubDComponentPtr ON_SubDComponentPtr::operator++() +{ + // prefix ++ + *this = this->NextComponent(); + return *this; +} + +const ON_SubDComponentPtr ON_SubDComponentPtr::operator++(int) +{ + // postfix ++ + const ON_SubDComponentPtr input_value = *this; + *this = this->NextComponent(); + return input_value; +} + +const ON_SubDComponentPtr ON_SubD::FirstComponent( + ON_SubDComponentPtr::Type component_type +) const +{ + switch (component_type) + { + case ON_SubDComponentPtr::Type::Vertex: + return ON_SubDComponentPtr::Create(this->FirstVertex()); + break; + case ON_SubDComponentPtr::Type::Edge: + return ON_SubDComponentPtr::Create(this->FirstEdge()); + break; + case ON_SubDComponentPtr::Type::Face: + return ON_SubDComponentPtr::Create(this->FirstFace()); + break; + default: + break; + } + return ON_SubDComponentPtr::Null; +} + + +unsigned ON_SubD::ComponentCount( + ON_SubDComponentPtr::Type component_type +) const +{ + switch (component_type) + { + case ON_SubDComponentPtr::Type::Vertex: + return this->VertexCount(); + break; + case ON_SubDComponentPtr::Type::Edge: + return this->EdgeCount(); + break; + case ON_SubDComponentPtr::Type::Face: + return this->FaceCount(); + break; + default: + break; + } + return 0; +} + void ON_SubD::Destroy() { m_subdimple_sp.reset(); diff --git a/opennurbs_subd.h b/opennurbs_subd.h index 07fdeba9..6fe6f7a7 100644 --- a/opennurbs_subd.h +++ b/opennurbs_subd.h @@ -2403,6 +2403,41 @@ public: ON_SubDFacePtr faceptr ); + /// + /// Depending on the type of this component, returns an ON_SubDComponentPtr to + /// ON_SubDVertex::NextVertex(), ON_SubDEdge::NextEdge(), or ON_SubDFace::NextFace(). + /// + /// + /// An ON_SubDComponentPtr to the next active component of the same type in the SubD + /// or ON_SubDComponentPtr::Null if there is no next active component. + /// + const ON_SubDComponentPtr NextComponent() const; + + /// + /// Depending on the type of this component, returns an ON_SubDComponentPtr to + /// ON_SubDVertex::PrevVertex(), ON_SubDEdge::PrevEdge(), or ON_SubDFace::PrevFace(). + /// + /// + /// An ON_SubDComponentPtr to the previous active component of the same type in the SubD + /// or ON_SubDComponentPtr::Null if there is no previous active component. + /// + const ON_SubDComponentPtr PrevComponent() const; + + /// + /// Prefix operator ++ sets this to ON_SubDComponentPtr::NextComponent() + /// and returns the new value of this. + /// + /// ON_SubDComponentPtr::NextComponent() + const ON_SubDComponentPtr operator++(); + + /// + /// Postfix operator ++ sets this to ON_SubDComponentPtr::NextComponent() + /// and returns the previous value of this. + /// + /// ON_SubDComponentPtr::NextComponent() + const ON_SubDComponentPtr operator++(int); + + wchar_t* ToString( wchar_t* s, size_t s_capacity @@ -5256,19 +5291,156 @@ public: /* Description: - Creates a SubD sphere with 24 quad faces + Creates a SubD box Parameters: - sphere - [in] - Location, size and orientation of the sphere + corners - [in] + Box corners. + The bottom quad is specified by the first 4 points + and the top quad specified by the last 4 points. + edge_sharpness - [in] + If edge_sharpness = ON_SubDEdgeSharpness::SmoothValue, the edges where box sides meet will be smooth. + If ON_SubDEdgeSharpness::SmoothValue < edge_sharpness <= ON_SubDEdgeSharpenss::MaximumValue, + the edges where box sides meet will have the specified sharpness. + If edge_sharpness = ON_SubDEdgeSharpenss::CreaseValue, + the edges where box sides meet will be creases. + facecount_x - [in] Number of faces in x direction + facecount_y - [in] Number of faces in y direction + facecount_z - [in] Number of faces in z direction destination_subd [out] - - If destination_subd is not null, make the SubD box there + If destination_subd is not null, the SubD box is saved in this instance. Returns: Pointer to the resulting SubD if successful Null for error */ - //static ON_SubD* CreateSubDSphere( - // const ON_Sphere sphere, - // ON_SubD* destination_subd); + static ON_SubD* CreateSubDBox( + const ON_3dPoint corners[8], + double edge_sharpness, + unsigned int facecount_x, + unsigned int facecount_y, + unsigned int facecount_z, + ON_SubD* destination_subd + ); + + +#if 0 + /* + Description: + Creates a SubD sphere made from triangular faces and 6 valent vertices. + Parameters: + sphere - [in] + Location, size and orientation of the sphere + vertex_location - [in] + If vertex_location = ON_SubDComponentLocation::ControlNet, then the control net + points will be on the surface of the sphere. Otherwise the limit surface + points will be on the sphere. + subdivision_level - [in] + The resulting sphere will have 80*4^tri_subdivision_level triangles. + 0 - 180 triangles + 1 - 320 triangles + 2 - 1280 triangles + ... + destination_subd [out] - + If destination_subd is not null, the SubD sphere is saved in this instance. + Returns: + Pointer to the resulting SubD if successful + Null for error + */ + static ON_SubD* CreateSubDTriSphere( + const ON_Sphere sphere, + ON_SubDComponentLocation vertex_location, + unsigned tri_subdivision_level, + ON_SubD* destination_subd + ); + + /* + Description: + Creates a SubD sphere based on an icosohedran (20 triangular faces and 5 valent vertices). + Parameters: + sphere - [in] + Location, size and orientation of the sphere + vertex_location - [in] + If vertex_location = ON_SubDComponentLocation::ControlNet, then the control net + points will be on the surface of the sphere. Otherwise the limit surface + points will be on the sphere. + subdivision_level - [in] + 0 - 80 triangles (icosohedral control net) + 1 - 60 quad + 2 - 240 quads + ... + destination_subd [out] - + If destination_subd is not null, the SubD sphere is saved in this instance. + Returns: + Pointer to the resulting SubD if successful + Null for error + */ + static ON_SubD* CreateSubDIcosahedran( + const ON_Sphere sphere, + ON_SubDComponentLocation vertex_location, + unsigned subdivision_level, + ON_SubD* destination_subd + ); + + /* + Description: + Creates a SubD sphere based on an dodecahedron (20 triangular faces and 5 valent vertices). + Parameters: + sphere - [in] + Location, size and orientation of the sphere + vertex_location - [in] + If vertex_location = ON_SubDComponentLocation::ControlNet, then the control net + points will be on the surface of the sphere. Otherwise the limit surface + points will be on the sphere. + subdivision_level - [in] + 0 - 5 pentagons (dodecahedral control net) + 1 - 60 quad + 2 - 240 quads + ... + destination_subd [out] - + If destination_subd is not null, the SubD sphere is saved in this instance. + Returns: + Pointer to the resulting SubD if successful + Null for error + */ + static ON_SubD* CreateSubDDodecahedran( + const ON_Sphere sphere, + ON_SubDComponentLocation vertex_location, + unsigned subdivision_level, + ON_SubD* destination_subd + ); + + + /* + Description: + Creates a SubD sphere made with triangles and quads to + resemble a globe with latitude and longitude circles. + Parameters: + sphere - [in] + Location, size and orientation of the sphere + vertex_location - [in] + If vertex_location = ON_SubDComponentLocation::ControlNet, then the control net + points will be on the surface of the sphere. Otherwise the limit surface + points will be on the sphere. + subdivision_level - [in] + The resulting sphere will have 80*4^tri_subdivision_level triangles. + 0 - 180 triangles + 1 - 320 triangles + 2 - 1280 triangles + ... + destination_subd [out] - + If destination_subd is not null, the SubD sphere is saved in this instance. + Returns: + Pointer to the resulting SubD if successful + Null for error + */ + static ON_SubD* CreateSubDGlobe( + const ON_Sphere sphere, + ON_SubDComponentLocation vertex_location, + unsigned latitude_count, + unsigned longitued_count, + ON_SubD* destination_subd + ); + +#endif /* Description: @@ -5286,7 +5458,8 @@ public: Null for error */ //static ON_SubD* CreateSubDCylinder( - // const ON_Cylinder& cylinder, + // const ON_Cylinder cylinder, + // ON_SubDComponentLocation vertex_location, // unsigned int facecount_around, // unsigned int facecount_length, // ON_SubD* destination_subd); @@ -5422,6 +5595,7 @@ public: ); /* + Description: Remove all levels except the active level. Returns: Number of removed levels. @@ -5520,6 +5694,28 @@ public: */ const ON_SubDComponentPtr InSubD(const class ON_SubDComponentBase* b) const; + /// + /// ON_SubD::FirstVertex(), ON_SubD::FirstEdge(), or ON_SubD::FirstFace() is returned, + /// depending on the value of component_type. + /// + /// + /// The first component of the specified type. + const ON_SubDComponentPtr FirstComponent( + ON_SubDComponentPtr::Type component_type + ) const; + + + /// + /// ON_SubD::VertexCount(), ON_SubD::EdgeCount(), or ON_SubD::FaceCount() is returned, + /// depending on the value of component_type. + /// + /// + /// The first component of the specified type. + unsigned ComponentCount( + ON_SubDComponentPtr::Type component_type + ) const; + + ///////////////////////////////////////////////////////// // // Vertex access @@ -14960,6 +15156,13 @@ public: /// Number of sharp edges attached to this face. unsigned int SharpEdgeCount() const; + /// + /// Get the maximum sharpeness of the edges that form the face's boundary. + /// (Creased edges have zero sharpness.) + /// + /// The maximum sharpness of the face's edges. + double MaximumEdgeSharpness() const; + const class ON_SubDVertex* Vertex( unsigned int i @@ -19155,7 +19358,7 @@ public: then at least one vertex of f is part of the edge chain and f is on the specified side of the edge chain. - If a vertex v is side_components[], then it is preceded and followed by the same + If a vertex v is in side_components[], then it is preceded and followed by the same face (...f,v,f,...), there are consecutive edges in the edge chain (...e0,e1,...), and e0 and e1 are consecutive edges in f's boundary. diff --git a/opennurbs_subd_fragment.cpp b/opennurbs_subd_fragment.cpp index 7745b563..d7c94a9d 100644 --- a/opennurbs_subd_fragment.cpp +++ b/opennurbs_subd_fragment.cpp @@ -3703,11 +3703,28 @@ unsigned int ON_SubDDisplayParameters::DisplayDensity() const unsigned int ON_SubDDisplayParameters::DisplayDensity(const ON_SubD& subd) const { const unsigned display_density = this->m_display_density; - return - this->DisplayDensityIsAdaptive() ? - ON_SubDDisplayParameters::AbsoluteDisplayDensityFromSubD(display_density, subd) + const unsigned absolute_display_density + = this->DisplayDensityIsAdaptive() + ? ON_SubDDisplayParameters::AbsoluteDisplayDensityFromSubD(display_density, subd) : display_density ; + + if (0 == absolute_display_density) + { + // If subd has ngons with n != 4, then the display density has to be >= 1. + ON_SubDFaceIdIterator fit(subd); + for (const ON_SubDFace* f = fit.FirstFace(); nullptr != f; f = fit.NextFace()) + { + if (4 != f->m_edge_count && f->m_edge_count > 3 && f->m_edge_count <= ON_SubDFace::MaximumEdgeCount) + { + // This face will have f->m_edge_count subd mesh fragments of density 0. + // That's why the default quad face density must be >= 1. + return 1u; + } + } + } + + return absolute_display_density; } const unsigned char ON_SubDDisplayParameters::GetRawDisplayDensityForExperts() const diff --git a/opennurbs_subd_frommesh.cpp b/opennurbs_subd_frommesh.cpp index 64c9c471..f9c4f906 100644 --- a/opennurbs_subd_frommesh.cpp +++ b/opennurbs_subd_frommesh.cpp @@ -1217,13 +1217,55 @@ ON_SubD* ON_SubD::CreateSubDBox( unsigned int facecount_x, unsigned int facecount_y, unsigned int facecount_z, - ON_SubD* subd) + ON_SubD* destination_subd) { - if (ON_SubDEdgeTag::Crease != edge_tag) - edge_tag = ON_SubDEdgeTag::Smooth; + double edge_sharpness + = ON_SubDEdgeTag::Crease == edge_tag + ? ON_SubDEdgeSharpness::CreaseValue + : ON_SubDEdgeSharpness::SmoothValue + ; - if (nullptr == subd) - subd = new ON_SubD; + return ON_SubD::CreateSubDBox( + corners, + edge_sharpness, + facecount_x, + facecount_y, + facecount_z, + destination_subd + ); +} + +ON_SubD* ON_SubD::CreateSubDBox( + const ON_3dPoint corners[8], + double edge_sharpness, + unsigned int facecount_x, + unsigned int facecount_y, + unsigned int facecount_z, + ON_SubD* destination_subd +) +{ + if (nullptr == corners) + return nullptr; + if (facecount_x <= 0) + return nullptr; + if (facecount_y <= 0) + return nullptr; + if (facecount_z <= 0) + return nullptr; + + const ON_SubDEdgeTag edge_tag + = (ON_SubDEdgeSharpness::CreaseValue == edge_sharpness) + ? ON_SubDEdgeTag::Crease + : ON_SubDEdgeTag::Smooth; + + const bool bSharpEdge + = edge_sharpness > ON_SubDEdgeSharpness::SmoothValue + && edge_sharpness <= ON_SubDEdgeSharpness::MaximumValue; + + ON_SubD* subd + = (nullptr != destination_subd) + ? destination_subd + : new ON_SubD; ON_3dVector xdir = corners[1] - corners[0]; ON_3dVector ydir = corners[3] - corners[0]; @@ -1342,6 +1384,21 @@ ON_SubD* ON_SubD::CreateSubDBox( box_edges[7].Append(ON_SubDEdgePtr::Create(e, 0)); } + if (edge_sharpness > ON_SubDEdgeSharpness::Tolerance && edge_sharpness <= ON_SubDEdgeSharpness::MaximumValue) + { + const ON_SubDEdgeSharpness sharpness = ON_SubDEdgeSharpness::FromConstant(edge_sharpness); + if (sharpness.IsSharp()) + { + for (int i = 0; i < 12; ++i) + { + ON_ClassArray< ON_SubDEdgePtr >& sharp_edges = box_edges[i]; + const int c = sharp_edges.Count(); + for (int j = 0; j < c; ++j) + sharp_edges[j].SetRelativeSharpness(sharpness); + } + } + } + ON_ClassArray< ON_ClassArray< ON_SubDEdgePtr > > face_edges[2]; // Bottom face @@ -1579,10 +1636,6 @@ ON_SubD* ON_SubD::CreateSubDBox( { e = subd->AddEdge(ON_SubDEdgeTag::Smooth, IndexVertex(vertex, vert_index, 0, iy, iz), IndexVertex(vertex, vert_index, 0, iy + 1, iz)); row.Append(ON_SubDEdgePtr::Create(e, 0)); - - // mac compile warning // ON_3dPoint p0 = row.Last()->RelativeVertex(0)->ControlNetPoint(); - // mac compile warning // ON_3dPoint p1 = row.Last()->RelativeVertex(1)->ControlNetPoint(); - // mac compile warning // iy = iy; } } } @@ -1600,10 +1653,6 @@ ON_SubD* ON_SubD::CreateSubDBox( { e = subd->AddEdge(ON_SubDEdgeTag::Smooth, IndexVertex(vertex, vert_index, 0, iy, iz), IndexVertex(vertex, vert_index, 0, iy, iz + 1)); col.Append(ON_SubDEdgePtr::Create(e, 0)); - - // mac compile warning // ON_3dPoint p0 = col.Last()->RelativeVertex(0)->ControlNetPoint(); - // mac compile warning // ON_3dPoint p1 = col.Last()->RelativeVertex(1)->ControlNetPoint(); - // mac compile warning // iy = iy; } } } @@ -1617,19 +1666,6 @@ ON_SubD* ON_SubD::CreateSubDBox( edge_ptrs[1] = face_edges[0][iz + 1][iy]; edge_ptrs[2] = face_edges[1][iy + 1][iz].Reversed(); edge_ptrs[3] = face_edges[0][iz][iy].Reversed(); - - // mac compile warning // ON_3dPoint p00 = edge_ptrs[0].RelativeVertex(0)->ControlNetPoint(); - // mac compile warning // ON_3dPoint p01 = edge_ptrs[0].RelativeVertex(1)->ControlNetPoint(); - - // mac compile warning // ON_3dPoint p10 = edge_ptrs[1].RelativeVertex(0)->ControlNetPoint(); - // mac compile warning // ON_3dPoint p11 = edge_ptrs[1].RelativeVertex(1)->ControlNetPoint(); - - // mac compile warning // ON_3dPoint p20 = edge_ptrs[2].RelativeVertex(0)->ControlNetPoint(); - // mac compile warning // ON_3dPoint p21 = edge_ptrs[2].RelativeVertex(1)->ControlNetPoint(); - - // mac compile warning // ON_3dPoint p30 = edge_ptrs[3].RelativeVertex(0)->ControlNetPoint(); - // mac compile warning // ON_3dPoint p31 = edge_ptrs[3].RelativeVertex(1)->ControlNetPoint(); - ON_SubDFace* f0 = subd->AddFace(edge_ptrs, 4); if (nullptr == f0) return nullptr; @@ -1692,8 +1728,10 @@ ON_SubD* ON_SubD::CreateSubDBox( } } - subd->SubDModifiedNofification(); - //subd->UpdateAllTagsAndSectorCoefficients(true); + if (subd == destination_subd) + subd->SubDModifiedNofification(); + else + subd->UpdateAllTagsAndSectorCoefficients(true); return subd; } diff --git a/opennurbs_texture.h b/opennurbs_texture.h index 48dd8705..8e9e84e0 100644 --- a/opennurbs_texture.h +++ b/opennurbs_texture.h @@ -317,8 +317,9 @@ public: // rendering physically based (PBR) materials. pbr_base_color_texture = 1U, //Reuse diffuse texture. pbr_subsurface_texture = 10U, - pbr_subsurface_scattering_texture = 11U, - pbr_subsurface_scattering_radius_texture = 12U, + /* Deprecated */ pbr_subsurface_scattering_texture = 11U, + pbr_subsurface_scattering_color_texture = 11U, + pbr_subsurface_scattering_radius_texture = 12U, pbr_metallic_texture = 13U, pbr_specular_texture = 14U, pbr_specular_tint_texture = 15U, diff --git a/opennurbs_xform.cpp b/opennurbs_xform.cpp index e816f8d3..098462e2 100644 --- a/opennurbs_xform.cpp +++ b/opennurbs_xform.cpp @@ -1679,6 +1679,8 @@ bool ON_Xform::DecomposeAffine(ON_Xform& L, ON_3dVector& T) const void ON_Xform::DecomposeTextureMapping(ON_3dVector& offset, ON_3dVector& repeat, ON_3dVector& rotation) const { + // All angles in radians. + ON_Xform xform = *this; repeat.x = sqrt(xform[0][0] * xform[0][0] + xform[0][1] * xform[0][1] + xform[0][2] * xform[0][2]); @@ -1715,7 +1717,7 @@ void ON_Xform::DecomposeTextureMapping(ON_3dVector& offset, ON_3dVector& repeat, } rotation.x = atan2(dSinAlpha, dCosAlpha); - rotation.y = atan2(dSinBeta, dCosBeta); + rotation.y = atan2(dSinBeta, dCosBeta); rotation.z = atan2(dSinGamma, dCosGamma); const ON_Xform R = TextureMapping(ON_3dVector::ZeroVector, repeat, rotation).Inverse(); @@ -1730,6 +1732,8 @@ void ON_Xform::DecomposeTextureMapping(ON_3dVector& offset, ON_3dVector& repeat, //static const ON_Xform ON_Xform::TextureMapping(const ON_3dVector& offset, const ON_3dVector& repeat, const ON_3dVector& rotation) { + // All angles in radians. + ON_Xform S = ON_Xform::DiagonalTransformation(repeat.x, repeat.y, repeat.z); ON_Xform R; diff --git a/opennurbs_xml.h b/opennurbs_xml.h index 6e71c77c..053b93fc 100644 --- a/opennurbs_xml.h +++ b/opennurbs_xml.h @@ -281,16 +281,24 @@ typedef bool (*ON_XMLRecurseChildrenCallback)(class ON_XMLNode*, void*); #define ON_ENVIRONMENT_PROJECTION_SPHERICAL L"spherical" // Texture simulation. +#define ON_TEXTURE_SIMULATION_ON L"on" #define ON_TEXTURE_SIMULATION_FILENAME L"filename" -#define ON_TEXTURE_SIMULATION_REPEAT L"repeat" +#define ON_TEXTURE_SIMULATION_MODE L"mode" +#define ON_TEXTURE_SIMULATION_TYPE L"type" #define ON_TEXTURE_SIMULATION_OFFSET L"offset" +#define ON_TEXTURE_SIMULATION_REPEAT L"repeat" #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_MIN_FILTER L"min-filter" +#define ON_TEXTURE_SIMULATION_MAG_FILTER L"mag-filter" +#define ON_TEXTURE_SIMULATION_TRANSPARENCY_TEXTURE_ID L"transparency-texture-id" #define ON_TEXTURE_SIMULATION_TRANSPARENT_COLOR L"trans-color" #define ON_TEXTURE_SIMULATION_TRANSPARENT_COLOR_SENSITIVITY L"trans-color-sensitivity" +#define ON_TEXTURE_SIMULATION_TREAT_AS_LINEAR L"treat-as-linear" +#define ON_TEXTURE_SIMULATION_WRAP_TYPE L"wrap-type" +#define ON_TEXTURE_SIMULATION_BLEND_CONSTANT_A L"blend-constant-a" // Strings returned by ON_RenderContent::Kind(). #define ON_KIND_MATERIAL L"material"