/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "Vegetation_precompiled.h" #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////// // #pragma inline_depth(0) namespace Vegetation { namespace DescriptorUtil { static bool UpdateVersion(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement) { if (classElement.GetVersion() < 4) { AZ::Vector3 positionMin(-0.3f, -0.3f, 0.0f); if (classElement.GetChildData(AZ_CRC("PositionMin", 0x1abef6a6), positionMin)) { classElement.RemoveElementByName(AZ_CRC("PositionMin", 0x1abef6a6)); classElement.AddElementWithData(context, "PositionMinX", (float)positionMin.GetX()); classElement.AddElementWithData(context, "PositionMinY", (float)positionMin.GetY()); classElement.AddElementWithData(context, "PositionMinZ", (float)positionMin.GetZ()); } AZ::Vector3 positionMax(0.3f, 0.3f, 0.0f); if (classElement.GetChildData(AZ_CRC("PositionMax", 0x26b3c9ff), positionMax)) { classElement.RemoveElementByName(AZ_CRC("PositionMax", 0x26b3c9ff)); classElement.AddElementWithData(context, "PositionMaxX", (float)positionMax.GetX()); classElement.AddElementWithData(context, "PositionMaxY", (float)positionMax.GetY()); classElement.AddElementWithData(context, "PositionMaxZ", (float)positionMax.GetZ()); } AZ::Vector3 rotationMin(0.0f, 0.0f, -180.0f); if (classElement.GetChildData(AZ_CRC("RotationMin", 0xf556391b), rotationMin)) { classElement.RemoveElementByName(AZ_CRC("RotationMin", 0xf556391b)); classElement.AddElementWithData(context, "RotationMinX", (float)rotationMin.GetX()); classElement.AddElementWithData(context, "RotationMinY", (float)rotationMin.GetY()); classElement.AddElementWithData(context, "RotationMinZ", (float)rotationMin.GetZ()); } AZ::Vector3 rotationMax(0.0f, 0.0f, 180.0f); if (classElement.GetChildData(AZ_CRC("RotationMax", 0xc95b0642), rotationMax)) { classElement.RemoveElementByName(AZ_CRC("RotationMax", 0xc95b0642)); classElement.AddElementWithData(context, "RotationMaxX", (float)rotationMax.GetX()); classElement.AddElementWithData(context, "RotationMaxY", (float)rotationMax.GetY()); classElement.AddElementWithData(context, "RotationMaxZ", (float)rotationMax.GetZ()); } } if (classElement.GetVersion() < 5) { classElement.RemoveElementByName(AZ_CRC("RadiusMax", 0x5e90f2ea)); } if (classElement.GetVersion() < 6) { AZStd::shared_ptr baseInstanceSpawner = LegacyVegetationInstanceSpawner::ConvertLegacyDescriptorData(classElement); classElement.AddElementWithData(context, "InstanceSpawner", baseInstanceSpawner); } if (classElement.GetVersion() < 7) { // The only type of spawners supported prior to this version were legacy vegetation spawners. classElement.AddElementWithData(context, "SpawnerType", AZStd::string("Legacy Vegetation")); } if (classElement.GetVersion() < 8) { // Spawner type was briefly stored as a display string instead of a TypeId. AZStd::string spawnerType; if (classElement.GetChildData(AZ_CRC("SpawnerType", 0xbabb9f23), spawnerType)) { AZ::TypeId newSpawnerType = azrtti_typeid(); if (spawnerType == "Legacy Vegetation") { newSpawnerType = azrtti_typeid(); } else if (spawnerType == "Dynamic Slice") { newSpawnerType = azrtti_typeid(); } classElement.RemoveElementByName(AZ_CRC("SpawnerType", 0xbabb9f23)); classElement.AddElementWithData(context, "SpawnerType", newSpawnerType); } } return true; } } AZStd::fixed_vector, Descriptor::m_maxSpawnerTypesExpected> Descriptor::m_spawnerTypes; void Descriptor::Reflect(AZ::ReflectContext* context) { // Don't reflect again if we're already reflected to the passed in context if (context->IsTypeReflected(VegetationDescriptorTypeId)) { return; } SurfaceTagDistance::Reflect(context); AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { serialize->RegisterGenericType>(); serialize->Class() ->Version(8, &DescriptorUtil::UpdateVersion) ->Field("SpawnerType", &Descriptor::m_spawnerType) ->Field("InstanceSpawner", &Descriptor::m_instanceSpawner) ->Field("Weight", &Descriptor::m_weight) ->Field("Advanced", &Descriptor::m_advanced) ->Field("PositionOverrideEnabled", &Descriptor::m_positionOverrideEnabled) ->Field("PositionMinX", &Descriptor::m_positionMinX) ->Field("PositionMaxX", &Descriptor::m_positionMaxX) ->Field("PositionMinY", &Descriptor::m_positionMinY) ->Field("PositionMaxY", &Descriptor::m_positionMaxY) ->Field("PositionMinZ", &Descriptor::m_positionMinZ) ->Field("PositionMaxZ", &Descriptor::m_positionMaxZ) ->Field("RotationOverrideEnabled", &Descriptor::m_rotationOverrideEnabled) ->Field("RotationMinX", &Descriptor::m_rotationMinX) ->Field("RotationMaxX", &Descriptor::m_rotationMaxX) ->Field("RotationMinY", &Descriptor::m_rotationMinY) ->Field("RotationMaxY", &Descriptor::m_rotationMaxY) ->Field("RotationMinZ", &Descriptor::m_rotationMinZ) ->Field("RotationMaxZ", &Descriptor::m_rotationMaxZ) ->Field("ScaleOverrideEnabled", &Descriptor::m_scaleOverrideEnabled) ->Field("ScaleMin", &Descriptor::m_scaleMin) ->Field("ScaleMax", &Descriptor::m_scaleMax) ->Field("AltitudeFilterOverrideEnabled", &Descriptor::m_altitudeFilterOverrideEnabled) ->Field("AltitudeFilterMin", &Descriptor::m_altitudeFilterMin) ->Field("AltitudeFilterMax", &Descriptor::m_altitudeFilterMax) ->Field("RadiusOverrideEnabled", &Descriptor::m_radiusOverrideEnabled) ->Field("BoundMode", &Descriptor::m_boundMode) ->Field("RadiusMin", &Descriptor::m_radiusMin) ->Field("SurfaceAlignmentOverrideEnabled", &Descriptor::m_surfaceAlignmentOverrideEnabled) ->Field("SurfaceAlignmentMin", &Descriptor::m_surfaceAlignmentMin) ->Field("SurfaceAlignmentMax", &Descriptor::m_surfaceAlignmentMax) ->Field("SlopeFilterOverrideEnabled", &Descriptor::m_slopeFilterOverrideEnabled) ->Field("SlopeFilterMin", &Descriptor::m_slopeFilterMin) ->Field("SlopeFilterMax", &Descriptor::m_slopeFilterMax) ->Field("SurfaceFilterOverrideMode", &Descriptor::m_surfaceFilterOverrideMode) ->Field("InclusiveSurfaceFilterTags", &Descriptor::m_inclusiveSurfaceFilterTags) ->Field("ExclusiveSurfaceFilterTags", &Descriptor::m_exclusiveSurfaceFilterTags) ->Field("SurfaceTagDistance", &Descriptor::m_surfaceTagDistance) ; AZ::EditContext* edit = serialize->GetEditContext(); if (edit) { edit->Class( "Vegetation Descriptor", "Details used to create vegetation instances") // For this ComboBox to actually work, there is a PropertyHandler registration in EditorVegetationSystemComponent.cpp ->DataElement(AZ::Edit::UIHandlers::ComboBox, &Descriptor::m_spawnerType, "Instance Spawner", "The type of instances to spawn") ->Attribute(AZ::Edit::Attributes::GenericValueList, &Descriptor::GetSpawnerTypeList) ->Attribute(AZ::Edit::Attributes::ChangeNotify, &Descriptor::SpawnerTypeChanged) ->DataElement(AZ::Edit::UIHandlers::Default, &Descriptor::m_instanceSpawner, "Instance", "Instance data") ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly) ->DataElement(0, &Descriptor::m_weight, "Weight", "Weight counted against the total density of the placed vegetation sector") ->DataElement(0, &Descriptor::m_advanced, "Display Per-Item Overrides", "Display the per-item override settings that can be used with filter and modifier components when those components have 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree) ->ClassElement(AZ::Edit::ClassElements::Group, "Position Modifier") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_positionOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Position Modifier has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_positionMinX, "Min X", "Minimum position offset on X axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -2.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsPositionFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_positionMaxX, "Max X", "Maximum position offset on X axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -2.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsPositionFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_positionMinY, "Min Y", "Minimum position offset on Y axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -2.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsPositionFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_positionMaxY, "Max Y", "Maximum position offset on Y axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -2.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsPositionFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_positionMinZ, "Min Z", "Minimum position offset on Z axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -2.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsPositionFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_positionMaxZ, "Max Z", "Maximum position offset on Z axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -2.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsPositionFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "Rotation Modifier") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_rotationOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Rotation Modifier has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_rotationMinX, "Min X", "Minimum rotation offset on X axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -180.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRotationFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_rotationMaxX, "Max X", "Maximum rotation offset on X axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -180.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRotationFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_rotationMinY, "Min Y", "Minimum rotation offset on Y axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -180.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRotationFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_rotationMaxY, "Max Y", "Maximum rotation offset on Y axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -180.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRotationFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_rotationMinZ, "Min Z", "Minimum rotation offset on Z axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -180.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRotationFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_rotationMaxZ, "Max Z", "Maximum rotation offset on Z axis.") ->Attribute(AZ::Edit::Attributes::Min, std::numeric_limits::lowest()) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMin, -180.0f) ->Attribute(AZ::Edit::Attributes::SoftMax, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRotationFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "Scale Modifier") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_scaleOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Scale Modifier has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_scaleMin, "Min", "") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::SoftMax, 10.0f) ->Attribute(AZ::Edit::Attributes::Step, 0.125f) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsScaleFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_scaleMax, "Max", "") ->Attribute(AZ::Edit::Attributes::Min, 0.01f) ->Attribute(AZ::Edit::Attributes::SoftMax, 10.0f) ->Attribute(AZ::Edit::Attributes::Step, 0.125f) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsScaleFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "Altitude Filter") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_altitudeFilterOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Altitude Filter has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(0, &Descriptor::m_altitudeFilterMin, "Min", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsAltitudeFilterReadOnly) ->DataElement(0, &Descriptor::m_altitudeFilterMax, "Max", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsAltitudeFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "Distance Between Filter (Radius)") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_radiusOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Distance Between Filter has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &Descriptor::m_boundMode, "Bound Mode", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetBoundModeVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->EnumAttribute(BoundMode::Radius, "Radius") ->EnumAttribute(BoundMode::MeshRadius, "MeshRadius") ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsDistanceBetweenFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_radiusMin, "Radius Min", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsRadiusReadOnly) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, std::numeric_limits::max()) ->Attribute(AZ::Edit::Attributes::SoftMax, 16.0f) // match current default sector size in meters. ->ClassElement(AZ::Edit::ClassElements::Group, "Surface Slope Alignment") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_surfaceAlignmentOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Surface Slope Alignment Modifier has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_surfaceAlignmentMin, "Min", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 1.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsSurfaceAlignmentFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_surfaceAlignmentMax, "Max", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 1.0f) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsSurfaceAlignmentFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "Slope Filter") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(0, &Descriptor::m_slopeFilterOverrideEnabled, "Override Enabled", "Enable per-item override settings for this item when the Slope Filter has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_slopeFilterMin, "Min", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsSlopeFilterReadOnly) ->DataElement(AZ::Edit::UIHandlers::Slider, &Descriptor::m_slopeFilterMax, "Max", "") ->Attribute(AZ::Edit::Attributes::Min, 0.0f) ->Attribute(AZ::Edit::Attributes::Max, 180.0f) ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsSlopeFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "Surface Mask Filter") ->Attribute(AZ::Edit::Attributes::AutoExpand, false) ->DataElement(AZ::Edit::UIHandlers::ComboBox, &Descriptor::m_surfaceFilterOverrideMode, "Override Mode", "Enable per-item override settings for this item when the Surface Mask Filter has 'Allow Per-Item Overrides' enabled.") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->EnumAttribute(OverrideMode::Disable, "Disable") ->EnumAttribute(OverrideMode::Replace, "Replace") ->EnumAttribute(OverrideMode::Extend, "Extend") ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(0, &Descriptor::m_inclusiveSurfaceFilterTags, "Inclusion Tags", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsSurfaceTagFilterReadOnly) ->DataElement(0, &Descriptor::m_exclusiveSurfaceFilterTags, "Exclusion Tags", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ->Attribute(AZ::Edit::Attributes::ReadOnly, &Descriptor::IsSurfaceTagFilterReadOnly) ->ClassElement(AZ::Edit::ClassElements::Group, "") ->DataElement(0, &Descriptor::m_surfaceTagDistance, "Surface Mask Depth Filter", "") ->Attribute(AZ::Edit::Attributes::Visibility, &Descriptor::GetAdvancedGroupVisibility) ; } } if (auto behaviorContext = azrtti_cast(context)) { behaviorContext->Class() ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Category, "Vegetation") ->Attribute(AZ::Script::Attributes::Module, "vegetation") ->Constructor() ->Property("spawnerType", &Descriptor::GetSpawnerType, &Descriptor::SetSpawnerType) ->Property("spawner", &Descriptor::GetSpawner, &Descriptor::SetSpawner) ->Property("weight", BehaviorValueProperty(&Descriptor::m_weight)) ->Property("surfaceTagDistance", BehaviorValueProperty(&Descriptor::m_surfaceTagDistance)) ->Property("surfaceFilterOverrideMode", [](Descriptor* descriptor) { return (AZ::u8)(descriptor->m_surfaceFilterOverrideMode); }, [](Descriptor* descriptor, const AZ::u8& i) { descriptor->m_surfaceFilterOverrideMode = (OverrideMode)i; }) ->Property("radiusOverrideEnabled", BehaviorValueProperty(&Descriptor::m_radiusOverrideEnabled)) ->Property("radiusMin", BehaviorValueProperty(&Descriptor::m_radiusMin)) ->Property("boundMode", [](Descriptor* descriptor) { return (AZ::u8)(descriptor->m_boundMode); }, [](Descriptor* descriptor, const AZ::u8& i) { descriptor->m_boundMode = (BoundMode)i; }) ->Property("surfaceAlignmentOverrideEnabled", BehaviorValueProperty(&Descriptor::m_surfaceAlignmentOverrideEnabled)) ->Property("surfaceAlignmentMin", BehaviorValueProperty(&Descriptor::m_surfaceAlignmentMin)) ->Property("surfaceAlignmentMax", BehaviorValueProperty(&Descriptor::m_surfaceAlignmentMax)) ->Property("rotationOverrideEnabled", BehaviorValueProperty(&Descriptor::m_rotationOverrideEnabled)) ->Property("rotationMinX", BehaviorValueProperty(&Descriptor::m_rotationMinX)) ->Property("rotationMaxX", BehaviorValueProperty(&Descriptor::m_rotationMaxX)) ->Property("rotationMinY", BehaviorValueProperty(&Descriptor::m_rotationMinY)) ->Property("rotationMaxY", BehaviorValueProperty(&Descriptor::m_rotationMaxY)) ->Property("rotationMinZ", BehaviorValueProperty(&Descriptor::m_rotationMinZ)) ->Property("rotationMaxZ", BehaviorValueProperty(&Descriptor::m_rotationMaxZ)) ->Property("positionOverrideEnabled", BehaviorValueProperty(&Descriptor::m_positionOverrideEnabled)) ->Property("positionMinX", BehaviorValueProperty(&Descriptor::m_positionMinX)) ->Property("positionMaxX", BehaviorValueProperty(&Descriptor::m_positionMaxX)) ->Property("positionMinY", BehaviorValueProperty(&Descriptor::m_positionMinY)) ->Property("positionMaxY", BehaviorValueProperty(&Descriptor::m_positionMaxY)) ->Property("positionMinZ", BehaviorValueProperty(&Descriptor::m_positionMinZ)) ->Property("positionMaxZ", BehaviorValueProperty(&Descriptor::m_positionMaxZ)) ->Property("scaleOverrideEnabled", BehaviorValueProperty(&Descriptor::m_scaleOverrideEnabled)) ->Property("scaleMin", BehaviorValueProperty(&Descriptor::m_scaleMin)) ->Property("scaleMax", BehaviorValueProperty(&Descriptor::m_scaleMax)) ->Property("altitudeFilterOverrideEnabled", BehaviorValueProperty(&Descriptor::m_altitudeFilterOverrideEnabled)) ->Property("altitudeFilterMin", BehaviorValueProperty(&Descriptor::m_altitudeFilterMin)) ->Property("altitudeFilterMax", BehaviorValueProperty(&Descriptor::m_altitudeFilterMax)) ->Property("slopeFilterOverrideEnabled", BehaviorValueProperty(&Descriptor::m_slopeFilterOverrideEnabled)) ->Property("slopeFilterMin", BehaviorValueProperty(&Descriptor::m_slopeFilterMin)) ->Property("slopeFilterMax", BehaviorValueProperty(&Descriptor::m_slopeFilterMax)) ->Method("GetNumInclusiveSurfaceFilterTags", &Descriptor::GetNumInclusiveSurfaceFilterTags) ->Method("GetInclusiveSurfaceFilterTag", &Descriptor::GetInclusiveSurfaceFilterTag) ->Method("RemoveInclusiveSurfaceFilterTag", &Descriptor::RemoveInclusiveSurfaceFilterTag) ->Method("AddInclusiveSurfaceFilterTag", &Descriptor::AddInclusiveSurfaceFilterTag) ->Method("GetNumExclusiveSurfaceFilterTags", &Descriptor::GetNumExclusiveSurfaceFilterTags) ->Method("GetExclusiveSurfaceFilterTag", &Descriptor::GetExclusiveSurfaceFilterTag) ->Method("RemoveExclusiveSurfaceFilterTag", &Descriptor::RemoveExclusiveSurfaceFilterTag) ->Method("AddExclusiveSurfaceFilterTag", &Descriptor::AddExclusiveSurfaceFilterTag) ; } } void SurfaceTagDistance::Reflect(AZ::ReflectContext * context) { AZ::SerializeContext* serialize = azrtti_cast(context); if (serialize) { serialize->Class() ->Version(0) ->Field("SurfaceTag", &SurfaceTagDistance::m_tags) ->Field("UpperDistanceInMeters", &SurfaceTagDistance::m_upperDistanceInMeters) ->Field("LowerDistanceInMeters", &SurfaceTagDistance::m_lowerDistanceInMeters) ; AZ::EditContext* edit = serialize->GetEditContext(); if (edit) { edit->Class( "VegetationSurfaceTagDepth", "Describes depth information for a vegetation object based on a tag to match with a surface mask") ->DataElement(0, &SurfaceTagDistance::m_tags, "Surface Tags", "The surface tags to compare the distance from the planting tag to.") ->DataElement(0, &SurfaceTagDistance::m_upperDistanceInMeters, "Upper Distance Range (m)", "Upper Distance in meters from comparison surface, negative for below") ->DataElement(0, &SurfaceTagDistance::m_lowerDistanceInMeters, "Lower Distance Range (m)", "Lower Distance in meters from comparison surface, negative for below") ; } } if (auto behaviorContext = azrtti_cast(context)) { behaviorContext->Class() ->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview) ->Attribute(AZ::Script::Attributes::Category, "Vegetation") ->Constructor() ->Property("upperDistanceInMeters", BehaviorValueProperty(&SurfaceTagDistance::m_upperDistanceInMeters)) ->Property("lowerDistanceInMeters", BehaviorValueProperty(&SurfaceTagDistance::m_lowerDistanceInMeters)) ->Method("GetNumTags", &SurfaceTagDistance::GetNumTags) ->Method("GetTag", &SurfaceTagDistance::GetTag) ->Method("RemoveTag", &SurfaceTagDistance::RemoveTag) ->Method("AddTag", &SurfaceTagDistance::AddTag) ; } } size_t SurfaceTagDistance::GetNumTags() const { return m_tags.size(); } AZ::Crc32 SurfaceTagDistance::GetTag(int tagIndex) const { if (tagIndex < m_tags.size() && tagIndex >= 0) { return m_tags[tagIndex]; } return AZ::Crc32(); } void SurfaceTagDistance::RemoveTag(int tagIndex) { if (tagIndex < m_tags.size() && tagIndex >= 0) { m_tags.erase(m_tags.begin() + tagIndex); } } void SurfaceTagDistance::AddTag(const AZStd::string& tag) { m_tags.push_back(SurfaceData::SurfaceTag(tag)); } bool SurfaceTagDistance::operator==(const SurfaceTagDistance& rhs) const { return m_tags == rhs.m_tags && m_lowerDistanceInMeters == rhs.m_lowerDistanceInMeters && m_upperDistanceInMeters == rhs.m_upperDistanceInMeters; } Descriptor::Descriptor() { // Default instance spawner on new descriptors to legacy vegetation, at least for now. m_instanceSpawner = AZStd::make_shared(); m_spawnerType = azrtti_typeid(*m_instanceSpawner); } Descriptor::~Descriptor() { } bool Descriptor::HasEquivalentInstanceSpawners(const Descriptor& rhs) const { bool instanceSpawnersMatch = false; if (m_spawnerType == rhs.m_spawnerType) { if (m_instanceSpawner == rhs.m_instanceSpawner) { // This will match if they're both null, or both the same pointer. instanceSpawnersMatch = true; } else { // Only match if they're both not null and have equivalent data. if (m_instanceSpawner && rhs.m_instanceSpawner) { instanceSpawnersMatch = (*m_instanceSpawner) == (*rhs.m_instanceSpawner); } } } return instanceSpawnersMatch; } bool Descriptor::operator==(const Descriptor& rhs) const { return HasEquivalentInstanceSpawners(rhs) && m_weight == rhs.m_weight && m_surfaceTagDistance == rhs.m_surfaceTagDistance && m_surfaceFilterOverrideMode == rhs.m_surfaceFilterOverrideMode && m_inclusiveSurfaceFilterTags == rhs.m_inclusiveSurfaceFilterTags && m_exclusiveSurfaceFilterTags == rhs.m_exclusiveSurfaceFilterTags && m_radiusOverrideEnabled == rhs.m_radiusOverrideEnabled && m_radiusMin == rhs.m_radiusMin && m_boundMode == rhs.m_boundMode && m_surfaceAlignmentOverrideEnabled == rhs.m_surfaceAlignmentOverrideEnabled && m_surfaceAlignmentMin == rhs.m_surfaceAlignmentMin && m_surfaceAlignmentMax == rhs.m_surfaceAlignmentMax && m_rotationOverrideEnabled == rhs.m_rotationOverrideEnabled && m_rotationMinX == rhs.m_rotationMinX && m_rotationMaxX == rhs.m_rotationMaxX && m_rotationMinY == rhs.m_rotationMinY && m_rotationMaxY == rhs.m_rotationMaxY && m_rotationMinZ == rhs.m_rotationMinZ && m_rotationMaxZ == rhs.m_rotationMaxZ && m_positionOverrideEnabled == rhs.m_positionOverrideEnabled && m_positionMinX == rhs.m_positionMinX && m_positionMaxX == rhs.m_positionMaxX && m_positionMinY == rhs.m_positionMinY && m_positionMaxY == rhs.m_positionMaxY && m_positionMinZ == rhs.m_positionMinZ && m_positionMaxZ == rhs.m_positionMaxZ && m_scaleOverrideEnabled == rhs.m_scaleOverrideEnabled && m_scaleMin == rhs.m_scaleMin && m_scaleMax == rhs.m_scaleMax && m_altitudeFilterOverrideEnabled == rhs.m_altitudeFilterOverrideEnabled && m_altitudeFilterMin == rhs.m_altitudeFilterMin && m_altitudeFilterMax == rhs.m_altitudeFilterMax && m_slopeFilterOverrideEnabled == rhs.m_slopeFilterOverrideEnabled && m_slopeFilterMin == rhs.m_slopeFilterMin && m_slopeFilterMax == rhs.m_slopeFilterMax ; } size_t Descriptor::GetNumInclusiveSurfaceFilterTags() const { return m_inclusiveSurfaceFilterTags.size(); } AZ::Crc32 Descriptor::GetInclusiveSurfaceFilterTag(int tagIndex) const { if (tagIndex < m_inclusiveSurfaceFilterTags.size() && tagIndex >= 0) { return m_inclusiveSurfaceFilterTags[tagIndex]; } return AZ::Crc32(); } void Descriptor::RemoveInclusiveSurfaceFilterTag(int tagIndex) { if (tagIndex < m_inclusiveSurfaceFilterTags.size() && tagIndex >= 0) { m_inclusiveSurfaceFilterTags.erase(m_inclusiveSurfaceFilterTags.begin() + tagIndex); } } void Descriptor::AddInclusiveSurfaceFilterTag(const AZStd::string& tag) { m_inclusiveSurfaceFilterTags.push_back(SurfaceData::SurfaceTag(tag)); } size_t Descriptor::GetNumExclusiveSurfaceFilterTags() const { return m_exclusiveSurfaceFilterTags.size(); } AZ::Crc32 Descriptor::GetExclusiveSurfaceFilterTag(int tagIndex) const { if (tagIndex < m_exclusiveSurfaceFilterTags.size() && tagIndex >= 0) { return m_exclusiveSurfaceFilterTags[tagIndex]; } return AZ::Crc32(); } void Descriptor::RemoveExclusiveSurfaceFilterTag(int tagIndex) { if (tagIndex < m_exclusiveSurfaceFilterTags.size() && tagIndex >= 0) { m_exclusiveSurfaceFilterTags.erase(m_exclusiveSurfaceFilterTags.begin() + tagIndex); } } void Descriptor::AddExclusiveSurfaceFilterTag(const AZStd::string& tag) { m_exclusiveSurfaceFilterTags.push_back(SurfaceData::SurfaceTag(tag)); } AZ::u32 Descriptor::GetAdvancedGroupVisibility() const { return m_advanced ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide; } AZ::u32 Descriptor::GetBoundModeVisibility() const { // Only show Bound Mode if we're showing advanced settings *and* this type of instance spawner // can provide radius data. If not, the "MeshRadius" setting is meaningless, so don't allow it // to be set. return (m_advanced && m_instanceSpawner && m_instanceSpawner->HasRadiusData()) ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide; } void Descriptor::RefreshSpawnerTypeList() const { m_spawnerTypes.clear(); // Find all registered types that are derived from InstanceSpawner, and get their display names. // (To change the display name for a class, go to its EditContext and change the name passed in // to the EditContext Class constructor) AZ::SerializeContext* serializeContext{}; AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext); AZ_Assert(serializeContext, "No SerializeContext found."); if (serializeContext) { serializeContext->EnumerateDerived( [&](const AZ::SerializeContext::ClassData* classData, const AZ::Uuid& classUuid) -> bool { auto spawnerDisplayName = classData->m_editData ? classData->m_editData->m_name : classData->m_name; m_spawnerTypes.push_back(AZStd::make_pair(classData->m_typeId, spawnerDisplayName)); return true; }); } // Alphabetically sort the list so that it has a well-defined order, regardless of what order we find the entries. AZStd::sort(m_spawnerTypes.begin(), m_spawnerTypes.end(), [](const auto& lhs, const auto& rhs) {return lhs.second < rhs.second; }); AZ_Assert(!m_spawnerTypes.empty(), "No serialized InstanceSpawner types were found."); } AZStd::vector> Descriptor::GetSpawnerTypeList() const { if (m_spawnerTypes.empty()) { RefreshSpawnerTypeList(); } AZ_Assert(!m_spawnerTypes.empty(), "No serialized InstanceSpawner types were found."); // Copy our static list into a new list with the proper types. // This is necessary because the PropertyEditor doesn't always recognize alternate forms of string types, // such as string_view or const char*. AZStd::vector> returnList; returnList.reserve(m_spawnerTypes.size()); returnList.assign(m_spawnerTypes.begin(), m_spawnerTypes.end()); return returnList; } bool Descriptor::CreateInstanceSpawner(AZ::TypeId spawnerType, InstanceSpawner* spawnerToClone) { // Locate the registered Behavior class for the requested type. const AZ::BehaviorClass* sourceClass = AZ::BehaviorContextHelper::GetClass(spawnerType); if (!sourceClass) { // Can't find the new spawner type, so set back to the previous one. AZ_Error("Vegetation", false, "Unrecognized spawner type: %s", spawnerType.ToString().c_str()); return false; } // Create (or clone) a new instance of the type, and verify that it's the type we expected. AZ::BehaviorObject newInstance; if (spawnerToClone) { AZ_Assert(spawnerType == azrtti_typeid(spawnerToClone), "Mismatched InstanceSpawner types"); AZ::BehaviorObject source(spawnerToClone, spawnerType); newInstance = sourceClass->Clone(source); } else { newInstance = sourceClass->Create(); } AZ_Assert(newInstance.m_address, "Failed to create requested spawner type: %s", spawnerType.ToString().c_str()); AZ_Assert(newInstance.m_typeId == spawnerType, "Unrecognized spawner type: %s", newInstance.m_typeId.ToString().c_str()); m_instanceSpawner = AZStd::shared_ptr(reinterpret_cast(newInstance.m_address)); AZ_Assert(spawnerType == azrtti_typeid(*m_instanceSpawner), "Unrecognized spawner type: %s", m_instanceSpawner->RTTI_GetTypeName()); // Force the bound mode to use Radius if this type of spawner can't provide MeshRadius information. if (!m_instanceSpawner->HasRadiusData()) { m_boundMode = BoundMode::Radius; } // Make sure the spawner type stays in sync with the actual spawner type m_spawnerType = spawnerType; return true; } AZ::TypeId Descriptor::GetSpawnerType() const { return m_spawnerType; } void Descriptor::SetSpawnerType(const AZ::TypeId& spawnerType) { m_spawnerType = spawnerType; SpawnerTypeChanged(); } AZStd::any Descriptor::GetSpawner() const { // Note that this is bypassing our shared pointer, which has the potential to cause pointer lifetime // issues, since scripts won't affect the shared pointer lifetime. AZStd::any::type_info valueInfo; valueInfo.m_id = azrtti_typeid(*m_instanceSpawner); valueInfo.m_isPointer = false; valueInfo.m_useHeap = true; valueInfo.m_handler = [](AZStd::any::Action action, AZStd::any* dest, const AZStd::any* source) { switch (action) { case AZStd::any::Action::Reserve: { // No-op break; } case AZStd::any::Action::Copy: case AZStd::any::Action::Move: { *reinterpret_cast(dest) = AZStd::any_cast(const_cast(source)); break; } case AZStd::any::Action::Destroy: { *reinterpret_cast(dest) = nullptr; break; } } }; return AZStd::any(&(*m_instanceSpawner), valueInfo); } void Descriptor::SetSpawner(const AZStd::any& spawnerContainer) { bool success = false; // Convert our AZStd::any container back to an InstanceSpawner pointer. void* anyToVoidPtr = AZStd::any_cast(&const_cast(spawnerContainer)); InstanceSpawner* spawner = reinterpret_cast(anyToVoidPtr); if (spawner) { success = CreateInstanceSpawner(spawnerContainer.type(), spawner); } if (!success) { AZ_Error("Vegetation", false, "Error setting spawner to type: %s", spawnerContainer.type().ToString().c_str()); } } AZ::u32 Descriptor::SpawnerTypeChanged() { // Create a new InstanceSpawner if we changed the spawner type. if (m_spawnerType != azrtti_typeid(*m_instanceSpawner)) { bool success = CreateInstanceSpawner(m_spawnerType); // If something went wrong creating the new one, still make sure our spawner type // stays in sync with whatever existing spawner type we have. if (!success) { m_spawnerType = azrtti_typeid(*m_instanceSpawner); } // If we change our instance spawner, refresh the entire tree. The set of editable properties // will change based on the new spawner type. return AZ::Edit::PropertyRefreshLevels::EntireTree; } // Nothing changed, so nothing to refresh. return AZ::Edit::PropertyRefreshLevels::None; } }