Merge branch 'development' into cmake/linux_fix_warn_unused
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>monroegm-disable-blank-issue-2
commit
d91dbe3d92
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Memory/Memory.h>
|
||||||
|
#include <AzCore/Serialization/AZStdAnyDataContainer.inl>
|
||||||
|
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||||
|
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
#include <ExpressionEvaluation/ExpressionEngine/ExpressionTypes.h>
|
||||||
|
|
||||||
|
namespace AZ
|
||||||
|
{
|
||||||
|
class ElementInformationSerializer
|
||||||
|
: public BaseJsonSerializer
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
AZ_RTTI(ElementInformationSerializer, "{B33E6AA9-C700-4E3D-857C-55F362AFE57A}", BaseJsonSerializer);
|
||||||
|
AZ_CLASS_ALLOCATOR_DECL;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ElementInformation = ExpressionEvaluation::ElementInformation;
|
||||||
|
|
||||||
|
static const char* EmptyAnyIdentifier;
|
||||||
|
|
||||||
|
static bool IsEmptyAny(const rapidjson::Value& typeId)
|
||||||
|
{
|
||||||
|
if (typeId.IsString())
|
||||||
|
{
|
||||||
|
AZStd::string_view typeName(typeId.GetString(), typeId.GetStringLength());
|
||||||
|
return typeName == EmptyAnyIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonSerializationResult::Result Load
|
||||||
|
( void* outputValue
|
||||||
|
, const Uuid& outputValueTypeId
|
||||||
|
, const rapidjson::Value& inputValue
|
||||||
|
, JsonDeserializerContext& context) override
|
||||||
|
{
|
||||||
|
namespace JSR = JsonSerializationResult;
|
||||||
|
|
||||||
|
AZ_Assert(outputValueTypeId == azrtti_typeid<ElementInformation>(), "ElementInformationSerializer Load against "
|
||||||
|
"output typeID that was not ElementInformation");
|
||||||
|
AZ_Assert(outputValue, "ElementInformationSerializer Load against null output");
|
||||||
|
|
||||||
|
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
|
||||||
|
auto outputDatum = reinterpret_cast<ElementInformation*>(outputValue);
|
||||||
|
result.Combine(ContinueLoadingFromJsonObjectField
|
||||||
|
( &outputDatum->m_id
|
||||||
|
, azrtti_typeid<decltype(outputDatum->m_id)>()
|
||||||
|
, inputValue
|
||||||
|
, "Id"
|
||||||
|
, context));
|
||||||
|
|
||||||
|
// any storage begin
|
||||||
|
{
|
||||||
|
AZ::Uuid typeId = AZ::Uuid::CreateNull();
|
||||||
|
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
|
||||||
|
if (typeIdMember == inputValue.MemberEnd())
|
||||||
|
{
|
||||||
|
return context.Report
|
||||||
|
( JSR::Tasks::ReadField
|
||||||
|
, JSR::Outcomes::Missing
|
||||||
|
, AZStd::string::format("ElementInformationSerializer::Load failed to load the %s member"
|
||||||
|
, JsonSerialization::TypeIdFieldIdentifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsEmptyAny(typeIdMember->value))
|
||||||
|
{
|
||||||
|
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
|
||||||
|
if (typeId.IsNull())
|
||||||
|
{
|
||||||
|
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
|
||||||
|
, "ElementInformationSerializer::Load failed to load the AZ TypeId of the value");
|
||||||
|
}
|
||||||
|
|
||||||
|
AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId);
|
||||||
|
if (storage.empty() || storage.type() != typeId)
|
||||||
|
{
|
||||||
|
return context.Report(result, "ElementInformationSerializer::Load failed to load a value matched the "
|
||||||
|
"reported AZ TypeId. The C++ declaration may have been deleted or changed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Combine
|
||||||
|
( ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "Value", context));
|
||||||
|
outputDatum->m_extraStore = storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// any storage end
|
||||||
|
|
||||||
|
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
|
||||||
|
? "ElementInformationSerializer Load finished loading ElementInformation"
|
||||||
|
: "ElementInformationSerializer Load failed to load ElementInformation");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonSerializationResult::Result Store
|
||||||
|
( rapidjson::Value& outputValue
|
||||||
|
, const void* inputValue
|
||||||
|
, const void* defaultValue
|
||||||
|
, const Uuid& valueTypeId, JsonSerializerContext& context) override
|
||||||
|
{
|
||||||
|
namespace JSR = JsonSerializationResult;
|
||||||
|
|
||||||
|
AZ_Assert(valueTypeId == azrtti_typeid<ElementInformation>(), "ElementInformation Store against value typeID that "
|
||||||
|
"was not ElementInformation");
|
||||||
|
AZ_Assert(inputValue, "ElementInformation Store against null inputValue pointer ");
|
||||||
|
|
||||||
|
auto inputScriptDataPtr = reinterpret_cast<const ElementInformation*>(inputValue);
|
||||||
|
auto defaultScriptDataPtr = reinterpret_cast<const ElementInformation*>(defaultValue);
|
||||||
|
|
||||||
|
if (defaultScriptDataPtr)
|
||||||
|
{
|
||||||
|
if (inputScriptDataPtr->m_id == defaultScriptDataPtr->m_id
|
||||||
|
&& AZ::Helpers::CompareAnyValue(inputScriptDataPtr->m_extraStore, defaultScriptDataPtr->m_extraStore))
|
||||||
|
{
|
||||||
|
return context.Report
|
||||||
|
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "ElementInformation Store used defaults for "
|
||||||
|
"ElementInformation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSR::ResultCode result(JSR::Tasks::WriteValue);
|
||||||
|
outputValue.SetObject();
|
||||||
|
|
||||||
|
result.Combine(ContinueStoringToJsonObjectField
|
||||||
|
( outputValue
|
||||||
|
, "Id"
|
||||||
|
, &inputScriptDataPtr->m_id
|
||||||
|
, defaultScriptDataPtr ? &defaultScriptDataPtr->m_id : nullptr
|
||||||
|
, azrtti_typeid<decltype(inputScriptDataPtr->m_id)>()
|
||||||
|
, context));
|
||||||
|
|
||||||
|
if (!inputScriptDataPtr->m_extraStore.empty())
|
||||||
|
{
|
||||||
|
rapidjson::Value typeValue;
|
||||||
|
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_extraStore.type(), context));
|
||||||
|
outputValue.AddMember
|
||||||
|
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
|
||||||
|
, AZStd::move(typeValue)
|
||||||
|
, context.GetJsonAllocator());
|
||||||
|
|
||||||
|
result.Combine(ContinueStoringToJsonObjectField
|
||||||
|
( outputValue
|
||||||
|
, "Value"
|
||||||
|
, AZStd::any_cast<void>(const_cast<AZStd::any*>(&inputScriptDataPtr->m_extraStore))
|
||||||
|
, defaultScriptDataPtr ? AZStd::any_cast<void>(const_cast<AZStd::any*>(&defaultScriptDataPtr->m_extraStore)) : nullptr
|
||||||
|
, inputScriptDataPtr->m_extraStore.type()
|
||||||
|
, context));
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rapidjson::Value emptyAny;
|
||||||
|
AZStd::string emptyAnyName(EmptyAnyIdentifier);
|
||||||
|
emptyAny.SetString(emptyAnyName.c_str(), aznumeric_caster(emptyAnyName.size()), context.GetJsonAllocator());
|
||||||
|
outputValue.AddMember
|
||||||
|
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
|
||||||
|
, AZStd::move(emptyAny)
|
||||||
|
, context.GetJsonAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
|
||||||
|
? "ElementInformation Store finished saving ElementInformation"
|
||||||
|
: "ElementInformation Store failed to save ElementInformation");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AZ_CLASS_ALLOCATOR_IMPL(ElementInformationSerializer, SystemAllocator, 0);
|
||||||
|
|
||||||
|
const char* ElementInformationSerializer::EmptyAnyIdentifier = "Empty AZStd::any";
|
||||||
|
}
|
||||||
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Memory/Memory.h>
|
||||||
|
#include <AzCore/Serialization/AZStdAnyDataContainer.inl>
|
||||||
|
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||||
|
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
#include <ExpressionEvaluation/ExpressionEngine/ExpressionTree.h>
|
||||||
|
|
||||||
|
namespace AZ
|
||||||
|
{
|
||||||
|
class ExpressionTreeVariableDescriptorSerializer
|
||||||
|
: public BaseJsonSerializer
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
AZ_RTTI(ExpressionTreeVariableDescriptorSerializer, "{5EFF37D6-BD54-45C6-9FC6-B1E0D3A8204C}", BaseJsonSerializer);
|
||||||
|
AZ_CLASS_ALLOCATOR_DECL;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using VariableDescriptor = ExpressionEvaluation::ExpressionTree::VariableDescriptor;
|
||||||
|
|
||||||
|
JsonSerializationResult::Result Load
|
||||||
|
( void* outputValue
|
||||||
|
, const Uuid& outputValueTypeId
|
||||||
|
, const rapidjson::Value& inputValue
|
||||||
|
, JsonDeserializerContext& context) override
|
||||||
|
{
|
||||||
|
namespace JSR = JsonSerializationResult;
|
||||||
|
|
||||||
|
AZ_Assert(outputValueTypeId == azrtti_typeid<VariableDescriptor>(), "ExpressionTreeVariableDescriptorSerializer Load against "
|
||||||
|
"output typeID that was not VariableDescriptor");
|
||||||
|
AZ_Assert(outputValue, "ExpressionTreeVariableDescriptorSerializer Load against null output");
|
||||||
|
|
||||||
|
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
|
||||||
|
auto outputDatum = reinterpret_cast<VariableDescriptor*>(outputValue);
|
||||||
|
|
||||||
|
result.Combine(ContinueLoadingFromJsonObjectField
|
||||||
|
( &outputDatum->m_supportedTypes
|
||||||
|
, azrtti_typeid<decltype(outputDatum->m_supportedTypes)>()
|
||||||
|
, inputValue
|
||||||
|
, "SupportedTypes"
|
||||||
|
, context));
|
||||||
|
|
||||||
|
// any storage begin
|
||||||
|
AZ::Uuid typeId = AZ::Uuid::CreateNull();
|
||||||
|
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
|
||||||
|
if (typeIdMember == inputValue.MemberEnd())
|
||||||
|
{
|
||||||
|
return context.Report
|
||||||
|
( JSR::Tasks::ReadField
|
||||||
|
, JSR::Outcomes::Missing
|
||||||
|
, AZStd::string::format("ExpressionTreeVariableDescriptorSerializer::Load failed to load the %s member"
|
||||||
|
, JsonSerialization::TypeIdFieldIdentifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
|
||||||
|
if (typeId.IsNull())
|
||||||
|
{
|
||||||
|
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
|
||||||
|
, "ExpressionTreeVariableDescriptorSerializer::Load failed to load the AZ TypeId of the value");
|
||||||
|
}
|
||||||
|
|
||||||
|
AZStd::any storage = context.GetSerializeContext()->CreateAny(typeId);
|
||||||
|
if (storage.empty() || storage.type() != typeId)
|
||||||
|
{
|
||||||
|
return context.Report(result, "ExpressionTreeVariableDescriptorSerializer::Load failed to load a value matched the "
|
||||||
|
"reported AZ TypeId. The C++ declaration may have been deleted or changed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "Value", context));
|
||||||
|
outputDatum->m_value = storage;
|
||||||
|
// any storage end
|
||||||
|
|
||||||
|
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
|
||||||
|
? "ExpressionTreeVariableDescriptorSerializer Load finished loading VariableDescriptor"
|
||||||
|
: "ExpressionTreeVariableDescriptorSerializer Load failed to load VariableDescriptor");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonSerializationResult::Result Store
|
||||||
|
( rapidjson::Value& outputValue
|
||||||
|
, const void* inputValue
|
||||||
|
, const void* defaultValue
|
||||||
|
, const Uuid& valueTypeId, JsonSerializerContext& context) override
|
||||||
|
{
|
||||||
|
namespace JSR = JsonSerializationResult;
|
||||||
|
|
||||||
|
AZ_Assert(valueTypeId == azrtti_typeid<VariableDescriptor>(), "VariableDescriptor Store against value typeID that "
|
||||||
|
"was not VariableDescriptor");
|
||||||
|
AZ_Assert(inputValue, "VariableDescriptor Store against null inputValue pointer ");
|
||||||
|
|
||||||
|
auto inputScriptDataPtr = reinterpret_cast<const VariableDescriptor*>(inputValue);
|
||||||
|
auto defaultScriptDataPtr = reinterpret_cast<const VariableDescriptor*>(defaultValue);
|
||||||
|
|
||||||
|
if (defaultScriptDataPtr)
|
||||||
|
{
|
||||||
|
if (inputScriptDataPtr->m_supportedTypes == defaultScriptDataPtr->m_supportedTypes
|
||||||
|
&& AZ::Helpers::CompareAnyValue(inputScriptDataPtr->m_value, defaultScriptDataPtr->m_value))
|
||||||
|
{
|
||||||
|
return context.Report
|
||||||
|
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "VariableDescriptor Store used defaults for "
|
||||||
|
"VariableDescriptor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JSR::ResultCode result(JSR::Tasks::WriteValue);
|
||||||
|
outputValue.SetObject();
|
||||||
|
|
||||||
|
result.Combine(ContinueStoringToJsonObjectField
|
||||||
|
( outputValue
|
||||||
|
, "SupportedTypes"
|
||||||
|
, &inputScriptDataPtr->m_supportedTypes
|
||||||
|
, defaultScriptDataPtr ? &defaultScriptDataPtr->m_supportedTypes : nullptr
|
||||||
|
, azrtti_typeid<decltype(inputScriptDataPtr->m_supportedTypes)>()
|
||||||
|
, context));
|
||||||
|
|
||||||
|
rapidjson::Value typeValue;
|
||||||
|
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->m_value.type(), context));
|
||||||
|
outputValue.AddMember
|
||||||
|
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
|
||||||
|
, AZStd::move(typeValue)
|
||||||
|
, context.GetJsonAllocator());
|
||||||
|
|
||||||
|
result.Combine(ContinueStoringToJsonObjectField
|
||||||
|
( outputValue
|
||||||
|
, "Value"
|
||||||
|
, AZStd::any_cast<void>(const_cast<AZStd::any*>(&inputScriptDataPtr->m_value))
|
||||||
|
, defaultScriptDataPtr ? AZStd::any_cast<void>(const_cast<AZStd::any*>(&defaultScriptDataPtr->m_value)) : nullptr
|
||||||
|
, inputScriptDataPtr->m_value.type()
|
||||||
|
, context));
|
||||||
|
|
||||||
|
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
|
||||||
|
? "VariableDescriptor Store finished saving VariableDescriptor"
|
||||||
|
: "VariableDescriptor Store failed to save VariableDescriptor");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AZ_CLASS_ALLOCATOR_IMPL(ExpressionTreeVariableDescriptorSerializer, SystemAllocator, 0);
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace ScriptCanvas
|
||||||
|
{
|
||||||
|
class SerializationListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_RTTI(SerializationListener, "{CA4EE281-30B3-4928-BCD8-9305CE75E463}");
|
||||||
|
virtual ~SerializationListener() {}
|
||||||
|
|
||||||
|
virtual void OnSerialize() {}
|
||||||
|
|
||||||
|
virtual void OnDeserialize() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
using SerializationListeners = AZStd::vector<SerializationListener*>;
|
||||||
|
}
|
||||||
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AzCore/Serialization/AZStdAnyDataContainer.inl>
|
||||||
|
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||||
|
#include <ScriptCanvas/Asset/RuntimeAsset.h>
|
||||||
|
#include <ScriptCanvas/Serialization/BehaviorContextObjectSerializer.h>
|
||||||
|
|
||||||
|
using namespace ScriptCanvas;
|
||||||
|
|
||||||
|
namespace AZ
|
||||||
|
{
|
||||||
|
AZ_CLASS_ALLOCATOR_IMPL(BehaviorContextObjectSerializer, SystemAllocator, 0);
|
||||||
|
|
||||||
|
JsonSerializationResult::Result BehaviorContextObjectSerializer::Load
|
||||||
|
( void* outputValue
|
||||||
|
, [[maybe_unused]] const Uuid& outputValueTypeId
|
||||||
|
, const rapidjson::Value& inputValue
|
||||||
|
, JsonDeserializerContext& context)
|
||||||
|
{
|
||||||
|
namespace JSR = JsonSerializationResult;
|
||||||
|
|
||||||
|
AZ_Assert(outputValueTypeId == azrtti_typeid<BehaviorContextObject>(), "BehaviorContextObjectSerializer Load against output typeID"
|
||||||
|
"that was not BehaviorContextObject");
|
||||||
|
AZ_Assert(outputValue, "BehaviorContextObjectSerializer Load against null output");
|
||||||
|
|
||||||
|
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
|
||||||
|
auto outputBehaviorContextObject = reinterpret_cast<BehaviorContextObject*>(outputValue);
|
||||||
|
|
||||||
|
bool isOwned = false;
|
||||||
|
result.Combine(ContinueLoadingFromJsonObjectField
|
||||||
|
( &isOwned
|
||||||
|
, azrtti_typeid<bool>()
|
||||||
|
, inputValue
|
||||||
|
, "isOwned"
|
||||||
|
, context));
|
||||||
|
|
||||||
|
if (isOwned)
|
||||||
|
{
|
||||||
|
AZStd::any storage;
|
||||||
|
{ // any storage begin
|
||||||
|
|
||||||
|
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
|
||||||
|
if (typeIdMember == inputValue.MemberEnd())
|
||||||
|
{
|
||||||
|
return context.Report
|
||||||
|
(JSR::Tasks::ReadField
|
||||||
|
, JSR::Outcomes::Missing
|
||||||
|
, AZStd::string::format("BehaviorContextObjectSerializer::Load failed to load the %s member"
|
||||||
|
, JsonSerialization::TypeIdFieldIdentifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Uuid typeId;
|
||||||
|
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
|
||||||
|
if (typeId.IsNull())
|
||||||
|
{
|
||||||
|
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
|
||||||
|
, "BehaviorContextObjectSerializer::Load failed to load the AZ TypeId of the value");
|
||||||
|
}
|
||||||
|
|
||||||
|
storage = context.GetSerializeContext()->CreateAny(typeId);
|
||||||
|
if (storage.empty() || storage.type() != typeId)
|
||||||
|
{
|
||||||
|
return context.Report(result, "BehaviorContextObjectSerializer::Load failed to load a value matched the reported AZ "
|
||||||
|
"TypeId. The C++ declaration may have been deleted or changed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "value", context));
|
||||||
|
} // any storage end
|
||||||
|
|
||||||
|
auto bcClass = AZ::BehaviorContextHelper::GetClass(storage.type());
|
||||||
|
BehaviorContextObject::Deserialize(*outputBehaviorContextObject, *bcClass, storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
|
||||||
|
? "BehaviorContextObjectSerializer Load finished loading BehaviorContextObject"
|
||||||
|
: "BehaviorContextObjectSerializer Load failed to load BehaviorContextObject");
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonSerializationResult::Result BehaviorContextObjectSerializer::Store
|
||||||
|
( rapidjson::Value& outputValue
|
||||||
|
, const void* inputValue
|
||||||
|
, const void* defaultValue
|
||||||
|
, [[maybe_unused]] const Uuid& valueTypeId
|
||||||
|
, JsonSerializerContext& context)
|
||||||
|
{
|
||||||
|
namespace JSR = JsonSerializationResult;
|
||||||
|
|
||||||
|
AZ_Assert(valueTypeId == azrtti_typeid<BehaviorContextObject>(), "BehaviorContextObjectSerializer Store against value typeID that "
|
||||||
|
"was not BehaviorContextObject");
|
||||||
|
AZ_Assert(inputValue, "BehaviorContextObjectSerializer Store against null inputValue pointer ");
|
||||||
|
|
||||||
|
auto defaultScriptDataPtr = reinterpret_cast<const BehaviorContextObject*>(defaultValue);
|
||||||
|
auto inputScriptDataPtr = reinterpret_cast<const BehaviorContextObject*>(inputValue);
|
||||||
|
|
||||||
|
if (defaultScriptDataPtr)
|
||||||
|
{
|
||||||
|
if (AZ::Helpers::CompareAnyValue(inputScriptDataPtr->ToAny(), defaultScriptDataPtr->ToAny()))
|
||||||
|
{
|
||||||
|
return context.Report
|
||||||
|
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "BehaviorContextObjectSerializer Store used defaults "
|
||||||
|
"for BehaviorContextObject");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputValue.SetObject();
|
||||||
|
JSR::ResultCode result(JSR::Tasks::WriteValue);
|
||||||
|
const bool isInputOwned = inputScriptDataPtr->IsOwned();
|
||||||
|
const bool isDefaultOwned = defaultScriptDataPtr ? defaultScriptDataPtr->IsOwned() : false;
|
||||||
|
result.Combine(ContinueStoringToJsonObjectField
|
||||||
|
( outputValue
|
||||||
|
, "isOwned"
|
||||||
|
, &isInputOwned
|
||||||
|
, &isDefaultOwned
|
||||||
|
, azrtti_typeid<bool>()
|
||||||
|
, context));
|
||||||
|
|
||||||
|
if (isInputOwned)
|
||||||
|
{
|
||||||
|
// any storage begin
|
||||||
|
{
|
||||||
|
rapidjson::Value typeValue;
|
||||||
|
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->ToAny().type(), context));
|
||||||
|
outputValue.AddMember
|
||||||
|
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
|
||||||
|
, AZStd::move(typeValue)
|
||||||
|
, context.GetJsonAllocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Combine(ContinueStoringToJsonObjectField
|
||||||
|
( outputValue
|
||||||
|
, "value"
|
||||||
|
, inputScriptDataPtr->Get()
|
||||||
|
, defaultScriptDataPtr ? defaultScriptDataPtr->Get() : nullptr
|
||||||
|
, inputScriptDataPtr->ToAny().type()
|
||||||
|
, context));
|
||||||
|
// datum storage end
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
|
||||||
|
? "BehaviorContextObjectSerializer Store finished saving BehaviorContextObject"
|
||||||
|
: "BehaviorContextObjectSerializer Store failed to save BehaviorContextObject");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Memory/Memory.h>
|
||||||
|
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
|
||||||
|
namespace AZ
|
||||||
|
{
|
||||||
|
class BehaviorContextObjectSerializer
|
||||||
|
: public BaseJsonSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_RTTI(BehaviorContextObjectSerializer, "{88469C4C-923F-4508-A45C-33DDBB91074E}", BaseJsonSerializer);
|
||||||
|
AZ_CLASS_ALLOCATOR_DECL;
|
||||||
|
|
||||||
|
private:
|
||||||
|
JsonSerializationResult::Result Load
|
||||||
|
( void* outputValue
|
||||||
|
, const Uuid& outputValueTypeId
|
||||||
|
, const rapidjson::Value& inputValue
|
||||||
|
, JsonDeserializerContext& context) override;
|
||||||
|
|
||||||
|
JsonSerializationResult::Result Store
|
||||||
|
( rapidjson::Value& outputValue
|
||||||
|
, const void* inputValue
|
||||||
|
, const void* defaultValue
|
||||||
|
, const Uuid& valueTypeId, JsonSerializerContext& context) override;
|
||||||
|
};
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Atom/Features/SrgSemantics.azsli>
|
||||||
|
#include <viewsrg.srgi>
|
||||||
|
|
||||||
|
|
||||||
|
struct VertexInput
|
||||||
|
{
|
||||||
|
float2 Position : POSITION;
|
||||||
|
float2 UV : UV;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexOutput
|
||||||
|
{
|
||||||
|
float4 Position : SV_Position;
|
||||||
|
float3 Normal : NORMAL;
|
||||||
|
float2 UV : UV;
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderResourceGroup ObjectSrg : SRG_PerObject
|
||||||
|
{
|
||||||
|
Texture2D<float4> HeightmapImage;
|
||||||
|
|
||||||
|
Sampler LinearSampler
|
||||||
|
{
|
||||||
|
MinFilter = Linear;
|
||||||
|
MagFilter = Linear;
|
||||||
|
MipFilter = Linear;
|
||||||
|
AddressU = Clamp;
|
||||||
|
AddressV = Clamp;
|
||||||
|
AddressW = Clamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
row_major float3x4 m_modelToWorld;
|
||||||
|
float m_heightScale;
|
||||||
|
float2 m_uvMin;
|
||||||
|
float2 m_uvMax;
|
||||||
|
float2 m_uvStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
float4x4 GetObject_WorldMatrix()
|
||||||
|
{
|
||||||
|
float4x4 modelToWorld = float4x4(
|
||||||
|
float4(1, 0, 0, 0),
|
||||||
|
float4(0, 1, 0, 0),
|
||||||
|
float4(0, 0, 1, 0),
|
||||||
|
float4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
modelToWorld[0] = ObjectSrg::m_modelToWorld[0];
|
||||||
|
modelToWorld[1] = ObjectSrg::m_modelToWorld[1];
|
||||||
|
modelToWorld[2] = ObjectSrg::m_modelToWorld[2];
|
||||||
|
return modelToWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetHeight(float2 origUv)
|
||||||
|
{
|
||||||
|
float2 uv = clamp(origUv, 0.0f, 1.0f);
|
||||||
|
return ObjectSrg::m_heightScale * (ObjectSrg::HeightmapImage.SampleLevel(ObjectSrg::LinearSampler, uv, 0).r - 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexOutput MainVS(in VertexInput input)
|
||||||
|
{
|
||||||
|
VertexOutput output;
|
||||||
|
|
||||||
|
// Clamp the UVs *after* lerping to ensure that everything aligns properly right to the edge.
|
||||||
|
// We use out-of-bounds UV values to denote vertices that need to be removed.
|
||||||
|
float2 origUv = lerp(ObjectSrg::m_uvMin, ObjectSrg::m_uvMax, input.UV);
|
||||||
|
float2 uv = clamp(origUv, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
// Loop up the height and calculate our final position.
|
||||||
|
float height = GetHeight(uv);
|
||||||
|
float3 worldPosition = mul(GetObject_WorldMatrix(), float4(input.Position, height, 1.0f)).xyz;
|
||||||
|
output.Position = mul(ViewSrg::m_viewProjectionMatrix, float4(worldPosition, 1.0f));
|
||||||
|
|
||||||
|
// Remove all vertices outside our bounds by turning them into NaN positions.
|
||||||
|
output.Position = output.Position / ((origUv.x >= 0.0f && origUv.x < 1.0f && origUv.y >= 0.0f && origUv.y < 1.0f) ? 1.0f : 0.0f);
|
||||||
|
|
||||||
|
// Calculate normal
|
||||||
|
float2 gridSize = {1.0f, 1.0f};
|
||||||
|
float up = GetHeight(uv + ObjectSrg::m_uvStep * float2(-1.0f, 0.0f));
|
||||||
|
float right = GetHeight(uv + ObjectSrg::m_uvStep * float2( 0.0f, 1.0f));
|
||||||
|
float down = GetHeight(uv + ObjectSrg::m_uvStep * float2( 1.0f, 0.0f));
|
||||||
|
float left = GetHeight(uv + ObjectSrg::m_uvStep * float2( 0.0f, -1.0f));
|
||||||
|
|
||||||
|
float dydx = (right - left) * gridSize[0];
|
||||||
|
float dydz = (down - up) * gridSize[1];
|
||||||
|
|
||||||
|
output.Normal = normalize(float3(dydx, 2.0f, dydz));
|
||||||
|
|
||||||
|
output.UV = uv;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PixelOutput
|
||||||
|
{
|
||||||
|
float4 m_color : SV_Target0;
|
||||||
|
};
|
||||||
|
|
||||||
|
PixelOutput MainPS(in VertexOutput input)
|
||||||
|
{
|
||||||
|
PixelOutput output;
|
||||||
|
|
||||||
|
// Hard-coded fake light direction
|
||||||
|
float3 lightDirection = normalize(float3(1.0, -1.0, 1.0));
|
||||||
|
|
||||||
|
// Fake light intensity ranges from 1.0 for normals directly facing the light to zero for those
|
||||||
|
// directly facing away.
|
||||||
|
float lightDot = dot(normalize(input.Normal), lightDirection);
|
||||||
|
float lightIntensity = lightDot * 0.5 + 0.5;
|
||||||
|
|
||||||
|
// add a small amount of ambient and reduce direct light to keep in 0-1 range
|
||||||
|
lightIntensity = saturate(0.1 + lightIntensity * 0.9);
|
||||||
|
|
||||||
|
// The lightIntensity should not affect alpha so only apply it to rgb.
|
||||||
|
//output.m_color.rgb = ((input.Normal + float3(1.0, 1.0, 1.0)) / 2.0);
|
||||||
|
output.m_color.rgb = float3(1.0, 1.0, 1.0) * lightIntensity;
|
||||||
|
output.m_color.a = 1.0f;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
"Source" : "Terrain",
|
||||||
|
|
||||||
|
|
||||||
|
"RasterState" : { "CullMode" : "None" },
|
||||||
|
|
||||||
|
"DepthStencilState" : {
|
||||||
|
"Depth" : { "Enable" : true, "CompareFunc" : "GreaterEqual" }
|
||||||
|
},
|
||||||
|
|
||||||
|
"BlendState" : {
|
||||||
|
"Enable" : true,
|
||||||
|
"BlendSource" : "One",
|
||||||
|
"BlendAlphaSource" : "One",
|
||||||
|
"BlendDest" : "AlphaSourceInverse",
|
||||||
|
"BlendAlphaDest" : "AlphaSourceInverse",
|
||||||
|
"BlendAlphaOp" : "Add"
|
||||||
|
},
|
||||||
|
|
||||||
|
"DrawList" : "forward",
|
||||||
|
|
||||||
|
"ProgramSettings":
|
||||||
|
{
|
||||||
|
"EntryPoints":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "MainVS",
|
||||||
|
"type": "Vertex"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "MainPS",
|
||||||
|
"type": "Fragment"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Components/TerrainHeightGradientListComponent.h>
|
||||||
|
|
||||||
|
#include <AzCore/Asset/AssetManagerBus.h>
|
||||||
|
#include <AzCore/Component/Entity.h>
|
||||||
|
#include <AzCore/Asset/AssetManager.h>
|
||||||
|
#include <AzCore/RTTI/BehaviorContext.h>
|
||||||
|
#include <AzCore/Serialization/EditContext.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
#include <AzCore/Math/Aabb.h>
|
||||||
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||||
|
|
||||||
|
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||||
|
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
void TerrainHeightGradientListConfig::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainHeightGradientListConfig, AZ::ComponentConfig>()
|
||||||
|
->Version(1)
|
||||||
|
->Field("GradientEntities", &TerrainHeightGradientListConfig::m_gradientEntities)
|
||||||
|
;
|
||||||
|
|
||||||
|
AZ::EditContext* edit = serialize->GetEditContext();
|
||||||
|
if (edit)
|
||||||
|
{
|
||||||
|
edit->Class<TerrainHeightGradientListConfig>(
|
||||||
|
"Terrain Height Gradient List Component", "Provide height data for a region of the world")
|
||||||
|
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||||
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||||
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||||
|
|
||||||
|
->DataElement(0, &TerrainHeightGradientListConfig::m_gradientEntities, "Gradient Entities", "Ordered list of gradients to use as height providers.")
|
||||||
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||||
|
->Attribute(AZ::Edit::Attributes::ContainerCanBeModified, true)
|
||||||
|
->Attribute(AZ::Edit::Attributes::RequiredService, AZ_CRC_CE("GradientService"))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainHeightProviderService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainHeightProviderService"));
|
||||||
|
services.push_back(AZ_CRC_CE("GradientService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainAreaService"));
|
||||||
|
services.push_back(AZ_CRC_CE("BoxShapeService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
TerrainHeightGradientListConfig::Reflect(context);
|
||||||
|
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainHeightGradientListComponent, AZ::Component>()
|
||||||
|
->Version(0)
|
||||||
|
->Field("Configuration", &TerrainHeightGradientListComponent::m_configuration)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TerrainHeightGradientListComponent::TerrainHeightGradientListComponent(const TerrainHeightGradientListConfig& configuration)
|
||||||
|
: m_configuration(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::Activate()
|
||||||
|
{
|
||||||
|
LmbrCentral::DependencyNotificationBus::Handler::BusConnect(GetEntityId());
|
||||||
|
Terrain::TerrainAreaHeightRequestBus::Handler::BusConnect(GetEntityId());
|
||||||
|
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
|
||||||
|
|
||||||
|
// Make sure we get update notifications whenever this entity or any dependent gradient entity changes in any way.
|
||||||
|
// We'll use that to notify the terrain system that the height information needs to be refreshed.
|
||||||
|
m_dependencyMonitor.Reset();
|
||||||
|
m_dependencyMonitor.ConnectOwner(GetEntityId());
|
||||||
|
m_dependencyMonitor.ConnectDependency(GetEntityId());
|
||||||
|
|
||||||
|
for (auto& entityId : m_configuration.m_gradientEntities)
|
||||||
|
{
|
||||||
|
if (entityId != GetEntityId())
|
||||||
|
{
|
||||||
|
m_dependencyMonitor.ConnectDependency(entityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache any height data needed and notify that the area has changed.
|
||||||
|
OnCompositionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::Deactivate()
|
||||||
|
{
|
||||||
|
m_dependencyMonitor.Reset();
|
||||||
|
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
|
||||||
|
Terrain::TerrainAreaHeightRequestBus::Handler::BusDisconnect();
|
||||||
|
LmbrCentral::DependencyNotificationBus::Handler::BusDisconnect();
|
||||||
|
|
||||||
|
// Since this height data will no longer exist, notify the terrain system to refresh the area.
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainHeightGradientListComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<const TerrainHeightGradientListConfig*>(baseConfig))
|
||||||
|
{
|
||||||
|
m_configuration = *config;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainHeightGradientListComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<TerrainHeightGradientListConfig*>(outBaseConfig))
|
||||||
|
{
|
||||||
|
*config = m_configuration;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float TerrainHeightGradientListComponent::GetHeight(float x, float y)
|
||||||
|
{
|
||||||
|
float maxSample = 0.0f;
|
||||||
|
|
||||||
|
GradientSignal::GradientSampleParams params(AZ::Vector3(x, y, 0.0f));
|
||||||
|
|
||||||
|
// Right now, when the list contains multiple entries, we will use the highest point from each gradient.
|
||||||
|
// This is needed in part because gradients don't really have world bounds, so they exist everywhere but generally have a value
|
||||||
|
// of 0 outside their data bounds if they're using bounded data. We should examine the possibility of extending the gradient API
|
||||||
|
// to provide actual bounds so that it's possible to detect if the gradient even 'exists' in an area, at which point we could just
|
||||||
|
// make this list a prioritized list from top to bottom for any points that overlap.
|
||||||
|
for (auto& gradientId : m_configuration.m_gradientEntities)
|
||||||
|
{
|
||||||
|
float sample = 0.0f;
|
||||||
|
GradientSignal::GradientRequestBus::EventResult(sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
|
||||||
|
maxSample = AZ::GetMax(maxSample, sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float height = AZ::Lerp(m_cachedShapeBounds.GetMin().GetZ(), m_cachedShapeBounds.GetMax().GetZ(), maxSample);
|
||||||
|
|
||||||
|
return AZ::GetClamp(height, m_cachedMinWorldHeight, m_cachedMaxWorldHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::GetHeight(
|
||||||
|
const AZ::Vector3& inPosition, AZ::Vector3& outPosition, [[maybe_unused]] Sampler sampleFilter = Sampler::DEFAULT)
|
||||||
|
{
|
||||||
|
const float height = GetHeight(inPosition.GetX(), inPosition.GetY());
|
||||||
|
outPosition.SetZ(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::GetNormal(
|
||||||
|
const AZ::Vector3& inPosition, AZ::Vector3& outNormal, [[maybe_unused]] Sampler sampleFilter = Sampler::DEFAULT)
|
||||||
|
{
|
||||||
|
const float x = inPosition.GetX();
|
||||||
|
const float y = inPosition.GetY();
|
||||||
|
|
||||||
|
if ((x >= m_cachedShapeBounds.GetMin().GetX()) && (x <= m_cachedShapeBounds.GetMax().GetX()) &&
|
||||||
|
(y >= m_cachedShapeBounds.GetMin().GetY()) && (y <= m_cachedShapeBounds.GetMax().GetY()))
|
||||||
|
{
|
||||||
|
AZ::Vector2 fRange = (m_cachedHeightQueryResolution / 2.0f) + AZ::Vector2(0.05f);
|
||||||
|
|
||||||
|
AZ::Vector3 v1(x - fRange.GetX(), y - fRange.GetY(), GetHeight(x - fRange.GetX(), y - fRange.GetY()));
|
||||||
|
AZ::Vector3 v2(x - fRange.GetX(), y + fRange.GetY(), GetHeight(x - fRange.GetX(), y + fRange.GetY()));
|
||||||
|
AZ::Vector3 v3(x + fRange.GetX(), y - fRange.GetY(), GetHeight(x + fRange.GetX(), y - fRange.GetY()));
|
||||||
|
AZ::Vector3 v4(x + fRange.GetX(), y + fRange.GetY(), GetHeight(x + fRange.GetX(), y + fRange.GetY()));
|
||||||
|
outNormal = (v3 - v2).Cross(v4 - v1).GetNormalized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::OnCompositionChanged()
|
||||||
|
{
|
||||||
|
RefreshMinMaxHeights();
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::RefreshMinMaxHeights()
|
||||||
|
{
|
||||||
|
// Get the height range of our height provider based on the shape component.
|
||||||
|
LmbrCentral::ShapeComponentRequestsBus::EventResult(m_cachedShapeBounds, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
|
||||||
|
|
||||||
|
// Get the height range of the entire world
|
||||||
|
m_cachedHeightQueryResolution = AZ::Vector2(1.0f);
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
m_cachedHeightQueryResolution, &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainGridResolution);
|
||||||
|
|
||||||
|
AZ::Aabb worldBounds = AZ::Aabb::CreateNull();
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
worldBounds, &AzFramework::Terrain::TerrainDataRequestBus::Events::GetTerrainAabb);
|
||||||
|
|
||||||
|
// Save off the min/max heights so that we don't have to re-query them on every single height query.
|
||||||
|
m_cachedMinWorldHeight = worldBounds.GetMin().GetZ();
|
||||||
|
m_cachedMaxWorldHeight = worldBounds.GetMax().GetZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainHeightGradientListComponent::OnTerrainDataChanged(
|
||||||
|
[[maybe_unused]] const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask)
|
||||||
|
{
|
||||||
|
if (dataChangedMask & TerrainDataChangedMask::Settings)
|
||||||
|
{
|
||||||
|
// If the terrain system settings changed, it's possible that the world bounds have changed, which can affect our height data.
|
||||||
|
// Refresh the min/max heights and notify that the height data for this area needs to be refreshed.
|
||||||
|
OnCompositionChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Asset/AssetCommon.h>
|
||||||
|
#include <AzCore/Component/Component.h>
|
||||||
|
#include <AzCore/Component/EntityBus.h>
|
||||||
|
#include <AzCore/Component/TransformBus.h>
|
||||||
|
#include <AzCore/Jobs/JobManagerBus.h>
|
||||||
|
#include <AzCore/Jobs/JobFunction.h>
|
||||||
|
#include <AzCore/Math/Vector3.h>
|
||||||
|
#include <AzCore/Math/Aabb.h>
|
||||||
|
|
||||||
|
#include <LmbrCentral/Dependency/DependencyMonitor.h>
|
||||||
|
#include <LmbrCentral/Dependency/DependencyNotificationBus.h>
|
||||||
|
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||||
|
|
||||||
|
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||||
|
#include <TerrainSystem/TerrainSystemBus.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace LmbrCentral
|
||||||
|
{
|
||||||
|
template<typename, typename>
|
||||||
|
class EditorWrappedComponentBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
class TerrainHeightGradientListConfig
|
||||||
|
: public AZ::ComponentConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_CLASS_ALLOCATOR(TerrainHeightGradientListConfig, AZ::SystemAllocator, 0);
|
||||||
|
AZ_RTTI(TerrainHeightGradientListConfig, "{C5FD71A9-0722-4D4C-B605-EBEBF90C628F}", AZ::ComponentConfig);
|
||||||
|
static void Reflect(AZ::ReflectContext* context);
|
||||||
|
|
||||||
|
AZStd::vector<AZ::EntityId> m_gradientEntities;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TerrainHeightGradientListComponent
|
||||||
|
: public AZ::Component
|
||||||
|
, private Terrain::TerrainAreaHeightRequestBus::Handler
|
||||||
|
, private LmbrCentral::DependencyNotificationBus::Handler
|
||||||
|
, private AzFramework::Terrain::TerrainDataNotificationBus::Handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename, typename>
|
||||||
|
friend class LmbrCentral::EditorWrappedComponentBase;
|
||||||
|
AZ_COMPONENT(TerrainHeightGradientListComponent, "{1BB3BA6C-6D4A-4636-B542-F23ECBA8F2AB}");
|
||||||
|
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void Reflect(AZ::ReflectContext* context);
|
||||||
|
|
||||||
|
TerrainHeightGradientListComponent(const TerrainHeightGradientListConfig& configuration);
|
||||||
|
TerrainHeightGradientListComponent() = default;
|
||||||
|
~TerrainHeightGradientListComponent() = default;
|
||||||
|
|
||||||
|
void GetHeight(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, Sampler sampleFilter) override;
|
||||||
|
void GetNormal(const AZ::Vector3& inPosition, AZ::Vector3& outNormal, Sampler sampleFilter) override;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// AZ::Component interface implementation
|
||||||
|
void Activate() override;
|
||||||
|
void Deactivate() override;
|
||||||
|
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||||
|
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// LmbrCentral::DependencyNotificationBus
|
||||||
|
void OnCompositionChanged() override;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// AzFramework::Terrain::TerrainDataNotificationBus
|
||||||
|
void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TerrainHeightGradientListConfig m_configuration;
|
||||||
|
|
||||||
|
///////////////////////////////////////////
|
||||||
|
void GetNormalSynchronous(float x, float y, AZ::Vector3& normal);
|
||||||
|
|
||||||
|
void RefreshMinMaxHeights();
|
||||||
|
float GetHeight(float x, float y);
|
||||||
|
|
||||||
|
float m_cachedMinWorldHeight{ 0.0f };
|
||||||
|
float m_cachedMaxWorldHeight{ 0.0f };
|
||||||
|
AZ::Vector2 m_cachedHeightQueryResolution{ 1.0f, 1.0f };
|
||||||
|
AZ::Aabb m_cachedShapeBounds;
|
||||||
|
|
||||||
|
LmbrCentral::DependencyMonitor m_dependencyMonitor;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Components/TerrainLayerSpawnerComponent.h>
|
||||||
|
|
||||||
|
#include <AzCore/Asset/AssetManagerBus.h>
|
||||||
|
#include <AzCore/Component/Entity.h>
|
||||||
|
#include <AzCore/Asset/AssetManager.h>
|
||||||
|
#include <AzCore/RTTI/BehaviorContext.h>
|
||||||
|
#include <AzCore/Serialization/EditContext.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
#include <AzCore/Math/Aabb.h>
|
||||||
|
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||||
|
|
||||||
|
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||||
|
#include <SurfaceData/SurfaceDataProviderRequestBus.h>
|
||||||
|
#include <TerrainSystem/TerrainSystemBus.h>
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
void TerrainLayerSpawnerConfig::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainLayerSpawnerConfig, AZ::ComponentConfig>()
|
||||||
|
->Version(1)
|
||||||
|
->Field("Layer", &TerrainLayerSpawnerConfig::m_layer)
|
||||||
|
->Field("Priority", &TerrainLayerSpawnerConfig::m_priority)
|
||||||
|
->Field("UseGroundPlane", &TerrainLayerSpawnerConfig::m_useGroundPlane)
|
||||||
|
;
|
||||||
|
|
||||||
|
AZ::EditContext* edit = serialize->GetEditContext();
|
||||||
|
if (edit)
|
||||||
|
{
|
||||||
|
edit->Class<TerrainLayerSpawnerConfig>(
|
||||||
|
"Terrain Layer Spawner Component", "Provide terrain data for a region of the world")
|
||||||
|
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||||
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||||
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||||
|
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::ComboBox, &TerrainLayerSpawnerConfig::m_layer, "Layer Priority", "Defines a high level order that terrain spawners are applied")
|
||||||
|
->Attribute(AZ::Edit::Attributes::EnumValues, &TerrainLayerSpawnerConfig::GetSelectableLayers)
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Slider, &TerrainLayerSpawnerConfig::m_priority, "Sub Priority", "Defines order terrain spawners are applied within a layer. Larger numbers = higher priority")
|
||||||
|
->Attribute(AZ::Edit::Attributes::Min, AreaConstants::s_priorityMin)
|
||||||
|
->Attribute(AZ::Edit::Attributes::Max, AreaConstants::s_priorityMax)
|
||||||
|
->Attribute(AZ::Edit::Attributes::SoftMin, AreaConstants::s_priorityMin)
|
||||||
|
->Attribute(AZ::Edit::Attributes::SoftMax, AreaConstants::s_prioritySoftMax)
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainLayerSpawnerConfig::m_useGroundPlane, "Use Ground Plane", "Determines whether or not to provide a default ground plane")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> TerrainLayerSpawnerConfig::GetSelectableLayers() const
|
||||||
|
{
|
||||||
|
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> selectableLayers;
|
||||||
|
selectableLayers.push_back({ AreaConstants::s_backgroundLayer, AZStd::string("Background") });
|
||||||
|
selectableLayers.push_back({ AreaConstants::s_foregroundLayer, AZStd::string("Foreground") });
|
||||||
|
return selectableLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC("TerrainAreaService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC("TerrainAreaService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC("BoxShapeService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
TerrainLayerSpawnerConfig::Reflect(context);
|
||||||
|
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainLayerSpawnerComponent, AZ::Component>()
|
||||||
|
->Version(0)
|
||||||
|
->Field("Configuration", &TerrainLayerSpawnerComponent::m_configuration)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TerrainLayerSpawnerComponent::TerrainLayerSpawnerComponent(const TerrainLayerSpawnerConfig& configuration)
|
||||||
|
: m_configuration(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::Activate()
|
||||||
|
{
|
||||||
|
AZ::TransformNotificationBus::Handler::BusConnect(GetEntityId());
|
||||||
|
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId());
|
||||||
|
TerrainAreaRequestBus::Handler::BusConnect(GetEntityId());
|
||||||
|
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RegisterArea, GetEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::Deactivate()
|
||||||
|
{
|
||||||
|
TerrainAreaRequestBus::Handler::BusDisconnect();
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::UnregisterArea, GetEntityId());
|
||||||
|
|
||||||
|
AZ::TransformNotificationBus::Handler::BusDisconnect();
|
||||||
|
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainLayerSpawnerComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<const TerrainLayerSpawnerConfig*>(baseConfig))
|
||||||
|
{
|
||||||
|
m_configuration = *config;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainLayerSpawnerComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<TerrainLayerSpawnerConfig*>(outBaseConfig))
|
||||||
|
{
|
||||||
|
*config = m_configuration;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, [[maybe_unused]] const AZ::Transform& world)
|
||||||
|
{
|
||||||
|
RefreshArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::OnShapeChanged([[maybe_unused]] ShapeChangeReasons changeReason)
|
||||||
|
{
|
||||||
|
RefreshArea();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::RegisterArea()
|
||||||
|
{
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RegisterArea, GetEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainLayerSpawnerComponent::RefreshArea()
|
||||||
|
{
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::RefreshArea, GetEntityId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Asset/AssetCommon.h>
|
||||||
|
#include <AzCore/Component/Component.h>
|
||||||
|
#include <AzCore/Math/Vector3.h>
|
||||||
|
|
||||||
|
#include <AzCore/Jobs/JobManagerBus.h>
|
||||||
|
#include <AzCore/Jobs/JobFunction.h>
|
||||||
|
|
||||||
|
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||||
|
#include <TerrainSystem/TerrainSystemBus.h>
|
||||||
|
|
||||||
|
#include <AzCore/Component/TransformBus.h>
|
||||||
|
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||||
|
#include <AzCore/Math/Aabb.h>
|
||||||
|
|
||||||
|
namespace LmbrCentral
|
||||||
|
{
|
||||||
|
template<typename, typename>
|
||||||
|
class EditorWrappedComponentBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
namespace AreaConstants
|
||||||
|
{
|
||||||
|
static const AZ::u32 s_backgroundLayer = 0;
|
||||||
|
static const AZ::u32 s_foregroundLayer = 1;
|
||||||
|
static const AZ::u32 s_priorityMin = 0;
|
||||||
|
static const AZ::u32 s_priorityMax = 10000; //arbitrary number because std::numeric_limits<AZ::u32>::max() always dislays -1 in RPE
|
||||||
|
static const AZ::u32 s_prioritySoftMax = 100; //design specified slider range
|
||||||
|
}
|
||||||
|
|
||||||
|
class TerrainLayerSpawnerConfig
|
||||||
|
: public AZ::ComponentConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_CLASS_ALLOCATOR(TerrainLayerSpawnerConfig, AZ::SystemAllocator, 0);
|
||||||
|
AZ_RTTI(TerrainLayerSpawnerConfig, "{8E0695DE-E843-4858-BAEA-70953E74C810}", AZ::ComponentConfig);
|
||||||
|
static void Reflect(AZ::ReflectContext* context);
|
||||||
|
|
||||||
|
AZStd::vector<AZStd::pair<AZ::u32, AZStd::string>> GetSelectableLayers() const;
|
||||||
|
AZ::u32 m_layer = AreaConstants::s_foregroundLayer;
|
||||||
|
AZ::u32 m_priority = AreaConstants::s_priorityMin;
|
||||||
|
bool m_useGroundPlane = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TerrainLayerSpawnerComponent
|
||||||
|
: public AZ::Component
|
||||||
|
, private AZ::TransformNotificationBus::Handler
|
||||||
|
, private LmbrCentral::ShapeComponentNotificationsBus::Handler
|
||||||
|
, private Terrain::TerrainAreaRequestBus::Handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename, typename>
|
||||||
|
friend class LmbrCentral::EditorWrappedComponentBase;
|
||||||
|
AZ_COMPONENT(TerrainLayerSpawnerComponent, "{3848605F-A4EA-478C-B710-84AB8DCA9EC5}");
|
||||||
|
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void Reflect(AZ::ReflectContext* context);
|
||||||
|
|
||||||
|
TerrainLayerSpawnerComponent(const TerrainLayerSpawnerConfig& configuration);
|
||||||
|
TerrainLayerSpawnerComponent() = default;
|
||||||
|
~TerrainLayerSpawnerComponent() = default;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// AZ::Component interface implementation
|
||||||
|
void Activate() override;
|
||||||
|
void Deactivate() override;
|
||||||
|
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||||
|
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// AZ::TransformNotificationBus::Handler
|
||||||
|
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||||
|
|
||||||
|
// ShapeComponentNotificationsBus
|
||||||
|
void OnShapeChanged(ShapeChangeReasons changeReason) override;
|
||||||
|
|
||||||
|
void RegisterArea() override;
|
||||||
|
void RefreshArea() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TerrainLayerSpawnerConfig m_configuration;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Components/TerrainWorldComponent.h>
|
||||||
|
#include <AzCore/Asset/AssetManagerBus.h>
|
||||||
|
#include <AzCore/Component/Entity.h>
|
||||||
|
#include <AzCore/Asset/AssetManager.h>
|
||||||
|
#include <AzCore/RTTI/BehaviorContext.h>
|
||||||
|
#include <AzCore/Serialization/EditContext.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
void TerrainWorldConfig::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainWorldConfig, AZ::ComponentConfig>()
|
||||||
|
->Version(1)
|
||||||
|
->Field("WorldMin", &TerrainWorldConfig::m_worldMin)
|
||||||
|
->Field("WorldMax", &TerrainWorldConfig::m_worldMax)
|
||||||
|
->Field("HeightQueryResolution", &TerrainWorldConfig::m_heightQueryResolution)
|
||||||
|
;
|
||||||
|
|
||||||
|
AZ::EditContext* edit = serialize->GetEditContext();
|
||||||
|
if (edit)
|
||||||
|
{
|
||||||
|
edit->Class<TerrainWorldConfig>(
|
||||||
|
"Terrain World Component", "Data required for the terrain system to run")
|
||||||
|
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||||
|
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
|
||||||
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||||
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||||
|
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMin, "World Bounds (Min)", "")
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_worldMax, "World Bounds (Max)", "")
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldConfig::m_heightQueryResolution, "Height Query Resolution (m)", "")
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldComponent::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
TerrainWorldConfig::Reflect(context);
|
||||||
|
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainWorldComponent, AZ::Component>()
|
||||||
|
->Version(0)
|
||||||
|
->Field("Configuration", &TerrainWorldComponent::m_configuration)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TerrainWorldComponent::TerrainWorldComponent(const TerrainWorldConfig& configuration)
|
||||||
|
: m_configuration(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TerrainWorldComponent::~TerrainWorldComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldComponent::Activate()
|
||||||
|
{
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::SetWorldMin, m_configuration.m_worldMin);
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::SetWorldMax, m_configuration.m_worldMax);
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(
|
||||||
|
&TerrainSystemServiceRequestBus::Events::SetHeightQueryResolution, m_configuration.m_heightQueryResolution);
|
||||||
|
|
||||||
|
// Currently, the Terrain System Component owns the Terrain System instance because the Terrain World component gets recreated
|
||||||
|
// every time an entity is added or removed to a level. If this ever changes, the Terrain System ownership could move into
|
||||||
|
// the level component.
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::Activate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldComponent::Deactivate()
|
||||||
|
{
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(&TerrainSystemServiceRequestBus::Events::Deactivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainWorldComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<const TerrainWorldConfig*>(baseConfig))
|
||||||
|
{
|
||||||
|
m_configuration = *config;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainWorldComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<TerrainWorldConfig*>(outBaseConfig))
|
||||||
|
{
|
||||||
|
*config = m_configuration;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AzCore/Asset/AssetCommon.h>
|
||||||
|
#include <AzCore/Component/Component.h>
|
||||||
|
#include <AzCore/Math/Vector3.h>
|
||||||
|
#include <TerrainSystem/TerrainSystem.h>
|
||||||
|
|
||||||
|
namespace LmbrCentral
|
||||||
|
{
|
||||||
|
template<typename, typename>
|
||||||
|
class EditorWrappedComponentBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
class TerrainWorldConfig
|
||||||
|
: public AZ::ComponentConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AZ_CLASS_ALLOCATOR(TerrainWorldConfig, AZ::SystemAllocator, 0);
|
||||||
|
AZ_RTTI(TerrainWorldConfig, "{295844DB-20DD-45B2-94DB-4245D5AE9AFF}", AZ::ComponentConfig);
|
||||||
|
static void Reflect(AZ::ReflectContext* context);
|
||||||
|
|
||||||
|
AZ::Vector3 m_worldMin{ 0.0f, 0.0f, 0.0f };
|
||||||
|
AZ::Vector3 m_worldMax{ 1024.0f, 1024.0f, 1024.0f };
|
||||||
|
AZ::Vector2 m_heightQueryResolution{ 1.0f, 1.0f };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TerrainWorldComponent
|
||||||
|
: public AZ::Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename, typename>
|
||||||
|
friend class LmbrCentral::EditorWrappedComponentBase;
|
||||||
|
AZ_COMPONENT(TerrainWorldComponent, "{4734EFDC-135D-4BF5-BE57-4F9AD03ADF78}");
|
||||||
|
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
|
||||||
|
static void Reflect(AZ::ReflectContext* context);
|
||||||
|
|
||||||
|
TerrainWorldComponent(const TerrainWorldConfig& configuration);
|
||||||
|
TerrainWorldComponent() = default;
|
||||||
|
~TerrainWorldComponent() override;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// AZ::Component interface implementation
|
||||||
|
void Activate() override;
|
||||||
|
void Deactivate() override;
|
||||||
|
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||||
|
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TerrainWorldConfig m_configuration;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||||
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Components/TerrainWorldDebuggerComponent.h>
|
||||||
|
|
||||||
|
#include <AzCore/Asset/AssetManager.h>
|
||||||
|
#include <AzCore/Asset/AssetManagerBus.h>
|
||||||
|
#include <AzCore/Component/Entity.h>
|
||||||
|
#include <AzCore/RTTI/BehaviorContext.h>
|
||||||
|
#include <AzCore/Serialization/EditContext.h>
|
||||||
|
#include <AzCore/Serialization/SerializeContext.h>
|
||||||
|
|
||||||
|
#include <AzFramework/Visibility/EntityBoundsUnionBus.h>
|
||||||
|
|
||||||
|
#include <Atom/RPI.Public/View.h>
|
||||||
|
#include <Atom/RPI.Public/ViewportContext.h>
|
||||||
|
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||||
|
|
||||||
|
namespace Terrain
|
||||||
|
{
|
||||||
|
void TerrainWorldDebuggerConfig::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainWorldDebuggerConfig, AZ::ComponentConfig>()
|
||||||
|
->Version(1)
|
||||||
|
->Field("DebugWireframe", &TerrainWorldDebuggerConfig::m_drawWireframe)
|
||||||
|
->Field("DebugWorldBounds", &TerrainWorldDebuggerConfig::m_drawWorldBounds)
|
||||||
|
;
|
||||||
|
|
||||||
|
AZ::EditContext* edit = serialize->GetEditContext();
|
||||||
|
if (edit)
|
||||||
|
{
|
||||||
|
edit->Class<TerrainWorldDebuggerConfig>(
|
||||||
|
"Terrain World Debugger Component", "Optional component for enabling terrain debugging features.")
|
||||||
|
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||||
|
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC_CE("Level") }))
|
||||||
|
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||||
|
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||||
|
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldDebuggerConfig::m_drawWireframe, "Show Wireframe", "")
|
||||||
|
->DataElement(AZ::Edit::UIHandlers::Default, &TerrainWorldDebuggerConfig::m_drawWorldBounds, "Show World Bounds", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainDebugService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainDebugService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||||
|
{
|
||||||
|
services.push_back(AZ_CRC_CE("TerrainService"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::Reflect(AZ::ReflectContext* context)
|
||||||
|
{
|
||||||
|
TerrainWorldDebuggerConfig::Reflect(context);
|
||||||
|
|
||||||
|
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||||
|
if (serialize)
|
||||||
|
{
|
||||||
|
serialize->Class<TerrainWorldDebuggerComponent, AZ::Component>()
|
||||||
|
->Version(0)
|
||||||
|
->Field("Configuration", &TerrainWorldDebuggerComponent::m_configuration)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TerrainWorldDebuggerComponent::TerrainWorldDebuggerComponent(const TerrainWorldDebuggerConfig& configuration)
|
||||||
|
: m_configuration(configuration)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TerrainWorldDebuggerComponent::~TerrainWorldDebuggerComponent()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::Activate()
|
||||||
|
{
|
||||||
|
m_wireframeBounds = AZ::Aabb::CreateNull();
|
||||||
|
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(
|
||||||
|
&TerrainSystemServiceRequestBus::Events::SetDebugWireframe, m_configuration.m_drawWireframe);
|
||||||
|
|
||||||
|
AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
|
||||||
|
AzFramework::BoundsRequestBus::Handler::BusConnect(GetEntityId());
|
||||||
|
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::Deactivate()
|
||||||
|
{
|
||||||
|
TerrainSystemServiceRequestBus::Broadcast(
|
||||||
|
&TerrainSystemServiceRequestBus::Events::SetDebugWireframe, false);
|
||||||
|
|
||||||
|
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
|
||||||
|
AzFramework::BoundsRequestBus::Handler::BusDisconnect();
|
||||||
|
AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
|
||||||
|
|
||||||
|
m_wireframeBounds = AZ::Aabb::CreateNull();
|
||||||
|
m_wireframeSectors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainWorldDebuggerComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<const TerrainWorldDebuggerConfig*>(baseConfig))
|
||||||
|
{
|
||||||
|
m_configuration = *config;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TerrainWorldDebuggerComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
|
||||||
|
{
|
||||||
|
if (auto config = azrtti_cast<TerrainWorldDebuggerConfig*>(outBaseConfig))
|
||||||
|
{
|
||||||
|
*config = m_configuration;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Aabb TerrainWorldDebuggerComponent::GetWorldBounds()
|
||||||
|
{
|
||||||
|
AZ::Aabb terrainAabb = AZ::Aabb::CreateFromPoint(AZ::Vector3::CreateZero());
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
terrainAabb, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb);
|
||||||
|
|
||||||
|
return terrainAabb;
|
||||||
|
}
|
||||||
|
|
||||||
|
AZ::Aabb TerrainWorldDebuggerComponent::GetLocalBounds()
|
||||||
|
{
|
||||||
|
// This is a level component, so the local bounds will always be the same as the world bounds.
|
||||||
|
return GetWorldBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::DisplayEntityViewport(
|
||||||
|
const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
||||||
|
{
|
||||||
|
// Draw a wireframe box around the entire terrain world bounds
|
||||||
|
if (m_configuration.m_drawWorldBounds)
|
||||||
|
{
|
||||||
|
AZ::Color outlineColor(1.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
AZ::Aabb aabb = GetWorldBounds();
|
||||||
|
|
||||||
|
debugDisplay.SetColor(outlineColor);
|
||||||
|
debugDisplay.DrawWireBox(aabb.GetMin(), aabb.GetMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a wireframe representation of the terrain surface
|
||||||
|
if (m_configuration.m_drawWireframe && !m_wireframeSectors.empty())
|
||||||
|
{
|
||||||
|
// Start by assuming we'll draw the entire world.
|
||||||
|
AZ::Aabb drawingAabb = GetWorldBounds();
|
||||||
|
|
||||||
|
// Assuming we can get the camera, reduce the drawing bounds to a fixed distance around the camera.
|
||||||
|
if (auto viewportContextRequests = AZ::RPI::ViewportContextRequests::Get(); viewportContextRequests)
|
||||||
|
{
|
||||||
|
// Get the current camera position.
|
||||||
|
AZ::RPI::ViewportContextPtr viewportContext = viewportContextRequests->GetViewportContextById(viewportInfo.m_viewportId);
|
||||||
|
AZ::Vector3 cameraPos = viewportContext->GetCameraTransform().GetTranslation();
|
||||||
|
|
||||||
|
// Determine how far to draw in each direction in world space based on our MaxSectorsToDraw
|
||||||
|
AZ::Vector2 queryResolution = AZ::Vector2(1.0f);
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainGridResolution);
|
||||||
|
AZ::Vector3 viewDistance(
|
||||||
|
queryResolution.GetX() * SectorSizeInGridPoints * sqrtf(MaxSectorsToDraw),
|
||||||
|
queryResolution.GetY() * SectorSizeInGridPoints * sqrtf(MaxSectorsToDraw),
|
||||||
|
0.0f);
|
||||||
|
|
||||||
|
// Create an AABB around the camera based on how far we want to be able to draw in each direction and clamp the
|
||||||
|
// drawing AABB to it.
|
||||||
|
AZ::Aabb cameraAabb = AZ::Aabb::CreateFromMinMax(
|
||||||
|
AZ::Vector3(
|
||||||
|
cameraPos.GetX() - viewDistance.GetX(), cameraPos.GetY() - viewDistance.GetY(), drawingAabb.GetMin().GetZ()),
|
||||||
|
AZ::Vector3(
|
||||||
|
cameraPos.GetX() + viewDistance.GetX(), cameraPos.GetY() + viewDistance.GetY(), drawingAabb.GetMin().GetZ()));
|
||||||
|
drawingAabb.Clamp(cameraAabb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each sector, if it appears within our view distance, draw it.
|
||||||
|
for (auto& sector : m_wireframeSectors)
|
||||||
|
{
|
||||||
|
if (drawingAabb.Overlaps(sector.m_aabb))
|
||||||
|
{
|
||||||
|
if (!sector.m_lineVertices.empty())
|
||||||
|
{
|
||||||
|
const AZ::Color primaryColor = AZ::Color(0.25f, 0.25f, 0.25f, 1.0f);
|
||||||
|
debugDisplay.DrawLines(sector.m_lineVertices, primaryColor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AZ_Warning("Debug", false, "empty sector!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::RefreshCachedWireframeGrid(const AZ::Aabb& dirtyRegion)
|
||||||
|
{
|
||||||
|
// Get the terrain world bounds and grid resolution.
|
||||||
|
|
||||||
|
AZ::Aabb worldBounds = GetWorldBounds();
|
||||||
|
|
||||||
|
AZ::Vector2 queryResolution = AZ::Vector2(1.0f);
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainGridResolution);
|
||||||
|
|
||||||
|
// Calculate the world size of each sector. Note that this size actually ends at the last point, not the last square.
|
||||||
|
// So for example, the sector size for 3 points will go from (*--*--*) even though it will be used to draw (*--*--*--).
|
||||||
|
const float xSectorSize = (queryResolution.GetX() * SectorSizeInGridPoints);
|
||||||
|
const float ySectorSize = (queryResolution.GetY() * SectorSizeInGridPoints);
|
||||||
|
|
||||||
|
// Calculate the total number of sectors to cache. The world bounds might not be evenly divisible by sector bounds, so we add
|
||||||
|
// an extra sector's worth of size in each direction so that clamping down to an integer still accounts for that fractional sector.
|
||||||
|
const int32_t numSectorsX = aznumeric_cast<int32_t>((worldBounds.GetXExtent() + xSectorSize) / xSectorSize);
|
||||||
|
const int32_t numSectorsY = aznumeric_cast<int32_t>((worldBounds.GetYExtent() + ySectorSize) / ySectorSize);
|
||||||
|
|
||||||
|
// If we haven't cached anything before, or if the world bounds has changed, clear our cache structure and repopulate it
|
||||||
|
// with WireframeSector entries with the proper AABB sizes.
|
||||||
|
if (!m_wireframeBounds.IsValid() || !dirtyRegion.IsValid() || !m_wireframeBounds.IsClose(worldBounds))
|
||||||
|
{
|
||||||
|
m_wireframeBounds = worldBounds;
|
||||||
|
|
||||||
|
m_wireframeSectors.clear();
|
||||||
|
m_wireframeSectors.reserve(numSectorsX * numSectorsY);
|
||||||
|
|
||||||
|
for (int32_t ySector = 0; ySector < numSectorsY; ySector++)
|
||||||
|
{
|
||||||
|
for (int32_t xSector = 0; xSector < numSectorsX; xSector++)
|
||||||
|
{
|
||||||
|
// For each sector, set up the AABB for the sector and reserve memory for the line vertices.
|
||||||
|
WireframeSector sector;
|
||||||
|
sector.m_lineVertices.reserve(VerticesPerSector);
|
||||||
|
sector.m_aabb = AZ::Aabb::CreateFromMinMax(
|
||||||
|
AZ::Vector3(
|
||||||
|
worldBounds.GetMin().GetX() + (xSector * xSectorSize), worldBounds.GetMin().GetY() + (ySector * ySectorSize),
|
||||||
|
worldBounds.GetMin().GetZ()),
|
||||||
|
AZ::Vector3(
|
||||||
|
worldBounds.GetMin().GetX() + ((xSector + 1) * xSectorSize),
|
||||||
|
worldBounds.GetMin().GetY() + ((ySector + 1) * ySectorSize), worldBounds.GetMax().GetZ()));
|
||||||
|
|
||||||
|
sector.m_aabb.Clamp(worldBounds);
|
||||||
|
|
||||||
|
m_wireframeSectors.push_back(AZStd::move(sector));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the visibility system that our bounds have changed.
|
||||||
|
AzFramework::IEntityBoundsUnionRequestBus::Broadcast(
|
||||||
|
&AzFramework::IEntityBoundsUnionRequestBus::Events::RefreshEntityLocalBoundsUnion, GetEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each sector, if it overlaps with the dirty region, clear it out and recache the wireframe line data.
|
||||||
|
for (auto& sector : m_wireframeSectors)
|
||||||
|
{
|
||||||
|
if (dirtyRegion.IsValid() && !dirtyRegion.Overlaps(sector.m_aabb))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sector.m_lineVertices.clear();
|
||||||
|
|
||||||
|
for (float y = sector.m_aabb.GetMin().GetY(); y < sector.m_aabb.GetMax().GetY(); y += queryResolution.GetY())
|
||||||
|
{
|
||||||
|
for (float x = sector.m_aabb.GetMin().GetX(); x < sector.m_aabb.GetMax().GetX(); x += queryResolution.GetX())
|
||||||
|
{
|
||||||
|
float x1 = x + queryResolution.GetX();
|
||||||
|
float y1 = y + queryResolution.GetY();
|
||||||
|
|
||||||
|
float z00 = 0.0f;
|
||||||
|
float z01 = 0.0f;
|
||||||
|
float z10 = 0.0f;
|
||||||
|
bool terrainExists;
|
||||||
|
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
z00, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x, y,
|
||||||
|
AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, &terrainExists);
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
z01, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x, y1,
|
||||||
|
AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, &terrainExists);
|
||||||
|
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||||
|
z10, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats, x1, y,
|
||||||
|
AzFramework::Terrain::TerrainDataRequests::Sampler::DEFAULT, &terrainExists);
|
||||||
|
|
||||||
|
sector.m_lineVertices.push_back(AZ::Vector3(x, y, z00));
|
||||||
|
sector.m_lineVertices.push_back(AZ::Vector3(x1, y, z10));
|
||||||
|
|
||||||
|
sector.m_lineVertices.push_back(AZ::Vector3(x, y, z00));
|
||||||
|
sector.m_lineVertices.push_back(AZ::Vector3(x, y1, z01));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainWorldDebuggerComponent::OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask)
|
||||||
|
{
|
||||||
|
if (dataChangedMask & (TerrainDataChangedMask::Settings | TerrainDataChangedMask::HeightData))
|
||||||
|
{
|
||||||
|
RefreshCachedWireframeGrid(dirtyRegion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Terrain
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue