Merge branch 'development' of https://github.com/o3de/o3de into cgalvan/RemovedGradientImageBuilder
This commit is contained in:
@@ -12,7 +12,7 @@ import pytest
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
from ly_test_tools.benchmark.data_aggregator import BenchmarkDataAggregator
|
||||
from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
|
||||
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorTestSuite
|
||||
from Atom.atom_utils.atom_component_helper import compare_screenshot_to_golden_image, golden_images_directory
|
||||
|
||||
DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
|
||||
@@ -23,89 +23,137 @@ logger = logging.getLogger(__name__)
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
# Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests.
|
||||
global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"]
|
||||
|
||||
global_extra_cmdline_args = ["-autotest_mode"] # Default is ["-BatchMode", "-autotest_mode"]
|
||||
use_null_renderer = False # Default is True
|
||||
enable_prefab_system = False
|
||||
|
||||
@pytest.mark.test_case_id("C34603773")
|
||||
class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest):
|
||||
use_null_renderer = False # Default is True
|
||||
screenshot_name = "AtomBasicLevelSetup.ppm"
|
||||
test_screenshots = [] # Gets set by setup()
|
||||
screenshot_directory = "" # Gets set by setup()
|
||||
@staticmethod
|
||||
def screenshot_setup(screenshot_directory, screenshot_names):
|
||||
"""
|
||||
:param screenshot_names: list of screenshot file names with extensions
|
||||
:return: tuple test_screenshots, golden_images each a list of full file paths
|
||||
"""
|
||||
test_screenshots = []
|
||||
golden_images = []
|
||||
for screenshot in screenshot_names:
|
||||
screenshot_path = os.path.join(screenshot_directory, screenshot)
|
||||
test_screenshots.append(screenshot_path)
|
||||
file_system.delete(test_screenshots, True, True)
|
||||
for golden_image in screenshot_names:
|
||||
golden_image_path = os.path.join(golden_images_directory(), golden_image)
|
||||
golden_images.append(golden_image_path)
|
||||
return test_screenshots, golden_images
|
||||
|
||||
# Clear existing test screenshots before starting test.
|
||||
def setup(self, workspace):
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)]
|
||||
file_system.delete(test_screenshots, True, True)
|
||||
|
||||
golden_images = [os.path.join(golden_images_directory(), screenshot_name)]
|
||||
|
||||
from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module
|
||||
|
||||
assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
class AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages(EditorSharedTest):
|
||||
use_null_renderer = False # Default is True
|
||||
screenshot_names = [
|
||||
"AreaLight_1.ppm",
|
||||
"AreaLight_2.ppm",
|
||||
"AreaLight_3.ppm",
|
||||
"AreaLight_4.ppm",
|
||||
"AreaLight_5.ppm",
|
||||
]
|
||||
test_screenshots = [] # Gets set by setup()
|
||||
screenshot_directory = "" # Gets set by setup()
|
||||
|
||||
# Clear existing test screenshots before starting test.
|
||||
def setup(self, workspace):
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
for screenshot in self.screenshot_names:
|
||||
screenshot_path = os.path.join(screenshot_directory, screenshot)
|
||||
self.test_screenshots.append(screenshot_path)
|
||||
file_system.delete(self.test_screenshots, True, True)
|
||||
|
||||
golden_images = []
|
||||
for golden_image in screenshot_names:
|
||||
golden_image_path = os.path.join(golden_images_directory(), golden_image)
|
||||
golden_images.append(golden_image_path)
|
||||
|
||||
class AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages_DX12(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_AreaLightScreenshotTest as test_module
|
||||
|
||||
assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True
|
||||
extra_cmdline_args = ["-rhi=dx12"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"AreaLight_1.ppm",
|
||||
"AreaLight_2.ppm",
|
||||
"AreaLight_3.ppm",
|
||||
"AreaLight_4.ppm",
|
||||
"AreaLight_5.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525095")
|
||||
class AtomGPU_LightComponent_AreaLightScreenshotsMatchGoldenImages_Vulkan(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_AreaLightScreenshotTest as test_module
|
||||
|
||||
extra_cmdline_args = ["-rhi=vulkan"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"AreaLight_1.ppm",
|
||||
"AreaLight_2.ppm",
|
||||
"AreaLight_3.ppm",
|
||||
"AreaLight_4.ppm",
|
||||
"AreaLight_5.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525110")
|
||||
class AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages(EditorSharedTest):
|
||||
use_null_renderer = False # Default is True
|
||||
screenshot_names = [
|
||||
"SpotLight_1.ppm",
|
||||
"SpotLight_2.ppm",
|
||||
"SpotLight_3.ppm",
|
||||
"SpotLight_4.ppm",
|
||||
"SpotLight_5.ppm",
|
||||
"SpotLight_6.ppm",
|
||||
]
|
||||
test_screenshots = [] # Gets set by setup()
|
||||
screenshot_directory = "" # Gets set by setup()
|
||||
|
||||
# Clear existing test screenshots before starting test.
|
||||
def setup(self, workspace):
|
||||
screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
for screenshot in self.screenshot_names:
|
||||
screenshot_path = os.path.join(screenshot_directory, screenshot)
|
||||
self.test_screenshots.append(screenshot_path)
|
||||
file_system.delete(self.test_screenshots, True, True)
|
||||
|
||||
golden_images = []
|
||||
for golden_image in screenshot_names:
|
||||
golden_image_path = os.path.join(golden_images_directory(), golden_image)
|
||||
golden_images.append(golden_image_path)
|
||||
|
||||
class AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages_DX12(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_SpotLightScreenshotTest as test_module
|
||||
|
||||
assert compare_screenshot_to_golden_image(screenshot_directory, test_screenshots, golden_images, 0.99) is True
|
||||
extra_cmdline_args = ["-rhi=dx12"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"SpotLight_1.ppm",
|
||||
"SpotLight_2.ppm",
|
||||
"SpotLight_3.ppm",
|
||||
"SpotLight_4.ppm",
|
||||
"SpotLight_5.ppm",
|
||||
"SpotLight_6.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
@pytest.mark.test_case_id("C34525110")
|
||||
class AtomGPU_LightComponent_SpotLightScreenshotsMatchGoldenImages_Vulkan(EditorSingleTest):
|
||||
from Atom.tests import hydra_AtomGPU_SpotLightScreenshotTest as test_module
|
||||
|
||||
extra_cmdline_args = ["-rhi=vulkan"]
|
||||
|
||||
# Custom setup/teardown to remove old screenshots and establish paths to golden images
|
||||
def setup(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
self.screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
|
||||
self.screenshot_names = [
|
||||
"SpotLight_1.ppm",
|
||||
"SpotLight_2.ppm",
|
||||
"SpotLight_3.ppm",
|
||||
"SpotLight_4.ppm",
|
||||
"SpotLight_5.ppm",
|
||||
"SpotLight_6.ppm",
|
||||
]
|
||||
self.test_screenshots, self.golden_images = TestAutomation.screenshot_setup(
|
||||
screenshot_directory=self.screenshot_directory,
|
||||
screenshot_names=self.screenshot_names)
|
||||
|
||||
def wrap_run(self, request, workspace, editor, editor_test_results, launcher_platform):
|
||||
yield
|
||||
assert compare_screenshot_to_golden_image(self.screenshot_directory,
|
||||
self.test_screenshots,
|
||||
self.golden_images,
|
||||
similarity_threshold=0.96) is True
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rhi', ['dx12', 'vulkan'])
|
||||
|
||||
@@ -86,9 +86,8 @@ def compare_screenshot_similarity(
|
||||
if create_zip_archive:
|
||||
create_screenshots_archive(screenshot_directory)
|
||||
result = (
|
||||
f"When comparing the test_screenshot: '{test_screenshot}' "
|
||||
f"to golden_image: '{golden_image}' the mean similarity of '{mean_similarity}' "
|
||||
f"was lower than the similarity threshold of '{similarity_threshold}'. ")
|
||||
f"When comparing the test_screenshot: '{test_screenshot}' to golden_image: '{golden_image}'.\n"
|
||||
f"The mean similarity ({mean_similarity}) was lower than the similarity threshold ({similarity_threshold})")
|
||||
|
||||
return result
|
||||
|
||||
@@ -123,7 +122,9 @@ def initial_viewport_setup(screen_width=1280, screen_height=720):
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
general.set_viewport_size(screen_width, screen_height)
|
||||
general.idle_wait_frames(1)
|
||||
general.update_viewport()
|
||||
general.idle_wait_frames(1)
|
||||
|
||||
|
||||
def enter_exit_game_mode_take_screenshot(screenshot_name, enter_game_tuple, exit_game_tuple, timeout_in_seconds=4):
|
||||
@@ -137,13 +138,18 @@ def enter_exit_game_mode_take_screenshot(screenshot_name, enter_game_tuple, exit
|
||||
"""
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
from editor_python_test_tools.utils import TestHelper
|
||||
from editor_python_test_tools.utils import TestHelper, Report
|
||||
|
||||
from Atom.atom_utils.screenshot_utils import ScreenshotHelper
|
||||
|
||||
screenshot_helper = ScreenshotHelper(general.idle_wait_frames)
|
||||
TestHelper.enter_game_mode(enter_game_tuple)
|
||||
TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=timeout_in_seconds)
|
||||
ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(screenshot_name)
|
||||
screenshot_helper.prepare_viewport_for_screenshot(1920, 1080)
|
||||
success_screenshot = TestHelper.wait_for_condition(
|
||||
function=lambda: screenshot_helper.capture_screenshot_blocking(screenshot_name),
|
||||
timeout_in_seconds=timeout_in_seconds)
|
||||
Report.result(("Screenshot taken", "Screenshot failed to be taken"), success_screenshot)
|
||||
TestHelper.exit_game_mode(exit_game_tuple)
|
||||
TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=timeout_in_seconds)
|
||||
|
||||
|
||||
@@ -107,10 +107,8 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel():
|
||||
18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component.
|
||||
19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component.
|
||||
20. Set the Camera Entity rotation value and set the Camera component Field of View value.
|
||||
21. Enter game mode.
|
||||
22. Take screenshot.
|
||||
23. Exit game mode.
|
||||
24. Look for errors.
|
||||
21. Enter/Exit game mode taking screenshot.
|
||||
22. Look for errors.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
@@ -127,7 +125,7 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel():
|
||||
|
||||
from Atom.atom_utils.atom_constants import AtomComponentProperties
|
||||
from Atom.atom_utils.atom_component_helper import initial_viewport_setup
|
||||
from Atom.atom_utils.screenshot_utils import ScreenshotHelper
|
||||
from Atom.atom_utils.atom_component_helper import enter_exit_game_mode_take_screenshot
|
||||
|
||||
DEGREE_RADIAN_FACTOR = 0.0174533
|
||||
SCREENSHOT_NAME = "AtomBasicLevelSetup"
|
||||
@@ -300,18 +298,10 @@ def AtomGPU_BasicLevelSetup_SetsUpLevel():
|
||||
Report.result(Tests.camera_fov_set, camera_component.get_component_property_value(
|
||||
AtomComponentProperties.camera('Field of view')) == camera_fov_value)
|
||||
|
||||
# 21. Enter game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
TestHelper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0)
|
||||
# 21. Enter/Exit game mode taking screenshot.
|
||||
enter_exit_game_mode_take_screenshot(f"{SCREENSHOT_NAME}.ppm", Tests.enter_game_mode, Tests.exit_game_mode)
|
||||
|
||||
# 22. Take screenshot.
|
||||
ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(f"{SCREENSHOT_NAME}.ppm")
|
||||
|
||||
# 23. Exit game mode.
|
||||
TestHelper.exit_game_mode(Tests.exit_game_mode)
|
||||
TestHelper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0)
|
||||
|
||||
# 24. Look for errors.
|
||||
# 22. Look for errors.
|
||||
TestHelper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
|
||||
for error_info in error_tracer.errors:
|
||||
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
|
||||
|
||||
@@ -360,18 +360,6 @@ void ReflectedPropertyControl::CreateItems(XmlNodeRef node, CVarBlockPtr& outBlo
|
||||
textureVar->Set(textureName);
|
||||
}
|
||||
}
|
||||
else if (!azstricmp(type, "color"))
|
||||
{
|
||||
CSmartVariable<Vec3> colorVar;
|
||||
AddVariable(group, colorVar, child->getTag(), humanReadableName.toUtf8().data(), strDescription.toUtf8().data(), func, pUserData, IVariable::DT_COLOR);
|
||||
ColorB color;
|
||||
if (child->getAttr("value", color))
|
||||
{
|
||||
ColorF colorLinear = ColorGammaToLinear(QColor(color.r, color.g, color.b));
|
||||
Vec3 colorVec3(colorLinear.r, colorLinear.g, colorLinear.b);
|
||||
colorVar->Set(colorVec3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -243,9 +243,6 @@ void ReflectedPropertyItem::SetVariable(IVariable *var)
|
||||
case ePropertySelection:
|
||||
m_reflectedVarAdapter = new ReflectedVarEnumAdapter;
|
||||
break;
|
||||
case ePropertyColor:
|
||||
m_reflectedVarAdapter = new ReflectedVarColorAdapter;
|
||||
break;
|
||||
case ePropertyUser:
|
||||
m_reflectedVarAdapter = new ReflectedVarUserAdapter;
|
||||
break;
|
||||
|
||||
@@ -312,50 +312,6 @@ void ReflectedVarVector4Adapter::SyncIVarToReflectedVar(IVariable *pVariable)
|
||||
pVariable->Set(Vec4(m_reflectedVar->m_value.GetX(), m_reflectedVar->m_value.GetY(), m_reflectedVar->m_value.GetZ(), m_reflectedVar->m_value.GetW()));
|
||||
}
|
||||
|
||||
|
||||
void ReflectedVarColorAdapter::SetVariable(IVariable *pVariable)
|
||||
{
|
||||
m_reflectedVar.reset(new CReflectedVarColor(pVariable->GetHumanName().toUtf8().data()));
|
||||
m_reflectedVar->m_description = pVariable->GetDescription().toUtf8().data();
|
||||
}
|
||||
|
||||
void ReflectedVarColorAdapter::SyncReflectedVarToIVar(IVariable *pVariable)
|
||||
{
|
||||
if (pVariable->GetType() == IVariable::VECTOR)
|
||||
{
|
||||
Vec3 v(0, 0, 0);
|
||||
pVariable->Get(v);
|
||||
const QColor col = ColorLinearToGamma(ColorF(v.x, v.y, v.z));
|
||||
m_reflectedVar->m_color.Set(static_cast<float>(col.redF()), static_cast<float>(col.greenF()), static_cast<float>(col.blueF()));
|
||||
}
|
||||
else
|
||||
{
|
||||
int col(0);
|
||||
pVariable->Get(col);
|
||||
const QColor qcolor = ColorToQColor((uint32)col);
|
||||
m_reflectedVar->m_color.Set(static_cast<float>(qcolor.redF()), static_cast<float>(qcolor.greenF()), static_cast<float>(qcolor.blueF()));
|
||||
}
|
||||
}
|
||||
|
||||
void ReflectedVarColorAdapter::SyncIVarToReflectedVar(IVariable *pVariable)
|
||||
{
|
||||
if (pVariable->GetType() == IVariable::VECTOR)
|
||||
{
|
||||
ColorF colLin = ColorGammaToLinear(QColor::fromRgbF(m_reflectedVar->m_color.GetX(), m_reflectedVar->m_color.GetY(), m_reflectedVar->m_color.GetZ()));
|
||||
pVariable->Set(Vec3(colLin.r, colLin.g, colLin.b));
|
||||
}
|
||||
else
|
||||
{
|
||||
int ir = static_cast<int>(m_reflectedVar->m_color.GetX() * 255.0f);
|
||||
int ig = static_cast<int>(m_reflectedVar->m_color.GetY() * 255.0f);
|
||||
int ib = static_cast<int>(m_reflectedVar->m_color.GetZ() * 255.0f);
|
||||
|
||||
pVariable->Set(static_cast<int>(RGB(ir, ig, ib)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ReflectedVarResourceAdapter::SetVariable(IVariable *pVariable)
|
||||
{
|
||||
m_reflectedVar.reset(new CReflectedVarResource(pVariable->GetHumanName().toUtf8().data()));
|
||||
|
||||
@@ -186,21 +186,6 @@ AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
|
||||
|
||||
class EDITOR_CORE_API ReflectedVarColorAdapter
|
||||
: public ReflectedVarAdapter
|
||||
{
|
||||
public:
|
||||
void SetVariable(IVariable* pVariable) override;
|
||||
void SyncReflectedVarToIVar(IVariable* pVariable) override;
|
||||
void SyncIVarToReflectedVar(IVariable* pVariable) override;
|
||||
CReflectedVar* GetReflectedVar() override { return m_reflectedVar.data(); }
|
||||
private:
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
QScopedPointer<CReflectedVarColor > m_reflectedVar;
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
};
|
||||
|
||||
class EDITOR_CORE_API ReflectedVarResourceAdapter
|
||||
: public ReflectedVarAdapter
|
||||
{
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
// Qt
|
||||
#include <QColor>
|
||||
#include <CryCommon/Cry_Color.h>
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
QColor ColorLinearToGamma(ColorF col)
|
||||
{
|
||||
float r = clamp_tpl(col.r, 0.0f, 1.0f);
|
||||
float g = clamp_tpl(col.g, 0.0f, 1.0f);
|
||||
float b = clamp_tpl(col.b, 0.0f, 1.0f);
|
||||
float a = clamp_tpl(col.a, 0.0f, 1.0f);
|
||||
|
||||
r = (float)(r <= 0.0031308 ? (12.92 * r) : (1.055 * pow((double)r, 1.0 / 2.4) - 0.055));
|
||||
g = (float)(g <= 0.0031308 ? (12.92 * g) : (1.055 * pow((double)g, 1.0 / 2.4) - 0.055));
|
||||
b = (float)(b <= 0.0031308 ? (12.92 * b) : (1.055 * pow((double)b, 1.0 / 2.4) - 0.055));
|
||||
|
||||
return QColor(int(r * 255.0f), int(g * 255.0f), int(b * 255.0f), int(a * 255.0f));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ColorF ColorGammaToLinear(const QColor& col)
|
||||
{
|
||||
float r = (float)col.red() / 255.0f;
|
||||
float g = (float)col.green() / 255.0f;
|
||||
float b = (float)col.blue() / 255.0f;
|
||||
float a = (float)col.alpha() / 255.0f;
|
||||
|
||||
return ColorF((float)(r <= 0.04045 ? (r / 12.92) : pow(((double)r + 0.055) / 1.055, 2.4)),
|
||||
(float)(g <= 0.04045 ? (g / 12.92) : pow(((double)g + 0.055) / 1.055, 2.4)),
|
||||
(float)(b <= 0.04045 ? (b / 12.92) : pow(((double)b + 0.055) / 1.055, 2.4)), a);
|
||||
}
|
||||
|
||||
QColor ColorToQColor(uint32 color)
|
||||
{
|
||||
return QColor::fromRgbF((float)GetRValue(color) / 255.0f,
|
||||
(float)GetGValue(color) / 255.0f,
|
||||
(float)GetBValue(color) / 255.0f);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/Math/Color.h>
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
@@ -184,9 +185,9 @@ QColor ColorLinearToGamma(ColorF col)
|
||||
float b = clamp_tpl(col.b, 0.0f, 1.0f);
|
||||
float a = clamp_tpl(col.a, 0.0f, 1.0f);
|
||||
|
||||
r = (float)(r <= 0.0031308 ? (12.92 * r) : (1.055 * pow((double)r, 1.0 / 2.4) - 0.055));
|
||||
g = (float)(g <= 0.0031308 ? (12.92 * g) : (1.055 * pow((double)g, 1.0 / 2.4) - 0.055));
|
||||
b = (float)(b <= 0.0031308 ? (12.92 * b) : (1.055 * pow((double)b, 1.0 / 2.4) - 0.055));
|
||||
r = AZ::Color::ConvertSrgbLinearToGamma(r);
|
||||
g = AZ::Color::ConvertSrgbLinearToGamma(g);
|
||||
b = AZ::Color::ConvertSrgbLinearToGamma(b);
|
||||
|
||||
return QColor(int(r * 255.0f), int(g * 255.0f), int(b * 255.0f), int(a * 255.0f));
|
||||
}
|
||||
@@ -199,9 +200,9 @@ ColorF ColorGammaToLinear(const QColor& col)
|
||||
float b = (float)col.blue() / 255.0f;
|
||||
float a = (float)col.alpha() / 255.0f;
|
||||
|
||||
return ColorF((float)(r <= 0.04045 ? (r / 12.92) : pow(((double)r + 0.055) / 1.055, 2.4)),
|
||||
(float)(g <= 0.04045 ? (g / 12.92) : pow(((double)g + 0.055) / 1.055, 2.4)),
|
||||
(float)(b <= 0.04045 ? (b / 12.92) : pow(((double)b + 0.055) / 1.055, 2.4)), a);
|
||||
return ColorF(AZ::Color::ConvertSrgbGammaToLinear(r),
|
||||
AZ::Color::ConvertSrgbGammaToLinear(g),
|
||||
AZ::Color::ConvertSrgbGammaToLinear(b), a);
|
||||
}
|
||||
|
||||
QColor ColorToQColor(uint32 color)
|
||||
|
||||
@@ -48,7 +48,6 @@ set(FILES
|
||||
Util/Image.cpp
|
||||
Util/ImageHistogram.h
|
||||
Util/Image.h
|
||||
Util/ColorUtils.cpp
|
||||
Undo/Undo.cpp
|
||||
Undo/IUndoManagerListener.h
|
||||
Undo/IUndoObject.h
|
||||
|
||||
@@ -134,6 +134,12 @@ namespace AZ
|
||||
//! Color from u32 => 0xAABBGGRR, RGB convert from Gamma corrected to Linear values.
|
||||
void FromU32GammaToLinear(u32 c);
|
||||
|
||||
//! Convert SRGB gamma space to linear space
|
||||
static float ConvertSrgbGammaToLinear(float x);
|
||||
|
||||
//! Convert SRGB linear space to gamma space
|
||||
static float ConvertSrgbLinearToGamma(float x);
|
||||
|
||||
//! Convert color from linear to gamma corrected space.
|
||||
Color LinearToGamma() const;
|
||||
|
||||
|
||||
@@ -370,6 +370,15 @@ namespace AZ
|
||||
*this = GammaToLinear();
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE float Color::ConvertSrgbGammaToLinear(float x)
|
||||
{
|
||||
return x <= 0.04045 ? (x / 12.92f) : static_cast<float>(pow((static_cast<double>(x) + 0.055) / 1.055, 2.4));
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE float Color::ConvertSrgbLinearToGamma(float x)
|
||||
{
|
||||
return x <= 0.0031308 ? 12.92f * x : static_cast<float>(1.055 * pow(static_cast<double>(x), 1.0 / 2.4) - 0.055);
|
||||
}
|
||||
|
||||
AZ_MATH_INLINE Color Color::LinearToGamma() const
|
||||
{
|
||||
@@ -377,9 +386,9 @@ namespace AZ
|
||||
float g = GetG();
|
||||
float b = GetB();
|
||||
|
||||
r = (r <= 0.0031308 ? 12.92f * r : static_cast<float>(1.055 * pow(static_cast<double>(r), 1.0 / 2.4) - 0.055));
|
||||
g = (g <= 0.0031308 ? 12.92f * g : static_cast<float>(1.055 * pow(static_cast<double>(g), 1.0 / 2.4) - 0.055));
|
||||
b = (b <= 0.0031308 ? 12.92f * b : static_cast<float>(1.055 * pow(static_cast<double>(b), 1.0 / 2.4) - 0.055));
|
||||
r = ConvertSrgbLinearToGamma(r);
|
||||
g = ConvertSrgbLinearToGamma(g);
|
||||
b = ConvertSrgbLinearToGamma(b);
|
||||
|
||||
return Color(r,g,b,GetA());
|
||||
}
|
||||
@@ -391,9 +400,9 @@ namespace AZ
|
||||
float g = GetG();
|
||||
float b = GetB();
|
||||
|
||||
return Color(r <= 0.04045 ? (r / 12.92f) : static_cast<float>(pow((static_cast<double>(r) + 0.055) / 1.055, 2.4)),
|
||||
g <= 0.04045 ? (g / 12.92f) : static_cast<float>(pow((static_cast<double>(g) + 0.055) / 1.055, 2.4)),
|
||||
b <= 0.04045 ? (b / 12.92f) : static_cast<float>(pow((static_cast<double>(b) + 0.055) / 1.055, 2.4)), GetA());
|
||||
return Color(ConvertSrgbGammaToLinear(r),
|
||||
ConvertSrgbGammaToLinear(g),
|
||||
ConvertSrgbGammaToLinear(b), GetA());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <AzCore/Serialization/Json/UnorderedSetSerializer.h>
|
||||
#include <AzCore/Serialization/Json/UnsupportedTypesSerializer.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Settings/ConfigurableStack.h>
|
||||
#include <AzCore/std/any.h>
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
@@ -50,6 +51,8 @@ namespace AZ
|
||||
|
||||
void JsonSystemComponent::Reflect(ReflectContext* reflectContext)
|
||||
{
|
||||
JsonConfigurableStackSerializer::Reflect(reflectContext);
|
||||
|
||||
if (JsonRegistrationContext* jsonContext = azrtti_cast<JsonRegistrationContext*>(reflectContext))
|
||||
{
|
||||
jsonContext->Serializer<JsonBoolSerializer>()->HandlesType<bool>();
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/RTTI/ReflectContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
#include <AzCore/std/containers/unordered_map.h>
|
||||
#include <AzCore/Math/Uuid.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -22,6 +23,7 @@ namespace AZ
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonRegistrationContext, "{5A763774-CA8B-4245-A897-A03C503DCD60}", ReflectContext);
|
||||
AZ_CLASS_ALLOCATOR(JsonRegistrationContext, SystemAllocator, 0);
|
||||
|
||||
class SerializerBuilder;
|
||||
using SerializerMap = AZStd::unordered_map<Uuid, AZStd::unique_ptr<BaseJsonSerializer>, AZStd::hash<Uuid>>;
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Settings/ConfigurableStack.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/std/containers/queue.h>
|
||||
#include <AzCore/std/tuple.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(JsonConfigurableStackSerializer, AZ::SystemAllocator, 0);
|
||||
|
||||
JsonSerializationResult::Result JsonConfigurableStackSerializer::Load(
|
||||
void* outputValue,
|
||||
[[maybe_unused]] const Uuid& outputValueTypeId,
|
||||
const rapidjson::Value& inputValue,
|
||||
JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
switch (inputValue.GetType())
|
||||
{
|
||||
case rapidjson::kArrayType:
|
||||
return LoadFromArray(outputValue, inputValue, context);
|
||||
case rapidjson::kObjectType:
|
||||
return LoadFromObject(outputValue, inputValue, context);
|
||||
|
||||
case rapidjson::kNullType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kFalseType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kTrueType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kStringType:
|
||||
[[fallthrough]];
|
||||
case rapidjson::kNumberType:
|
||||
return context.Report(
|
||||
JSR::Tasks::ReadField, JSR::Outcomes::Unsupported,
|
||||
"Unsupported type. Configurable stack values can only be read from arrays or objects.");
|
||||
default:
|
||||
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unknown, "Unknown json type encountered for string value.");
|
||||
}
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonConfigurableStackSerializer::Store(
|
||||
[[maybe_unused]] rapidjson::Value& outputValue,
|
||||
[[maybe_unused]] const void* inputValue,
|
||||
[[maybe_unused]] const void* defaultValue,
|
||||
[[maybe_unused]] const Uuid& valueTypeId,
|
||||
JsonSerializerContext& context)
|
||||
{
|
||||
return context.Report(
|
||||
JsonSerializationResult::Tasks::WriteValue, JsonSerializationResult::Outcomes::Unsupported,
|
||||
"Configuration stacks can not be written out.");
|
||||
}
|
||||
|
||||
void JsonConfigurableStackSerializer::Reflect(ReflectContext* context)
|
||||
{
|
||||
if (JsonRegistrationContext* jsonContext = azrtti_cast<JsonRegistrationContext*>(context))
|
||||
{
|
||||
jsonContext->Serializer<JsonConfigurableStackSerializer>()->HandlesType<ConfigurableStack>();
|
||||
}
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonConfigurableStackSerializer::LoadFromArray(
|
||||
void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
auto stack = reinterpret_cast<ConfigurableStackInterface*>(outputValue);
|
||||
const Uuid& nodeValueType = stack->GetNodeType();
|
||||
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
uint32_t counter = 0;
|
||||
for (auto& it : inputValue.GetArray())
|
||||
{
|
||||
ScopedContextPath subPath(context, counter);
|
||||
void* value = stack->AddNode(AZStd::to_string(counter));
|
||||
result.Combine(ContinueLoading(value, nodeValueType, it, context));
|
||||
counter++;
|
||||
}
|
||||
|
||||
return context.Report(
|
||||
result,
|
||||
result.GetProcessing() != JSR::Processing::Halted ? "Loaded configurable stack from array."
|
||||
: "Failed to load configurable stack from array.");
|
||||
}
|
||||
|
||||
JsonSerializationResult::Result JsonConfigurableStackSerializer::LoadFromObject(
|
||||
void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context)
|
||||
{
|
||||
namespace JSR = JsonSerializationResult; // Used remove name conflicts in AzCore in uber builds.
|
||||
|
||||
auto stack = reinterpret_cast<ConfigurableStackInterface*>(outputValue);
|
||||
const Uuid& nodeValueType = stack->GetNodeType();
|
||||
|
||||
AZStd::queue<AZStd::tuple<ConfigurableStackInterface::InsertPosition, AZStd::string_view, rapidjson::Value::ConstMemberIterator>>
|
||||
delayedEntries;
|
||||
JSR::ResultCode result(JSR::Tasks::ReadField);
|
||||
|
||||
auto add = [&](ConfigurableStackInterface::InsertPosition position, rapidjson::Value::ConstMemberIterator target,
|
||||
rapidjson::Value::ConstMemberIterator it)
|
||||
{
|
||||
if (target->value.IsString())
|
||||
{
|
||||
delayedEntries.emplace(position, AZStd::string_view(target->value.GetString(), target->value.GetStringLength()), it);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Combine(context.Report(
|
||||
JSR::Tasks::ReadField, JSR::Outcomes::Skipped,
|
||||
"Skipped value for the Configurable Stack because the target wasn't a string."));
|
||||
}
|
||||
};
|
||||
|
||||
// Load all the regular entries into the stack and store any with a before or after binding for
|
||||
// later inserting.
|
||||
for (auto it = inputValue.MemberBegin(); it != inputValue.MemberEnd(); ++it)
|
||||
{
|
||||
AZStd::string_view name(it->name.GetString(), it->name.GetStringLength());
|
||||
ScopedContextPath subPath(context, name);
|
||||
if (it->value.IsObject())
|
||||
{
|
||||
if (auto target = it->value.FindMember(StackBefore); target != it->value.MemberEnd())
|
||||
{
|
||||
add(ConfigurableStackInterface::InsertPosition::Before, target, it);
|
||||
continue;
|
||||
}
|
||||
if (auto target = it->value.FindMember(StackAfter); target != it->value.MemberEnd())
|
||||
{
|
||||
add(ConfigurableStackInterface::InsertPosition::After, target, it);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void* value = stack->AddNode(name);
|
||||
result.Combine(ContinueLoading(value, nodeValueType, it->value, context));
|
||||
}
|
||||
|
||||
// Insert the entries that have been delayed.
|
||||
while (!delayedEntries.empty())
|
||||
{
|
||||
auto&& [insertPosition, target, valueStore] = delayedEntries.front();
|
||||
AZStd::string_view name(valueStore->name.GetString(), valueStore->name.GetStringLength());
|
||||
ScopedContextPath subPath(context, name);
|
||||
void* value = stack->AddNode(name, target, insertPosition);
|
||||
if (value != nullptr)
|
||||
{
|
||||
result.Combine(ContinueLoading(value, nodeValueType, valueStore->value, context));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Combine(context.Report(
|
||||
JSR::Tasks::ReadField, JSR::Outcomes::Skipped,
|
||||
AZStd::string::format(
|
||||
"Skipped value for the Configurable Stack because the target '%.*s' couldn't be found.", AZ_STRING_ARG(name))));
|
||||
}
|
||||
delayedEntries.pop();
|
||||
}
|
||||
|
||||
return context.Report(
|
||||
result,
|
||||
result.GetProcessing() != JSR::Processing::Halted ? "Loaded configurable stack from array."
|
||||
: "Failed to load configurable stack from array.");
|
||||
}
|
||||
} // namespace AZ
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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/base.h>
|
||||
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#include <AzCore/std/smart_ptr/shared_ptr.h>
|
||||
#include <AzCore/std/string/string.h>
|
||||
#include <AzCore/std/utils.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
//! The ConfigurableStack makes configuring stacks and arrays through the Settings Registry easier than using direct serialization
|
||||
//! to a container like AZStd::vector. It does this by using JSON Objects rather than JSON arrays, although arrays are supported
|
||||
//! for backwards compatibility. Two key words were added:
|
||||
//! - $stack_before : Insert the new entry before the referenced entry. Referencing is done by name.
|
||||
//! - $stack_after : Insert the new entry after the referenced entry. Referencing is done by name.
|
||||
//! to allow inserting new entries at specific locations. An example of a .setreg file at updates existing settings would be:
|
||||
//! // Original settings
|
||||
//! {
|
||||
//! "Settings in a stack":
|
||||
//! {
|
||||
//! "AnOriginalEntry":
|
||||
//! {
|
||||
//! "MyValue": "hello",
|
||||
//! "ExampleValue": 84
|
||||
//! },
|
||||
//! "TheSecondEntry":
|
||||
//! {
|
||||
//! "MyValue": "world"
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! // Customized settings.
|
||||
//! {
|
||||
//! "Settings in a stack":
|
||||
//! {
|
||||
//! // Add a new entry before "AnOriginalEntry" in the original document.
|
||||
//! "NewEntry":
|
||||
//! {
|
||||
//! "$stack_before": "AnOriginalEntry",
|
||||
//! "MyValue": 42
|
||||
//! },
|
||||
//! // Add a second entry after "AnOriginalEntry" in the original document.
|
||||
//! "SecondNewEntry":
|
||||
//! {
|
||||
//! "$stack_after": "AnOriginalEntry",
|
||||
//! "MyValue": "FortyTwo".
|
||||
//! },
|
||||
//! // Update a value in "AnOriginalEntry".
|
||||
//! "AnOriginalEntry":
|
||||
//! {
|
||||
//! "ExampleValue": 42
|
||||
//! },
|
||||
//! // Delete the "TheSecondEntry" from the settings.
|
||||
//! "TheSecondEntry" : null,
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! The ConfigurableStack uses an AZStd::shared_ptr to store the values. This supports settings up a base class and specifying
|
||||
//! derived classes in the settings, but requires that the base and derived classes all have a memory allocator associated with
|
||||
//! them (i.e. by using the "AZ_CLASS_ALLOCATOR" macro) and that the relation of the classes is reflected. Loading a
|
||||
//! ConfigurableStack can be done using the GetObject call on the SettingsRegistryInterface.
|
||||
|
||||
class ReflectContext;
|
||||
|
||||
class ConfigurableStackInterface
|
||||
{
|
||||
public:
|
||||
friend class JsonConfigurableStackSerializer;
|
||||
|
||||
virtual ~ConfigurableStackInterface() = default;
|
||||
|
||||
virtual const TypeId& GetNodeType() const = 0;
|
||||
|
||||
protected:
|
||||
enum class InsertPosition
|
||||
{
|
||||
Before,
|
||||
After
|
||||
};
|
||||
virtual void* AddNode(AZStd::string name) = 0;
|
||||
virtual void* AddNode(AZStd::string name, AZStd::string_view target, InsertPosition position) = 0;
|
||||
};
|
||||
|
||||
template<typename StackBaseType>
|
||||
class ConfigurableStack final : public ConfigurableStackInterface
|
||||
{
|
||||
public:
|
||||
using NodeValue = AZStd::shared_ptr<StackBaseType>;
|
||||
using Node = AZStd::pair<AZStd::string, NodeValue>;
|
||||
using NodeContainer = AZStd::vector<Node>;
|
||||
using Iterator = typename NodeContainer::iterator;
|
||||
using ConstIterator = typename NodeContainer::const_iterator;
|
||||
|
||||
~ConfigurableStack() override = default;
|
||||
|
||||
const TypeId& GetNodeType() const override;
|
||||
|
||||
Iterator begin();
|
||||
Iterator end();
|
||||
ConstIterator begin() const;
|
||||
ConstIterator end() const;
|
||||
|
||||
size_t size() const;
|
||||
|
||||
protected:
|
||||
void* AddNode(AZStd::string name) override;
|
||||
void* AddNode(AZStd::string name, AZStd::string_view target, InsertPosition position) override;
|
||||
|
||||
private:
|
||||
NodeContainer m_nodes;
|
||||
};
|
||||
|
||||
AZ_TYPE_INFO_TEMPLATE(ConfigurableStack, "{0A3D2038-6E6A-4EFD-A1B4-F30D947E21B1}", AZ_TYPE_INFO_TYPENAME);
|
||||
|
||||
template<typename StackBaseType>
|
||||
struct SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>
|
||||
{
|
||||
using ConfigurableStackType = ConfigurableStack<StackBaseType>;
|
||||
|
||||
class GenericConfigurableStackInfo : public GenericClassInfo
|
||||
{
|
||||
public:
|
||||
AZ_TYPE_INFO(GenericConfigurableStackInfo, "{FC5A9353-D0DE-48F6-81B5-1CB2985C5F65}");
|
||||
|
||||
GenericConfigurableStackInfo();
|
||||
|
||||
SerializeContext::ClassData* GetClassData() override;
|
||||
size_t GetNumTemplatedArguments() override;
|
||||
const Uuid& GetTemplatedTypeId([[maybe_unused]] size_t element) override;
|
||||
const Uuid& GetSpecializedTypeId() const override;
|
||||
const Uuid& GetGenericTypeId() const override;
|
||||
|
||||
void Reflect(SerializeContext* serializeContext) override;
|
||||
|
||||
SerializeContext::ClassData m_classData;
|
||||
};
|
||||
|
||||
using ClassInfoType = GenericConfigurableStackInfo;
|
||||
|
||||
static ClassInfoType* GetGenericInfo();
|
||||
static const Uuid& GetClassTypeId();
|
||||
};
|
||||
|
||||
class JsonConfigurableStackSerializer : public BaseJsonSerializer
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(JsonConfigurableStackSerializer, "{45A31805-9058-41A9-B1A3-71E2CB4D9237}", BaseJsonSerializer);
|
||||
AZ_CLASS_ALLOCATOR_DECL;
|
||||
|
||||
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;
|
||||
|
||||
static void Reflect(ReflectContext* context);
|
||||
|
||||
private:
|
||||
JsonSerializationResult::Result LoadFromArray(
|
||||
void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context);
|
||||
JsonSerializationResult::Result LoadFromObject(
|
||||
void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context);
|
||||
|
||||
static constexpr const char* StackBefore = "$stack_before";
|
||||
static constexpr const char* StackAfter = "$stack_after";
|
||||
};
|
||||
} // namespace AZ
|
||||
|
||||
#include <AzCore/Settings/ConfigurableStack.inl>
|
||||
@@ -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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
//
|
||||
// ConfigurableStack
|
||||
//
|
||||
|
||||
template<typename StackBaseType>
|
||||
const TypeId& ConfigurableStack<StackBaseType>::GetNodeType() const
|
||||
{
|
||||
return azrtti_typeid<NodeValue>();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
auto ConfigurableStack<StackBaseType>::begin() -> Iterator
|
||||
{
|
||||
return m_nodes.begin();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
auto ConfigurableStack<StackBaseType>::end() -> Iterator
|
||||
{
|
||||
return m_nodes.end();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
auto ConfigurableStack<StackBaseType>::begin() const -> ConstIterator
|
||||
{
|
||||
return m_nodes.begin();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
auto ConfigurableStack<StackBaseType>::end() const -> ConstIterator
|
||||
{
|
||||
return m_nodes.end();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
size_t ConfigurableStack<StackBaseType>::size() const
|
||||
{
|
||||
return m_nodes.size();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
void* ConfigurableStack<StackBaseType>::AddNode(AZStd::string name)
|
||||
{
|
||||
Node& result = m_nodes.emplace_back(AZStd::move(name));
|
||||
return &result.second;
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
void* ConfigurableStack<StackBaseType>::AddNode(AZStd::string name, AZStd::string_view target, InsertPosition position)
|
||||
{
|
||||
auto end = m_nodes.end();
|
||||
for (auto it = m_nodes.begin(); it != end; ++it)
|
||||
{
|
||||
if (it->first == target)
|
||||
{
|
||||
if (position == InsertPosition::After)
|
||||
{
|
||||
++it;
|
||||
}
|
||||
auto result = m_nodes.insert(it, Node(AZStd::move(name), {}));
|
||||
return &result->second;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// SerializeGenericTypeInfo
|
||||
//
|
||||
|
||||
|
||||
template<typename StackBaseType>
|
||||
SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::GenericConfigurableStackInfo()
|
||||
: m_classData{ SerializeContext::ClassData::Create<ConfigurableStackType>(
|
||||
"AZ::ConfigurableStack", GetSpecializedTypeId(), Internal::NullFactory::GetInstance(), nullptr, nullptr) }
|
||||
{
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
SerializeContext::ClassData* SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::GetClassData()
|
||||
{
|
||||
return &m_classData;
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
size_t SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::GetNumTemplatedArguments()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
const Uuid& SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::GetTemplatedTypeId(
|
||||
[[maybe_unused]] size_t element)
|
||||
{
|
||||
return SerializeGenericTypeInfo<StackBaseType>::GetClassTypeId();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
const Uuid& SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::GetSpecializedTypeId() const
|
||||
{
|
||||
return azrtti_typeid<ConfigurableStackType>();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
const Uuid& SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::GetGenericTypeId() const
|
||||
{
|
||||
return TYPEINFO_Uuid();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
void SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GenericConfigurableStackInfo::Reflect(SerializeContext* serializeContext)
|
||||
{
|
||||
if (serializeContext)
|
||||
{
|
||||
serializeContext->RegisterGenericClassInfo(GetSpecializedTypeId(), this, &AnyTypeInfoConcept<ConfigurableStackType>::CreateAny);
|
||||
if (serializeContext->FindClassData(azrtti_typeid<AZStd::shared_ptr<StackBaseType>>()) == nullptr)
|
||||
{
|
||||
serializeContext->RegisterGenericType<AZStd::shared_ptr<StackBaseType>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
auto SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GetGenericInfo() -> ClassInfoType*
|
||||
{
|
||||
return GetCurrentSerializeContextModule().CreateGenericClassInfo<ConfigurableStackType>();
|
||||
}
|
||||
|
||||
template<typename StackBaseType>
|
||||
const Uuid& SerializeGenericTypeInfo<ConfigurableStack<StackBaseType>>::GetClassTypeId()
|
||||
{
|
||||
return GetGenericInfo()->GetClassData()->m_typeId;
|
||||
}
|
||||
} // namespace AZ
|
||||
|
||||
@@ -560,6 +560,9 @@ set(FILES
|
||||
Serialization/std/VariantReflection.inl
|
||||
Settings/CommandLine.cpp
|
||||
Settings/CommandLine.h
|
||||
Settings/ConfigurableStack.cpp
|
||||
Settings/ConfigurableStack.inl
|
||||
Settings/ConfigurableStack.h
|
||||
Settings/SettingsRegistry.cpp
|
||||
Settings/SettingsRegistry.h
|
||||
Settings/SettingsRegistryConsoleUtils.cpp
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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/JSON/document.h>
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
#include <AzCore/Settings/ConfigurableStack.h>
|
||||
#include <AzCore/Serialization/Json/JsonSerialization.h>
|
||||
#include <AzCore/Serialization/Json/RegistrationContext.h>
|
||||
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
struct ConfigInt
|
||||
{
|
||||
AZ_TYPE_INFO(UnitTest::ConfigInt, "{1FAF6E55-7FA4-4FFA-8C41-34F422B8E8AB}");
|
||||
AZ_CLASS_ALLOCATOR(ConfigInt, AZ::SystemAllocator, 0);
|
||||
|
||||
int m_value;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto sc = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
sc->Class<ConfigInt>()->Field("Value", &ConfigInt::m_value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ConfigurableStackTests : public ScopedAllocatorSetupFixture
|
||||
{
|
||||
void Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto sc = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
AZ::JsonSystemComponent::Reflect(sc);
|
||||
ConfigInt::Reflect(sc);
|
||||
sc->RegisterGenericType<AZ::ConfigurableStack<ConfigInt>>();
|
||||
}
|
||||
else if (auto jrc = azrtti_cast<AZ::JsonRegistrationContext*>(context))
|
||||
{
|
||||
AZ::JsonSystemComponent::Reflect(jrc);
|
||||
}
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
ScopedAllocatorSetupFixture::SetUp();
|
||||
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
m_jsonRegistrationContext = AZStd::make_unique<AZ::JsonRegistrationContext>();
|
||||
|
||||
Reflect(m_serializeContext.get());
|
||||
Reflect(m_jsonRegistrationContext.get());
|
||||
|
||||
m_deserializationSettings.m_registrationContext = m_jsonRegistrationContext.get();
|
||||
m_deserializationSettings.m_serializeContext = m_serializeContext.get();
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
m_jsonRegistrationContext->EnableRemoveReflection();
|
||||
Reflect(m_jsonRegistrationContext.get());
|
||||
m_jsonRegistrationContext->DisableRemoveReflection();
|
||||
|
||||
m_serializeContext->EnableRemoveReflection();
|
||||
Reflect(m_serializeContext.get());
|
||||
m_serializeContext->DisableRemoveReflection();
|
||||
|
||||
ScopedAllocatorSetupFixture::TearDown();
|
||||
}
|
||||
|
||||
void ObjectTest(AZStd::string_view jsonText)
|
||||
{
|
||||
AZ::ConfigurableStack<ConfigInt> stack;
|
||||
|
||||
rapidjson::Document document;
|
||||
document.Parse(jsonText.data(), jsonText.length());
|
||||
ASSERT_FALSE(document.HasParseError());
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(stack, document, m_deserializationSettings);
|
||||
ASSERT_EQ(AZ::JsonSerializationResult::Processing::Completed, result.GetProcessing());
|
||||
ASSERT_EQ(4, stack.size());
|
||||
|
||||
int numberCounter = 0;
|
||||
int valueCounter = 42;
|
||||
for (auto& [name, value] : stack)
|
||||
{
|
||||
EXPECT_STREQ(AZStd::string::format("Value%i", numberCounter).c_str(), name.c_str());
|
||||
EXPECT_EQ(valueCounter, value->m_value);
|
||||
numberCounter++;
|
||||
valueCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
AZStd::unique_ptr<AZ::JsonRegistrationContext> m_jsonRegistrationContext;
|
||||
AZ::JsonDeserializerSettings m_deserializationSettings;
|
||||
};
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeArray)
|
||||
{
|
||||
AZ::ConfigurableStack<ConfigInt> stack;
|
||||
|
||||
rapidjson::Document document;
|
||||
document.Parse(
|
||||
R"([
|
||||
{ "Value": 42 },
|
||||
{ "Value": 43 },
|
||||
{ "Value": 44 },
|
||||
{ "Value": 45 }
|
||||
])");
|
||||
ASSERT_FALSE(document.HasParseError());
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(stack, document, m_deserializationSettings);
|
||||
ASSERT_EQ(AZ::JsonSerializationResult::Processing::Completed, result.GetProcessing());
|
||||
ASSERT_EQ(4, stack.size());
|
||||
|
||||
int numberCounter = 0;
|
||||
int valueCounter = 42;
|
||||
for (auto& [name, value] : stack)
|
||||
{
|
||||
EXPECT_STREQ(AZStd::to_string(numberCounter).c_str(), name.c_str());
|
||||
EXPECT_EQ(valueCounter, value->m_value);
|
||||
numberCounter++;
|
||||
valueCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObject)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value0": { "Value": 42 },
|
||||
"Value1": { "Value": 43 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 }
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithLateBefore)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value0": { "Value": 42 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 },
|
||||
"Value1":
|
||||
{
|
||||
"$stack_before": "Value2",
|
||||
"Value": 43
|
||||
}
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithEarlyBefore)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value1":
|
||||
{
|
||||
"$stack_before": "Value2",
|
||||
"Value": 43
|
||||
},
|
||||
"Value0": { "Value": 42 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 }
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithLateAfter)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value0": { "Value": 42 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 },
|
||||
"Value1":
|
||||
{
|
||||
"$stack_after": "Value0",
|
||||
"Value": 43
|
||||
}
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithEarlyAfter)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value1":
|
||||
{
|
||||
"$stack_after": "Value0",
|
||||
"Value": 43
|
||||
},
|
||||
"Value0": { "Value": 42 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 }
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithBeforeFirst)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value1": { "Value": 43 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 },
|
||||
"Value0":
|
||||
{
|
||||
"$stack_before": "Value1",
|
||||
"Value": 42
|
||||
}
|
||||
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithInsertAfterLast)
|
||||
{
|
||||
ObjectTest(
|
||||
R"({
|
||||
"Value3":
|
||||
{
|
||||
"$stack_after": "Value2",
|
||||
"Value": 45
|
||||
},
|
||||
"Value0": { "Value": 42 },
|
||||
"Value1": { "Value": 43 },
|
||||
"Value2": { "Value": 44 }
|
||||
})");
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithInvalidTarget)
|
||||
{
|
||||
AZ::ConfigurableStack<ConfigInt> stack;
|
||||
|
||||
rapidjson::Document document;
|
||||
document.Parse(
|
||||
R"({
|
||||
"Value1":
|
||||
{
|
||||
"$stack_after": "airplane",
|
||||
"Value": 43
|
||||
},
|
||||
"Value0": { "Value": 42 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 }
|
||||
})");
|
||||
ASSERT_FALSE(document.HasParseError());
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(stack, document, m_deserializationSettings);
|
||||
EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, result.GetProcessing());
|
||||
EXPECT_EQ(AZ::JsonSerializationResult::Outcomes::PartialSkip, result.GetOutcome());
|
||||
EXPECT_EQ(3, stack.size());
|
||||
}
|
||||
|
||||
TEST_F(ConfigurableStackTests, DeserializeObjectWithInvalidTargetType)
|
||||
{
|
||||
AZ::ConfigurableStack<ConfigInt> stack;
|
||||
|
||||
rapidjson::Document document;
|
||||
document.Parse(
|
||||
R"({
|
||||
"Value1":
|
||||
{
|
||||
"$stack_after": 42,
|
||||
"Value": 43
|
||||
},
|
||||
"Value0": { "Value": 42 },
|
||||
"Value2": { "Value": 44 },
|
||||
"Value3": { "Value": 45 }
|
||||
})");
|
||||
ASSERT_FALSE(document.HasParseError());
|
||||
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(stack, document, m_deserializationSettings);
|
||||
EXPECT_EQ(AZ::JsonSerializationResult::Processing::Completed, result.GetProcessing());
|
||||
EXPECT_EQ(AZ::JsonSerializationResult::Outcomes::PartialSkip, result.GetOutcome());
|
||||
EXPECT_EQ(3, stack.size());
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -76,6 +76,7 @@ set(FILES
|
||||
Name/NameTests.cpp
|
||||
RTTI/TypeSafeIntegralTests.cpp
|
||||
Settings/CommandLineTests.cpp
|
||||
Settings/ConfigurableStackTests.cpp
|
||||
Settings/SettingsRegistryTests.cpp
|
||||
Settings/SettingsRegistryConsoleUtilsTests.cpp
|
||||
Settings/SettingsRegistryMergeUtilsTests.cpp
|
||||
|
||||
@@ -140,28 +140,28 @@ namespace AzFramework
|
||||
|
||||
//! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each
|
||||
//! XY coordinate in the list.
|
||||
virtual void ProcessHeightsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessHeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessNormalsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessNormalsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessSurfacePointsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessSurfacePointsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
|
||||
@@ -272,42 +272,42 @@ namespace AzFramework
|
||||
//! Asynchronous versions of the various 'Process*' API functions declared above.
|
||||
//! It's the responsibility of the caller to ensure all callbacks are threadsafe.
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
virtual AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const = 0;
|
||||
|
||||
@@ -77,21 +77,21 @@ namespace UnitTest
|
||||
MOCK_CONST_METHOD5(
|
||||
GetSurfacePointFromFloats, void(float, float, AzFramework::SurfaceData::SurfacePoint&, Sampler, bool*));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessHeightsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessHeightsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessNormalsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessNormalsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessSurfaceWeightsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessSurfaceWeightsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessSurfacePointsFromList, void(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessSurfacePointsFromList, void(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessHeightsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessHeightsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessNormalsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessNormalsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessSurfaceWeightsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessSurfaceWeightsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD3(
|
||||
ProcessSurfacePointsFromListOfVector2, void(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
ProcessSurfacePointsFromListOfVector2, void(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD2(
|
||||
GetNumSamplesFromRegion, AZStd::pair<size_t, size_t>(const AZ::Aabb&, const AZ::Vector2&));
|
||||
MOCK_CONST_METHOD4(
|
||||
@@ -107,21 +107,21 @@ namespace UnitTest
|
||||
MOCK_CONST_METHOD1(
|
||||
GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessHeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessHeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessNormalsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessNormalsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessSurfaceWeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessSurfaceWeightsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessSurfacePointsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessSurfacePointsFromListAsync, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector3>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessHeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessHeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessNormalsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessNormalsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessSurfaceWeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessSurfaceWeightsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessSurfacePointsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
ProcessSurfacePointsFromListOfVector2Async, AZStd::shared_ptr<TerrainJobContext>(const AZStd::span<const AZ::Vector2>&, AzFramework::Terrain::SurfacePointListFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD5(
|
||||
ProcessHeightsFromRegionAsync, AZStd::shared_ptr<TerrainJobContext>(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler, AZStd::shared_ptr<ProcessAsyncParams>));
|
||||
MOCK_CONST_METHOD5(
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <Processing/PixelFormatInfo.h>
|
||||
#include <Processing/ImageFlags.h>
|
||||
#include <Atom/ImageProcessing/PixelFormats.h>
|
||||
#include <AzCore/Math/Color.h>
|
||||
|
||||
#include <Converters/FIR-Weights.h>
|
||||
#include <Converters/PixelOperation.h>
|
||||
@@ -118,19 +119,8 @@ namespace ImageProcessingAtom
|
||||
float m_fMaxDiff = 0.0f;
|
||||
};
|
||||
|
||||
|
||||
static float GammaToLinear(float x)
|
||||
{
|
||||
return (x <= 0.04045f) ? x / 12.92f : powf((x + 0.055f) / 1.055f, 2.4f);
|
||||
}
|
||||
|
||||
static float LinearToGamma(float x)
|
||||
{
|
||||
return (x <= 0.0031308f) ? x * 12.92f : 1.055f * powf(x, 1.0f / 2.4f) - 0.055f;
|
||||
}
|
||||
|
||||
static FunctionLookupTable<1024> s_lutGammaToLinear(GammaToLinear, 0.04045f, 0.00001f);
|
||||
static FunctionLookupTable<1024> s_lutLinearToGamma(LinearToGamma, 0.05f, 0.00001f);
|
||||
static FunctionLookupTable<1024> s_lutGammaToLinear(AZ::Color::ConvertSrgbGammaToLinear, 0.04045f, 0.00001f);
|
||||
static FunctionLookupTable<1024> s_lutLinearToGamma(AZ::Color::ConvertSrgbLinearToGamma, 0.05f, 0.00001f);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
|
||||
#include <AzCore/Math/Color.h>
|
||||
#include <AzCore/std/containers/array.h>
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
|
||||
namespace AZ
|
||||
@@ -105,6 +107,25 @@ namespace AZ
|
||||
return ((value - origMin) / (origMax - origMin)) * (scaledMax - scaledMin) + scaledMin;
|
||||
}
|
||||
|
||||
// Pre-compute a lookup table for converting SRGB gamma to linear
|
||||
// by specifying the AZ::u8 so we don't have to do the computation
|
||||
// when retrieving pixels
|
||||
using ConversionLookupTable = AZStd::array<float, 256>;
|
||||
ConversionLookupTable CreateSrgbGammaToLinearLookupTable()
|
||||
{
|
||||
ConversionLookupTable lookupTable;
|
||||
|
||||
for (size_t i = 0; i < lookupTable.array_size; ++i)
|
||||
{
|
||||
float srgbValue = i / static_cast<float>(std::numeric_limits<AZ::u8>::max());
|
||||
lookupTable[i] = AZ::Color::ConvertSrgbGammaToLinear(srgbValue);
|
||||
}
|
||||
|
||||
return lookupTable;
|
||||
}
|
||||
|
||||
static ConversionLookupTable s_SrgbGammaToLinearLookupTable = CreateSrgbGammaToLinearLookupTable();
|
||||
|
||||
float RetrieveFloatValue(const AZ::u8* mem, size_t index, AZ::RHI::Format format)
|
||||
{
|
||||
switch (format)
|
||||
@@ -113,12 +134,23 @@ namespace AZ
|
||||
case AZ::RHI::Format::A8_UNORM:
|
||||
case AZ::RHI::Format::R8G8_UNORM:
|
||||
case AZ::RHI::Format::R8G8B8A8_UNORM:
|
||||
case AZ::RHI::Format::A8B8G8R8_UNORM:
|
||||
{
|
||||
return mem[index] / static_cast<float>(std::numeric_limits<AZ::u8>::max());
|
||||
}
|
||||
case AZ::RHI::Format::R8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::R8G8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::R8G8B8A8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::A8B8G8R8_UNORM_SRGB:
|
||||
{
|
||||
// Use a lookup table that takes an AZ::u8 instead of a float
|
||||
// for better performance
|
||||
return s_SrgbGammaToLinearLookupTable[mem[index]];
|
||||
}
|
||||
case AZ::RHI::Format::R8_SNORM:
|
||||
case AZ::RHI::Format::R8G8_SNORM:
|
||||
case AZ::RHI::Format::R8G8B8A8_SNORM:
|
||||
case AZ::RHI::Format::A8B8G8R8_SNORM:
|
||||
{
|
||||
// Scale the value from AZ::s8 min/max to -1 to 1
|
||||
// We need to treat -128 and -127 the same, so that we get a symmetric
|
||||
@@ -452,9 +484,15 @@ namespace AZ
|
||||
case AZ::RHI::Format::A8_UNORM:
|
||||
case AZ::RHI::Format::R8G8_UNORM:
|
||||
case AZ::RHI::Format::R8G8B8A8_UNORM:
|
||||
case AZ::RHI::Format::A8B8G8R8_UNORM:
|
||||
case AZ::RHI::Format::R8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::R8G8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::R8G8B8A8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::A8B8G8R8_UNORM_SRGB:
|
||||
case AZ::RHI::Format::R8_SNORM:
|
||||
case AZ::RHI::Format::R8G8_SNORM:
|
||||
case AZ::RHI::Format::R8G8B8A8_SNORM:
|
||||
case AZ::RHI::Format::A8B8G8R8_SNORM:
|
||||
case AZ::RHI::Format::D16_UNORM:
|
||||
case AZ::RHI::Format::R16_UNORM:
|
||||
case AZ::RHI::Format::R16G16_UNORM:
|
||||
|
||||
+28
-26
@@ -144,44 +144,46 @@ namespace SurfaceData
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SurfaceDataMeshComponent::DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const
|
||||
void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
|
||||
}
|
||||
|
||||
void SurfaceDataMeshComponent::GetSurfacePointsFromList(
|
||||
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZ::Vector3 hitPosition;
|
||||
AZ::Vector3 hitNormal;
|
||||
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
// test AABB as first pass to claim the point
|
||||
const AZ::Vector3 testPosition = AZ::Vector3(
|
||||
inPosition.GetX(),
|
||||
inPosition.GetY(),
|
||||
(m_meshBounds.GetMax().GetZ() + m_meshBounds.GetMin().GetZ()) * 0.5f);
|
||||
|
||||
if (!m_meshBounds.Contains(testPosition))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::RPI::ModelAsset* mesh = m_meshAssetData.GetAs<AZ::RPI::ModelAsset>();
|
||||
if (!mesh)
|
||||
{
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
const AZ::Vector3 rayStart = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
|
||||
const AZ::Vector3 rayEnd = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMin().GetZ() - s_rayAABBHeightPadding);
|
||||
return GetMeshRayIntersection(
|
||||
*mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, outPosition, outNormal);
|
||||
}
|
||||
|
||||
|
||||
void SurfaceDataMeshComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZ::Vector3 hitPosition;
|
||||
AZ::Vector3 hitNormal;
|
||||
if (DoRayTrace(inPosition, hitPosition, hitNormal))
|
||||
for (auto& inPosition : inPositions)
|
||||
{
|
||||
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
|
||||
// test AABB as first pass to claim the point
|
||||
if (SurfaceData::AabbContains2D(m_meshBounds, inPosition))
|
||||
{
|
||||
const AZ::Vector3 rayStart =
|
||||
AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMax().GetZ() + s_rayAABBHeightPadding);
|
||||
const AZ::Vector3 rayEnd =
|
||||
AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_meshBounds.GetMin().GetZ() - s_rayAABBHeightPadding);
|
||||
bool rayHit = GetMeshRayIntersection(
|
||||
*mesh, m_meshWorldTM, m_meshWorldTMInverse, m_meshNonUniformScale, rayStart, rayEnd, hitPosition, hitNormal);
|
||||
|
||||
if (rayHit)
|
||||
{
|
||||
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AZ::Aabb SurfaceDataMeshComponent::GetSurfaceAabb() const
|
||||
{
|
||||
return m_meshBounds;
|
||||
|
||||
+1
-1
@@ -80,9 +80,9 @@ namespace SurfaceData
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataProviderRequestBus
|
||||
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
|
||||
void GetSurfacePointsFromList(AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const override;
|
||||
|
||||
private:
|
||||
bool DoRayTrace(const AZ::Vector3& inPosition, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const;
|
||||
void UpdateMeshData();
|
||||
void OnCompositionChanged();
|
||||
|
||||
|
||||
+14
-11
@@ -302,25 +302,28 @@ namespace EMStudio
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if motion event with this configuration exists and return color.
|
||||
AZ::u32 MotionEventPresetManager::GetEventColor(const EMotionFX::EventDataSet& eventDatas) const
|
||||
{
|
||||
for (const MotionEventPreset* preset : m_eventPresets)
|
||||
{
|
||||
EMotionFX::EventDataSet commonDatas;
|
||||
const EMotionFX::EventDataSet& presetDatas = preset->GetEventDatas();
|
||||
const bool allMatch = AZStd::all_of(presetDatas.cbegin(), presetDatas.cend(), [eventDatas](const EMotionFX::EventDataPtr& presetData)
|
||||
|
||||
const size_t numEventDatas = eventDatas.size();
|
||||
if (numEventDatas == presetDatas.size())
|
||||
{
|
||||
const auto thisPresetDataHasMatch = AZStd::find_if(eventDatas.cbegin(), eventDatas.cend(), [presetData](const EMotionFX::EventDataPtr& eventData)
|
||||
for (size_t i = 0; i < numEventDatas; ++i)
|
||||
{
|
||||
return ((presetData && eventData && *presetData == *eventData) || (!presetData && !eventData));
|
||||
});
|
||||
return thisPresetDataHasMatch != eventDatas.cend();
|
||||
});
|
||||
if (allMatch)
|
||||
{
|
||||
return preset->GetEventColor();
|
||||
const EMotionFX::EventDataPtr& eventData = eventDatas[i];
|
||||
const EMotionFX::EventDataPtr& presetData = presetDatas[i];
|
||||
|
||||
if (eventData && presetData &&
|
||||
eventData->RTTI_GetType() == presetData->RTTI_GetType() &&
|
||||
*eventData == *presetData)
|
||||
{
|
||||
return preset->GetEventColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-20
@@ -108,29 +108,9 @@ namespace GradientSignal
|
||||
void AddTag(AZStd::string tag) override;
|
||||
|
||||
private:
|
||||
static float CalculateAltitudeRatio(const SurfaceData::SurfacePointList& points, size_t inPositionIndex, float altitudeMin, float altitudeMax)
|
||||
{
|
||||
if (points.IsEmpty(inPositionIndex))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// GetSurfacePoints (which was used to populate the points list) always returns points in decreasing height order, so the
|
||||
// first point in the list contains the highest altitude.
|
||||
const float highestAltitude = points.GetHighestSurfacePoint(inPositionIndex).m_position.GetZ();
|
||||
|
||||
// Turn the absolute altitude value into a 0-1 value by returning the % of the given altitude range that it falls at.
|
||||
return GetRatio(altitudeMin, altitudeMax, highestAltitude);
|
||||
}
|
||||
|
||||
mutable AZStd::shared_mutex m_cacheMutex;
|
||||
SurfaceAltitudeGradientConfig m_configuration;
|
||||
LmbrCentral::DependencyMonitor m_dependencyMonitor;
|
||||
AZStd::atomic_bool m_dirty{ false };
|
||||
|
||||
// m_surfacePointList exists here because it will more efficiently reuse memory across GetValue() calls if it stays constructed.
|
||||
// The mutex exists to ensure that we don't try to use it from GetValue() in multiple threads at once.
|
||||
mutable AZStd::recursive_mutex m_surfacePointListMutex;
|
||||
mutable SurfaceData::SurfacePointList m_surfacePointList;
|
||||
};
|
||||
}
|
||||
|
||||
-19
@@ -82,25 +82,6 @@ namespace GradientSignal
|
||||
void AddTag(AZStd::string tag) override;
|
||||
|
||||
private:
|
||||
static float GetMaxSurfaceWeight(const SurfaceData::SurfacePointList& points)
|
||||
{
|
||||
float result = 0.0f;
|
||||
points.EnumeratePoints([&result](
|
||||
[[maybe_unused]] size_t inPositionIndex, [[maybe_unused]] const AZ::Vector3& position,
|
||||
[[maybe_unused]] const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks) -> bool
|
||||
{
|
||||
masks.EnumerateWeights(
|
||||
[&result]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool
|
||||
{
|
||||
result = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), result);
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SurfaceMaskGradientConfig m_configuration;
|
||||
LmbrCentral::DependencyMonitor m_dependencyMonitor;
|
||||
};
|
||||
|
||||
-33
@@ -124,39 +124,6 @@ namespace GradientSignal
|
||||
void SetFallOffMidpoint(float midpoint) override;
|
||||
|
||||
private:
|
||||
float GetSlopeRatio(const SurfaceData::SurfacePointList& points, float angleMin, float angleMax) const
|
||||
{
|
||||
constexpr size_t inPositionIndex = 0;
|
||||
if (points.IsEmpty(inPositionIndex))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Assuming our surface normal vector is actually normalized, we can get the slope
|
||||
// by just grabbing the Z value. It's the same thing as normal.Dot(AZ::Vector3::CreateAxisZ()).
|
||||
auto highestSurfacePoint = points.GetHighestSurfacePoint(inPositionIndex);
|
||||
AZ_Assert(
|
||||
highestSurfacePoint.m_normal.GetNormalized().IsClose(highestSurfacePoint.m_normal),
|
||||
"Surface normals are expected to be normalized");
|
||||
const float slope = highestSurfacePoint.m_normal.GetZ();
|
||||
// Convert slope back to an angle so that we can lerp in "angular space", not "slope value space".
|
||||
// (We want our 0-1 range to be linear across the range of angles)
|
||||
const float slopeAngle = acosf(slope);
|
||||
|
||||
switch (m_configuration.m_rampType)
|
||||
{
|
||||
case SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP:
|
||||
return m_configuration.m_smoothStep.GetSmoothedValue(GetRatio(angleMin, angleMax, slopeAngle));
|
||||
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_UP:
|
||||
// For ramp up, linearly interpolate from min to max.
|
||||
return GetRatio(angleMin, angleMax, slopeAngle);
|
||||
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_DOWN:
|
||||
default:
|
||||
// For ramp down, linearly interpolate from max to min.
|
||||
return GetRatio(angleMax, angleMin, slopeAngle);
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceSlopeGradientConfig m_configuration;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -202,18 +202,9 @@ namespace GradientSignal
|
||||
|
||||
float SurfaceAltitudeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
|
||||
{
|
||||
// For GetValue(), we reuse our SurfacePointList for the GetSurfacePoints query to avoid the repeated cost of memory allocation
|
||||
// and deallocation across GetValue() calls. However, this also means we can only use it from one thread at a time, so lock a
|
||||
// mutex to ensure no other threads call GetValue() at the same time.
|
||||
AZStd::unique_lock<decltype(m_surfacePointListMutex)> surfacePointLock(m_surfacePointListMutex);
|
||||
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
|
||||
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, m_surfacePointList);
|
||||
|
||||
constexpr size_t inPositionIndex = 0;
|
||||
return CalculateAltitudeRatio(m_surfacePointList, inPositionIndex, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
|
||||
float result = 0.0f;
|
||||
GetValues(AZStd::span<const AZ::Vector3>(&sampleParams.m_position, 1), AZStd::span<float>(&result, 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
void SurfaceAltitudeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
|
||||
@@ -231,17 +222,20 @@ namespace GradientSignal
|
||||
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagsToSample,
|
||||
points);
|
||||
|
||||
if (points.IsEmpty())
|
||||
// For each position, turn the height into a 0-1 value based on our min/max altitudes.
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
{
|
||||
// No surface data, so no output values.
|
||||
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For each position, turn the height into a 0-1 value based on our min/max altitudes.
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
if (!points.IsEmpty(index))
|
||||
{
|
||||
outValues[index] = CalculateAltitudeRatio(points, index, m_configuration.m_altitudeMin, m_configuration.m_altitudeMax);
|
||||
// Get the point with the highest Z value and use that for the altitude.
|
||||
const float highestAltitude = points.GetHighestSurfacePoint(index).m_position.GetZ();
|
||||
|
||||
// Turn the absolute altitude value into a 0-1 value by returning the % of the given altitude range that it falls at.
|
||||
outValues[index] = GetRatio(m_configuration.m_altitudeMin, m_configuration.m_altitudeMax, highestAltitude);
|
||||
}
|
||||
else
|
||||
{
|
||||
outValues[index] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,16 +162,7 @@ namespace GradientSignal
|
||||
float SurfaceMaskGradientComponent::GetValue(const GradientSampleParams& params) const
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
if (!m_configuration.m_surfaceTagList.empty())
|
||||
{
|
||||
SurfaceData::SurfacePointList points;
|
||||
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
|
||||
params.m_position, m_configuration.m_surfaceTagList, points);
|
||||
|
||||
result = GetMaxSurfaceWeight(points);
|
||||
}
|
||||
|
||||
GetValues(AZStd::span<const AZ::Vector3>(¶ms.m_position, 1), AZStd::span<float>(&result, 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -183,34 +174,31 @@ namespace GradientSignal
|
||||
return;
|
||||
}
|
||||
|
||||
bool valuesFound = false;
|
||||
// Initialize all our output values to 0.
|
||||
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
|
||||
|
||||
if (!m_configuration.m_surfaceTagList.empty())
|
||||
{
|
||||
// Rather than calling GetSurfacePoints on the EBus repeatedly in a loop, we instead pass a lambda into the EBus that contains
|
||||
// the loop within it so that we can avoid the repeated EBus-calling overhead.
|
||||
SurfaceData::SurfacePointList points;
|
||||
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
|
||||
[this, positions, &outValues, &valuesFound](SurfaceData::SurfaceDataSystemRequestBus::Events* surfaceDataRequests)
|
||||
{
|
||||
// It's possible that there's nothing connected to the EBus, so keep track of the fact that we have valid results.
|
||||
valuesFound = true;
|
||||
SurfaceData::SurfacePointList points;
|
||||
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagList,
|
||||
points);
|
||||
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
{
|
||||
points.Clear();
|
||||
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagList, points);
|
||||
outValues[index] = GetMaxSurfaceWeight(points);
|
||||
}
|
||||
// For each position, get the max surface weight that matches our filter and that appears at that position.
|
||||
points.EnumeratePoints(
|
||||
[&outValues](
|
||||
size_t inPositionIndex, [[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& normal,
|
||||
const SurfaceData::SurfaceTagWeights& masks) -> bool
|
||||
{
|
||||
masks.EnumerateWeights(
|
||||
[inPositionIndex, &outValues]([[maybe_unused]] AZ::Crc32 surfaceType, float weight) -> bool
|
||||
{
|
||||
outValues[inPositionIndex] = AZ::GetMax(AZ::GetClamp(weight, 0.0f, 1.0f), outValues[inPositionIndex]);
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (!valuesFound)
|
||||
{
|
||||
// No surface tags, so no output values.
|
||||
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t SurfaceMaskGradientComponent::GetNumTags() const
|
||||
|
||||
@@ -205,14 +205,9 @@ namespace GradientSignal
|
||||
|
||||
float SurfaceSlopeGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
|
||||
{
|
||||
SurfaceData::SurfacePointList points;
|
||||
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePoints,
|
||||
sampleParams.m_position, m_configuration.m_surfaceTagsToSample, points);
|
||||
|
||||
const float angleMin = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMin, 0.0f, 90.0f));
|
||||
const float angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 0.0f, 90.0f));
|
||||
|
||||
return GetSlopeRatio(points, angleMin, angleMax);
|
||||
float result = 0.0f;
|
||||
GetValues(AZStd::span<const AZ::Vector3>(&sampleParams.m_position, 1), AZStd::span<float>(&result, 1));
|
||||
return result;
|
||||
}
|
||||
|
||||
void SurfaceSlopeGradientComponent::GetValues(AZStd::span<const AZ::Vector3> positions, AZStd::span<float> outValues) const
|
||||
@@ -223,32 +218,49 @@ namespace GradientSignal
|
||||
return;
|
||||
}
|
||||
|
||||
bool valuesFound = false;
|
||||
|
||||
// Rather than calling GetSurfacePoints on the EBus repeatedly in a loop, we instead pass a lambda into the EBus that contains
|
||||
// the loop within it so that we can avoid the repeated EBus-calling overhead.
|
||||
SurfaceData::SurfacePointList points;
|
||||
SurfaceData::SurfaceDataSystemRequestBus::Broadcast(
|
||||
[this, positions, &outValues, &valuesFound](SurfaceData::SurfaceDataSystemRequestBus::Events* surfaceDataRequests)
|
||||
{
|
||||
// It's possible that there's nothing connected to the EBus, so keep track of the fact that we have valid results.
|
||||
valuesFound = true;
|
||||
SurfaceData::SurfacePointList points;
|
||||
&SurfaceData::SurfaceDataSystemRequestBus::Events::GetSurfacePointsFromList, positions, m_configuration.m_surfaceTagsToSample,
|
||||
points);
|
||||
|
||||
const float angleMin = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMin, 0.0f, 90.0f));
|
||||
const float angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 0.0f, 90.0f));
|
||||
const float angleMin = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMin, 0.0f, 90.0f));
|
||||
const float angleMax = AZ::DegToRad(AZ::GetClamp(m_configuration.m_slopeMax, 0.0f, 90.0f));
|
||||
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
{
|
||||
points.Clear();
|
||||
surfaceDataRequests->GetSurfacePoints(positions[index], m_configuration.m_surfaceTagsToSample, points);
|
||||
outValues[index] = GetSlopeRatio(points, angleMin, angleMax);
|
||||
}
|
||||
});
|
||||
|
||||
if (!valuesFound)
|
||||
for (size_t index = 0; index < positions.size(); index++)
|
||||
{
|
||||
// No surface tags, so no output values.
|
||||
AZStd::fill(outValues.begin(), outValues.end(), 0.0f);
|
||||
if (points.IsEmpty(index))
|
||||
{
|
||||
outValues[index] = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assuming our surface normal vector is actually normalized, we can get the slope
|
||||
// by just grabbing the Z value. It's the same thing as normal.Dot(AZ::Vector3::CreateAxisZ()).
|
||||
auto highestSurfacePoint = points.GetHighestSurfacePoint(index);
|
||||
AZ_Assert(
|
||||
highestSurfacePoint.m_normal.GetNormalized().IsClose(highestSurfacePoint.m_normal),
|
||||
"Surface normals are expected to be normalized");
|
||||
const float slope = highestSurfacePoint.m_normal.GetZ();
|
||||
// Convert slope back to an angle so that we can lerp in "angular space", not "slope value space".
|
||||
// (We want our 0-1 range to be linear across the range of angles)
|
||||
const float slopeAngle = acosf(slope);
|
||||
|
||||
switch (m_configuration.m_rampType)
|
||||
{
|
||||
case SurfaceSlopeGradientConfig::RampType::SMOOTH_STEP:
|
||||
outValues[index] = m_configuration.m_smoothStep.GetSmoothedValue(GetRatio(angleMin, angleMax, slopeAngle));
|
||||
break;
|
||||
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_UP:
|
||||
// For ramp up, linearly interpolate from min to max.
|
||||
outValues[index] = GetRatio(angleMin, angleMax, slopeAngle);
|
||||
break;
|
||||
case SurfaceSlopeGradientConfig::RampType::LINEAR_RAMP_DOWN:
|
||||
default:
|
||||
// For ramp down, linearly interpolate from max to min.
|
||||
outValues[index] = GetRatio(angleMax, angleMin, slopeAngle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace GradientSignal
|
||||
// Create a fake surface point with the position we're sampling.
|
||||
AzFramework::SurfaceData::SurfacePoint point;
|
||||
point.m_position = params.m_position;
|
||||
point.m_normal = AZ::Vector3::CreateAxisZ();
|
||||
SurfaceData::SurfacePointList pointList = AZStd::span<const AzFramework::SurfaceData::SurfacePoint>(&point, 1);
|
||||
|
||||
// Send it into the component, see what emerges
|
||||
|
||||
@@ -78,6 +78,7 @@ namespace UnitTest
|
||||
for (int x = 0; x < dataSize; x++)
|
||||
{
|
||||
float angle = AZ::DegToRad(inputAngles[(y * dataSize) + x]);
|
||||
point.m_position = AZ::Vector3(aznumeric_cast<float>(x), aznumeric_cast<float>(y), 0.0f);
|
||||
point.m_normal = AZ::Vector3(sinf(angle), 0.0f, cosf(angle));
|
||||
mockSurface->m_surfacePoints[AZStd::make_pair(static_cast<float>(x), static_cast<float>(y))] =
|
||||
AZStd::span<const AzFramework::SurfaceData::SurfacePoint>(&point, 1);
|
||||
@@ -549,10 +550,10 @@ namespace UnitTest
|
||||
mockSurface->m_bounds = mockShapeComponentHandler.m_GetEncompassingAabb;
|
||||
AzFramework::SurfaceData::SurfacePoint mockOutputs[] =
|
||||
{
|
||||
{ AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateAxisZ() },
|
||||
};
|
||||
|
||||
mockSurface->m_surfacePoints[AZStd::make_pair(0.0f, 0.0f)] =
|
||||
@@ -597,10 +598,10 @@ namespace UnitTest
|
||||
auto mockSurface = surfaceEntity->CreateComponent<MockSurfaceProviderComponent>();
|
||||
mockSurface->m_bounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(0.0f), AZ::Vector3(1.0f));
|
||||
AzFramework::SurfaceData::SurfacePoint mockOutputs[] = {
|
||||
{ AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 0.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 2.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 5.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 10.0f), AZ::Vector3::CreateAxisZ() },
|
||||
};
|
||||
|
||||
mockSurface->m_surfacePoints[AZStd::make_pair(0.0f, 0.0f)] =
|
||||
@@ -667,10 +668,10 @@ namespace UnitTest
|
||||
auto mockSurface = surfaceEntity->CreateComponent<MockSurfaceProviderComponent>();
|
||||
mockSurface->m_bounds = AZ::Aabb::CreateFromMinMax(AZ::Vector3(0.0f), AZ::Vector3(1.0f));
|
||||
AzFramework::SurfaceData::SurfacePoint mockOutputs[] = {
|
||||
{ AZ::Vector3(0.0f, 0.0f, -10.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, -5.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 15.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 20.0f), AZ::Vector3::CreateZero() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, -10.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, -5.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 15.0f), AZ::Vector3::CreateAxisZ() },
|
||||
{ AZ::Vector3(0.0f, 0.0f, 20.0f), AZ::Vector3::CreateAxisZ() },
|
||||
};
|
||||
|
||||
// Altitude value below min - should result in 0.0f.
|
||||
@@ -724,6 +725,8 @@ namespace UnitTest
|
||||
{
|
||||
for (int x = 0; x < dataSize; x++)
|
||||
{
|
||||
point.m_position = AZ::Vector3(aznumeric_cast<float>(x), aznumeric_cast<float>(y), 0.0f);
|
||||
point.m_normal = AZ::Vector3::CreateAxisZ();
|
||||
point.m_surfaceTags.clear();
|
||||
point.m_surfaceTags.emplace_back(AZ_CRC_CE("test_mask"), expectedOutput[(y * dataSize) + x]);
|
||||
mockSurface->m_surfacePoints[AZStd::make_pair(static_cast<float>(x), static_cast<float>(y))] =
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
//#include "CustomizeKeyboardPage.h"
|
||||
|
||||
#include <AzCore/Math/Color.h>
|
||||
|
||||
#include <Util/EditorUtils.h>
|
||||
|
||||
#include <Editor/Resource.h>
|
||||
@@ -99,9 +101,9 @@ QColor ColorLinearToGamma(ColorF col)
|
||||
float g = clamp_tpl(col.g, 0.0f, 1.0f);
|
||||
float b = clamp_tpl(col.b, 0.0f, 1.0f);
|
||||
|
||||
r = (float)(r <= 0.0031308 ? (12.92 * r) : (1.055 * pow((double)r, 1.0 / 2.4) - 0.055));
|
||||
g = (float)(g <= 0.0031308 ? (12.92 * g) : (1.055 * pow((double)g, 1.0 / 2.4) - 0.055));
|
||||
b = (float)(b <= 0.0031308 ? (12.92 * b) : (1.055 * pow((double)b, 1.0 / 2.4) - 0.055));
|
||||
r = AZ::Color::ConvertSrgbLinearToGamma(r);
|
||||
g = AZ::Color::ConvertSrgbLinearToGamma(g);
|
||||
b = AZ::Color::ConvertSrgbLinearToGamma(b);
|
||||
|
||||
return QColor(int(r * 255.0f), int(g * 255.0f), int(b * 255.0f));
|
||||
}
|
||||
@@ -113,7 +115,7 @@ ColorF ColorGammaToLinear(const QColor& col)
|
||||
float g = (float)col.green() / 255.0f;
|
||||
float b = (float)col.blue() / 255.0f;
|
||||
|
||||
return ColorF((float)(r <= 0.04045 ? (r / 12.92) : pow(((double)r + 0.055) / 1.055, 2.4)),
|
||||
(float)(g <= 0.04045 ? (g / 12.92) : pow(((double)g + 0.055) / 1.055, 2.4)),
|
||||
(float)(b <= 0.04045 ? (b / 12.92) : pow(((double)b + 0.055) / 1.055, 2.4)));
|
||||
return ColorF(AZ::Color::ConvertSrgbGammaToLinear(r),
|
||||
AZ::Color::ConvertSrgbGammaToLinear(g),
|
||||
AZ::Color::ConvertSrgbGammaToLinear(b));
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace SurfaceData
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataProviderRequestBus
|
||||
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
|
||||
void GetSurfacePointsFromList(AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataModifierRequestBus
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace SurfaceData
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataProviderRequestBus
|
||||
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const override;
|
||||
void GetSurfacePointsFromList(AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataModifierRequestBus
|
||||
|
||||
@@ -185,8 +185,6 @@ namespace SurfaceData
|
||||
|
||||
bool SurfaceDataColliderComponent::DoRayTrace(const AZ::Vector3& inPosition, bool queryPointOnly, AZ::Vector3& outPosition, AZ::Vector3& outNormal) const
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
// test AABB as first pass to claim the point
|
||||
const AZ::Vector3 testPosition = AZ::Vector3(
|
||||
inPosition.GetX(),
|
||||
@@ -229,18 +227,45 @@ namespace SurfaceData
|
||||
|
||||
void SurfaceDataColliderComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZ::Vector3 hitPosition;
|
||||
AZ::Vector3 hitNormal;
|
||||
|
||||
// We want a full raycast, so don't just query the start point.
|
||||
constexpr bool queryPointOnly = false;
|
||||
|
||||
if (DoRayTrace(inPosition, queryPointOnly, hitPosition, hitNormal))
|
||||
{
|
||||
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, hitPosition, hitNormal, m_newPointWeights);
|
||||
}
|
||||
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
|
||||
}
|
||||
|
||||
void SurfaceDataColliderComponent::GetSurfacePointsFromList(
|
||||
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AzPhysics::SimulatedBodyComponentRequestsBus::Event(
|
||||
GetEntityId(),
|
||||
[this, inPositions, &surfacePointList](AzPhysics::SimulatedBodyComponentRequestsBus::Events* simBody)
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
AzPhysics::RayCastRequest request;
|
||||
request.m_direction = -AZ::Vector3::CreateAxisZ();
|
||||
|
||||
for (auto& inPosition : inPositions)
|
||||
{
|
||||
// test AABB as first pass to claim the point
|
||||
if (SurfaceData::AabbContains2D(m_colliderBounds, inPosition))
|
||||
{
|
||||
// We're casting the ray to look for a collision, so start at the top of the collider and cast downwards
|
||||
// the full height of the collider.
|
||||
request.m_start = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_colliderBounds.GetMax().GetZ());
|
||||
request.m_distance = m_colliderBounds.GetExtents().GetZ();
|
||||
|
||||
AzPhysics::SceneQueryHit result = simBody->RayCast(request);
|
||||
|
||||
if (result)
|
||||
{
|
||||
surfacePointList.AddSurfacePoint(
|
||||
GetEntityId(), inPosition, result.m_position, result.m_normal, m_newPointWeights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void SurfaceDataColliderComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
@@ -143,24 +143,48 @@ namespace SurfaceData
|
||||
}
|
||||
|
||||
void SurfaceDataShapeComponent::GetSurfacePoints(const AZ::Vector3& inPosition, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
|
||||
}
|
||||
|
||||
void SurfaceDataShapeComponent::GetSurfacePointsFromList(
|
||||
AZStd::span<const AZ::Vector3> inPositions, SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
if (m_shapeBoundsIsValid && SurfaceData::AabbContains2D(m_shapeBounds, inPosition))
|
||||
if (!m_shapeBoundsIsValid)
|
||||
{
|
||||
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_shapeBounds.GetMax().GetZ());
|
||||
const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
|
||||
float intersectionDistance = 0.0f;
|
||||
bool hitShape = false;
|
||||
LmbrCentral::ShapeComponentRequestsBus::EventResult(hitShape, GetEntityId(), &LmbrCentral::ShapeComponentRequestsBus::Events::IntersectRay, rayOrigin, rayDirection, intersectionDistance);
|
||||
if (hitShape)
|
||||
{
|
||||
AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection;
|
||||
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, position, AZ::Vector3::CreateAxisZ(), m_newPointWeights);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LmbrCentral::ShapeComponentRequestsBus::Event(
|
||||
GetEntityId(),
|
||||
[this, inPositions, &surfacePointList](LmbrCentral::ShapeComponentRequestsBus::Events* shape)
|
||||
{
|
||||
const AZ::Vector3 rayDirection = -AZ::Vector3::CreateAxisZ();
|
||||
|
||||
// Shapes don't currently have a way to query normals at a point intersection, so we'll just return a Z-up normal
|
||||
// until they get support for it.
|
||||
const AZ::Vector3 surfacePointNormal = AZ::Vector3::CreateAxisZ();
|
||||
|
||||
for (auto& inPosition : inPositions)
|
||||
{
|
||||
if (SurfaceData::AabbContains2D(m_shapeBounds, inPosition))
|
||||
{
|
||||
const AZ::Vector3 rayOrigin = AZ::Vector3(inPosition.GetX(), inPosition.GetY(), m_shapeBounds.GetMax().GetZ());
|
||||
float intersectionDistance = 0.0f;
|
||||
bool hitShape = shape->IntersectRay(rayOrigin, rayDirection, intersectionDistance);
|
||||
if (hitShape)
|
||||
{
|
||||
AZ::Vector3 position = rayOrigin + intersectionDistance * rayDirection;
|
||||
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, position, surfacePointNormal, m_newPointWeights);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void SurfaceDataShapeComponent::ModifySurfacePoints(SurfacePointList& surfacePointList) const
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
@@ -32,7 +32,11 @@ namespace SurfaceData
|
||||
inPositionIndex = (inPositionIndex + 1) % m_inputPositions.size();
|
||||
}
|
||||
|
||||
AZ_Assert(foundMatch, "Couldn't find input position!");
|
||||
AZ_Assert(
|
||||
foundMatch,
|
||||
"Couldn't find input position: (%0.7f, %0.7f, %0.7f), m_lastInputPositionIndex = %zu, m_inputPositions.size() = %zu",
|
||||
inPosition.GetX(), inPosition.GetY(), inPosition.GetZ(), m_lastInputPositionIndex, m_inputPositions.size());
|
||||
|
||||
m_lastInputPositionIndex = inPositionIndex;
|
||||
return inPositionIndex;
|
||||
}
|
||||
|
||||
@@ -145,29 +145,42 @@ namespace Terrain
|
||||
|
||||
void TerrainSurfaceDataSystemComponent::GetSurfacePoints(
|
||||
const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const
|
||||
{
|
||||
GetSurfacePointsFromList(AZStd::span<const AZ::Vector3>(&inPosition, 1), surfacePointList);
|
||||
}
|
||||
|
||||
void TerrainSurfaceDataSystemComponent::GetSurfacePointsFromList(
|
||||
AZStd::span<const AZ::Vector3> inPositions, SurfaceData::SurfacePointList& surfacePointList) const
|
||||
{
|
||||
if (!m_terrainBoundsIsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isTerrainValidAtPoint = false;
|
||||
AzFramework::SurfaceData::SurfacePoint terrainSurfacePoint;
|
||||
AzFramework::Terrain::TerrainDataRequestBus::Broadcast(&AzFramework::Terrain::TerrainDataRequestBus::Events::GetSurfacePoint,
|
||||
inPosition, terrainSurfacePoint, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR,
|
||||
&isTerrainValidAtPoint);
|
||||
size_t inPositionIndex = 0;
|
||||
|
||||
const bool isHole = !isTerrainValidAtPoint;
|
||||
AzFramework::Terrain::TerrainDataRequestBus::Broadcast(
|
||||
&AzFramework::Terrain::TerrainDataRequestBus::Events::ProcessSurfacePointsFromList, inPositions,
|
||||
[this, inPositions, &inPositionIndex, &surfacePointList]
|
||||
(const AzFramework::SurfaceData::SurfacePoint& surfacePoint, bool terrainExists)
|
||||
{
|
||||
AZ_Assert(inPositionIndex < inPositions.size(), "Too many points returned from ProcessSurfacePointsFromList");
|
||||
|
||||
SurfaceData::SurfaceTagWeights weights(terrainSurfacePoint.m_surfaceTags);
|
||||
SurfaceData::SurfaceTagWeights weights(surfacePoint.m_surfaceTags);
|
||||
|
||||
// Always add a "terrain" or "terrainHole" tag.
|
||||
const AZ::Crc32 terrainTag = isHole ? Constants::s_terrainHoleTagCrc : Constants::s_terrainTagCrc;
|
||||
weights.AddSurfaceTagWeight(terrainTag, 1.0f);
|
||||
// Always add a "terrain" or "terrainHole" tag.
|
||||
const AZ::Crc32 terrainTag = terrainExists ? Constants::s_terrainTagCrc : Constants::s_terrainHoleTagCrc;
|
||||
weights.AddSurfaceTagWeight(terrainTag, 1.0f);
|
||||
|
||||
surfacePointList.AddSurfacePoint(GetEntityId(), inPosition, terrainSurfacePoint.m_position, terrainSurfacePoint.m_normal, weights);
|
||||
surfacePointList.AddSurfacePoint(
|
||||
GetEntityId(), inPositions[inPositionIndex], surfacePoint.m_position, surfacePoint.m_normal, weights);
|
||||
|
||||
inPositionIndex++;
|
||||
},
|
||||
AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR);
|
||||
}
|
||||
|
||||
|
||||
AZ::Aabb TerrainSurfaceDataSystemComponent::GetSurfaceAabb() const
|
||||
{
|
||||
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace Terrain
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SurfaceDataProviderRequestBus
|
||||
void GetSurfacePoints(const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const override;
|
||||
void GetSurfacePointsFromList(
|
||||
AZStd::span<const AZ::Vector3> inPositions, SurfaceData::SurfacePointList& surfacePointList) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AzFramework::Terrain::TerrainDataNotificationBus
|
||||
|
||||
@@ -192,7 +192,7 @@ bool TerrainSystem::InWorldBounds(float x, float y) const
|
||||
}
|
||||
|
||||
// Generate positions to be queried based on the sampler type.
|
||||
void TerrainSystem::GenerateQueryPositions(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
void TerrainSystem::GenerateQueryPositions(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AZStd::vector<AZ::Vector3>& outPositions,
|
||||
Sampler sampler) const
|
||||
{
|
||||
@@ -253,7 +253,7 @@ AZStd::vector<AZ::Vector3> TerrainSystem::GenerateInputPositionsFromRegion(
|
||||
}
|
||||
|
||||
void TerrainSystem::MakeBulkQueries(
|
||||
const AZStd::span<AZ::Vector3> inPositions,
|
||||
const AZStd::span<const AZ::Vector3> inPositions,
|
||||
AZStd::span<AZ::Vector3> outPositions,
|
||||
AZStd::span<bool> outTerrainExists,
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
|
||||
@@ -296,7 +296,7 @@ void TerrainSystem::MakeBulkQueries(
|
||||
if (prevAreaId != AZ::EntityId())
|
||||
{
|
||||
size_t spanLength = (windowEnd - windowStart) + 1;
|
||||
queryCallback(AZStd::span<AZ::Vector3>(inPositions.begin() + windowStart, spanLength),
|
||||
queryCallback(AZStd::span<const AZ::Vector3>(inPositions.begin() + windowStart, spanLength),
|
||||
AZStd::span<AZ::Vector3>(outPositions.begin() + windowStart, spanLength),
|
||||
AZStd::span<bool>(outTerrainExists.begin() + windowStart, spanLength),
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList>(outSurfaceWeights.begin() + windowStart, spanLength),
|
||||
@@ -311,7 +311,7 @@ void TerrainSystem::MakeBulkQueries(
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainSystem::GetHeightsSynchronous(const AZStd::span<AZ::Vector3>& inPositions, Sampler sampler,
|
||||
void TerrainSystem::GetHeightsSynchronous(const AZStd::span<const AZ::Vector3>& inPositions, Sampler sampler,
|
||||
AZStd::span<float> heights, AZStd::span<bool> terrainExists) const
|
||||
{
|
||||
AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex);
|
||||
@@ -328,7 +328,7 @@ void TerrainSystem::GetHeightsSynchronous(const AZStd::span<AZ::Vector3>& inPosi
|
||||
|
||||
GenerateQueryPositions(inPositions, outPositions, sampler);
|
||||
|
||||
auto callback = []([[maybe_unused]] const AZStd::span<AZ::Vector3> inPositions,
|
||||
auto callback = []([[maybe_unused]] const AZStd::span<const AZ::Vector3> inPositions,
|
||||
AZStd::span<AZ::Vector3> outPositions,
|
||||
AZStd::span<bool> outTerrainExists,
|
||||
[[maybe_unused]] AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
|
||||
@@ -516,7 +516,7 @@ bool TerrainSystem::GetIsHoleFromFloats(float x, float y, Sampler sampler) const
|
||||
return !terrainExists;
|
||||
}
|
||||
|
||||
void TerrainSystem::GetNormalsSynchronous(const AZStd::span<AZ::Vector3>& inPositions, Sampler sampler,
|
||||
void TerrainSystem::GetNormalsSynchronous(const AZStd::span<const AZ::Vector3>& inPositions, Sampler sampler,
|
||||
AZStd::span<AZ::Vector3> normals, AZStd::span<bool> terrainExists) const
|
||||
{
|
||||
AZStd::vector<AZ::Vector3> directionVectors;
|
||||
@@ -685,7 +685,7 @@ AzFramework::RenderGeometry::RayResult TerrainSystem::GetClosestIntersection(
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessHeightsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -695,7 +695,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessNormalsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -705,7 +705,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfaceWeightsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -715,7 +715,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfacePointsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -725,7 +725,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessHeightsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -735,7 +735,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessNormalsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -745,7 +745,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfaceWeightsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -755,7 +755,7 @@ AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext>
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessSurfacePointsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -830,7 +830,7 @@ AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::A
|
||||
}
|
||||
|
||||
void TerrainSystem::GetOrderedSurfaceWeightsFromList(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
[[maybe_unused]] Sampler sampler,
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList,
|
||||
AZStd::span<bool> terrainExists) const
|
||||
@@ -841,7 +841,7 @@ void TerrainSystem::GetOrderedSurfaceWeightsFromList(
|
||||
GetHeightsSynchronous(inPositions, AzFramework::Terrain::TerrainDataRequests::Sampler::EXACT, heights, terrainExists);
|
||||
}
|
||||
|
||||
auto callback = [](const AZStd::span<AZ::Vector3> inPositions,
|
||||
auto callback = [](const AZStd::span<const AZ::Vector3> inPositions,
|
||||
[[maybe_unused]] AZStd::span<AZ::Vector3> outPositions,
|
||||
[[maybe_unused]] AZStd::span<bool> outTerrainExists,
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
|
||||
@@ -929,7 +929,7 @@ const char* TerrainSystem::GetMaxSurfaceName(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessHeightsFromList(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -953,7 +953,7 @@ void TerrainSystem::ProcessHeightsFromList(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessNormalsFromList(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -977,7 +977,7 @@ void TerrainSystem::ProcessNormalsFromList(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessSurfaceWeightsFromList(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -1001,7 +1001,7 @@ void TerrainSystem::ProcessSurfaceWeightsFromList(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessSurfacePointsFromList(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -1034,7 +1034,7 @@ void TerrainSystem::ProcessSurfacePointsFromList(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessHeightsFromListOfVector2(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -1054,7 +1054,7 @@ void TerrainSystem::ProcessHeightsFromListOfVector2(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessNormalsFromListOfVector2(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -1074,7 +1074,7 @@ void TerrainSystem::ProcessNormalsFromListOfVector2(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
@@ -1094,7 +1094,7 @@ void TerrainSystem::ProcessSurfaceWeightsFromListOfVector2(
|
||||
}
|
||||
|
||||
void TerrainSystem::ProcessSurfacePointsFromListOfVector2(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter) const
|
||||
{
|
||||
|
||||
@@ -140,28 +140,28 @@ namespace Terrain
|
||||
|
||||
//! Given a list of XY coordinates, call the provided callback function with surface data corresponding to each
|
||||
//! XY coordinate in the list.
|
||||
virtual void ProcessHeightsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessHeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessNormalsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessNormalsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessSurfaceWeightsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessSurfacePointsFromList(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
virtual void ProcessSurfacePointsFromList(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessHeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessNormalsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessSurfaceWeightsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<AZ::Vector2>& inPositions,
|
||||
virtual void ProcessSurfacePointsFromListOfVector2(const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const override;
|
||||
|
||||
@@ -194,42 +194,42 @@ namespace Terrain
|
||||
const AzFramework::RenderGeometry::RayRequest& ray) const override;
|
||||
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListAsync(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessHeightsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessNormalsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessSurfaceWeightsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessSurfacePointsFromListOfVector2Async(
|
||||
const AZStd::span<AZ::Vector2>& inPositions,
|
||||
const AZStd::span<const AZ::Vector2>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const override;
|
||||
@@ -262,7 +262,7 @@ namespace Terrain
|
||||
template<typename SynchronousFunctionType, typename VectorType>
|
||||
AZStd::shared_ptr<TerrainJobContext> ProcessFromListAsync(
|
||||
SynchronousFunctionType synchronousFunction,
|
||||
const AZStd::span<VectorType>& inPositions,
|
||||
const AZStd::span<const VectorType>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params = nullptr) const;
|
||||
@@ -291,31 +291,31 @@ namespace Terrain
|
||||
AZ::Vector3 GetNormalSynchronous(float x, float y, Sampler sampler, bool* terrainExistsPtr) const;
|
||||
|
||||
typedef AZStd::function<void(
|
||||
const AZStd::span<AZ::Vector3> inPositions,
|
||||
const AZStd::span<const AZ::Vector3> inPositions,
|
||||
AZStd::span<AZ::Vector3> outPositions,
|
||||
AZStd::span<bool> outTerrainExists,
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeights,
|
||||
AZ::EntityId areaId)> BulkQueriesCallback;
|
||||
|
||||
void GetHeightsSynchronous(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
Sampler sampler, AZStd::span<float> heights,
|
||||
AZStd::span<bool> terrainExists) const;
|
||||
void GetNormalsSynchronous(
|
||||
const AZStd::span<AZ::Vector3>& inPositions,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
Sampler sampler, AZStd::span<AZ::Vector3> normals,
|
||||
AZStd::span<bool> terrainExists) const;
|
||||
void GetOrderedSurfaceWeightsFromList(
|
||||
const AZStd::span<AZ::Vector3>& inPositions, Sampler sampler,
|
||||
const AZStd::span<const AZ::Vector3>& inPositions, Sampler sampler,
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWeightsList,
|
||||
AZStd::span<bool> terrainExists) const;
|
||||
void MakeBulkQueries(
|
||||
const AZStd::span<AZ::Vector3> inPositions,
|
||||
const AZStd::span<const AZ::Vector3> inPositions,
|
||||
AZStd::span<AZ::Vector3> outPositions,
|
||||
AZStd::span<bool> outTerrainExists,
|
||||
AZStd::span<AzFramework::SurfaceData::SurfaceTagWeightList> outSurfaceWieghts,
|
||||
BulkQueriesCallback queryCallback) const;
|
||||
void GenerateQueryPositions(const AZStd::span<AZ::Vector3>& inPositions,
|
||||
void GenerateQueryPositions(const AZStd::span<const AZ::Vector3>& inPositions,
|
||||
AZStd::vector<AZ::Vector3>& outPositions,
|
||||
Sampler sampler) const;
|
||||
AZStd::vector<AZ::Vector3> GenerateInputPositionsFromRegion(
|
||||
@@ -361,7 +361,7 @@ namespace Terrain
|
||||
template<typename SynchronousFunctionType, typename VectorType>
|
||||
inline AZStd::shared_ptr<AzFramework::Terrain::TerrainDataRequests::TerrainJobContext> TerrainSystem::ProcessFromListAsync(
|
||||
SynchronousFunctionType synchronousFunction,
|
||||
const AZStd::span<VectorType>& inPositions,
|
||||
const AZStd::span<const VectorType>& inPositions,
|
||||
AzFramework::Terrain::SurfacePointListFillCallback perPositionCallback,
|
||||
Sampler sampleFilter,
|
||||
AZStd::shared_ptr<ProcessAsyncParams> params) const
|
||||
@@ -397,7 +397,7 @@ namespace Terrain
|
||||
const size_t subSpanCount = (i < numJobs - 1) ? numPositionsPerJob : AZStd::dynamic_extent;
|
||||
|
||||
// Define the job function using the sub span of positions to process.
|
||||
const AZStd::span<VectorType>& positionsToProcess = inPositions.subspan(subSpanOffset, subSpanCount);
|
||||
const AZStd::span<const VectorType>& positionsToProcess = inPositions.subspan(subSpanOffset, subSpanCount);
|
||||
auto jobFunction = [this, synchronousFunction, positionsToProcess, perPositionCallback, sampleFilter, jobContext, params]()
|
||||
{
|
||||
// Process the sub span of positions, unless the associated job context has been cancelled.
|
||||
|
||||
Reference in New Issue
Block a user