merging from main
This commit is contained in:
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game" UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game (fast decode)" UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="lz4hc" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game (Z-up)" UpAxis="Z" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Game (fast decode, Z-up)" UpAxis="Z" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="lz4hc" PlaybackFromMemory="0" PositionPrecision="1" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Prerendered" UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Prerendered (Z-up)" UpAxis="Z" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Rigids Only" UpAxis="Y" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="1" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Rigids Only (Z-up)" UpAxis="Z" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="deflate" PlaybackFromMemory="1" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Uncompressed (fastest compile)" UpAxis="Y" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="store" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration Name="Uncompressed (fastest compile, Z-up)" UpAxis="Z" MeshPrediction="0" UseBFrames="0" IndexFrameDistance="10" BlockCompressionFormat="store" PlaybackFromMemory="0" PositionPrecision="0" UVmax="0"/>
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9c36d7bc993ddf616f478115a123efabda5b4b833a4e6524312f43c228ae0902
|
||||
size 487003
|
||||
@@ -1 +0,0 @@
|
||||
<CacheBuildConfiguration UpAxis="Y" MeshPrediction="1" UseBFrames="1" IndexFrameDistance="15" BlockCompressionFormat="deflate" PlaybackFromMemory="1"/>
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96a21446422b834ea90a5d38eaaca309fdee31dc3cc03c0e9c094b39ec3a459d
|
||||
size 4715164
|
||||
@@ -1,17 +0,0 @@
|
||||
<Material MtlFlags="524544" vertModifType="0">
|
||||
<SubMaterials>
|
||||
<Material Name="mat01_white" MtlFlags="524416" Shader="Illum" GenMask="12000020040003" StringGenMask="%ALLOW_SILHOUETTE_POM%ALLOW_SPECULAR_ANTIALIASING%EMITTANCE_MAP%NORMAL_MAP%SPECULAR_MAP%SUBSURFACE_SCATTERING" SurfaceType="mat_default" Diffuse="1,1,1,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="174.72" vertModifType="0" LayerAct="1">
|
||||
<Textures>
|
||||
<Texture Map="Diffuse" File="engineassets/textures/white.dds"/>
|
||||
</Textures>
|
||||
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
|
||||
</Material>
|
||||
<Material Name="mat02_grey" MtlFlags="524416" Shader="Illum" GenMask="10000000000003" StringGenMask="%ALLOW_SILHOUETTE_POM%ALLOW_SPECULAR_ANTIALIASING%SUBSURFACE_SCATTERING" SurfaceType="mat_default" Diffuse="0.5,0.5,0.5,1" Specular="0.5,0.5,0.5,1" Opacity="1" Shininess="10" vertModifType="0" LayerAct="1">
|
||||
<Textures>
|
||||
<Texture Map="Diffuse" File="engineassets/textures/white.dds"/>
|
||||
</Textures>
|
||||
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
|
||||
</Material>
|
||||
</SubMaterials>
|
||||
<PublicParams EmittanceMapGamma="1" SSSIndex="0" IndirectColor="0.25,0.25,0.25"/>
|
||||
</Material>
|
||||
@@ -8,3 +8,8 @@
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(GEM_DEPENDENCIES
|
||||
Gem::Atom_RHI_Metal.Private
|
||||
Gem::Atom_RHI_Null.Private
|
||||
)
|
||||
@@ -8,3 +8,10 @@
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(GEM_DEPENDENCIES
|
||||
Gem::Atom_RHI_Null.Private
|
||||
Gem::Atom_RHI_Null.Builders
|
||||
Gem::Atom_RHI_Metal.Private
|
||||
Gem::Atom_RHI_Metal.Builders
|
||||
)
|
||||
@@ -25,10 +25,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE main
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Main.py
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
@@ -39,10 +38,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE periodic
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Periodic.py
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
@@ -56,7 +54,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TIMEOUT 3600
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
@@ -71,10 +68,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE periodic
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/scripting/TestSuite_Active.py
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
@@ -85,10 +81,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE sandbox
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/scripting/TestSuite_Sandbox.py
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
)
|
||||
@@ -101,10 +96,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE main
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/WhiteBox/TestSuite_Active.py
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
@@ -120,10 +114,9 @@ endif()
|
||||
# TEST_SUITE main
|
||||
# TEST_SERIAL
|
||||
# PATH ${CMAKE_CURRENT_LIST_DIR}/NvCloth/TestSuite_Active.py
|
||||
# TIMEOUT 3600
|
||||
# TIMEOUT 1500
|
||||
# RUNTIME_DEPENDENCIES
|
||||
# Legacy::Editor
|
||||
# Legacy::CryRenderNULL
|
||||
# AZ::AssetProcessor
|
||||
# AutomatedTesting.Assets
|
||||
# )
|
||||
@@ -136,10 +129,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE sandbox
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/EditorPythonBindings
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Gem::EditorPythonBindings.Editor
|
||||
@@ -154,10 +146,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE periodic
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/PythonAssetBuilder
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
Gem::EditorPythonBindings.Editor
|
||||
@@ -173,7 +164,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
TEST_SUITE main
|
||||
TEST_SERIAL TRUE
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/Blast/TestSuite_Active.py
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
AZ::AssetProcessor
|
||||
@@ -190,21 +181,23 @@ include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED)
|
||||
|
||||
## DynVeg ##
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Main
|
||||
TEST_SERIAL
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
|
||||
TIMEOUT 36000
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.GameLauncher
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
# Temporarily moving all tests to periodic suite - SPEC-6553
|
||||
#ly_add_pytest(
|
||||
# NAME AutomatedTesting::DynamicVegetationTests_Main
|
||||
# TEST_SERIAL
|
||||
# TEST_SUITE main
|
||||
# PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
# PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
|
||||
# TIMEOUT 1500
|
||||
# RUNTIME_DEPENDENCIES
|
||||
# AZ::AssetProcessor
|
||||
# Legacy::Editor
|
||||
# AutomatedTesting.GameLauncher
|
||||
# AutomatedTesting.Assets
|
||||
# COMPONENT
|
||||
# LargeWorlds
|
||||
#)
|
||||
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Sandbox
|
||||
@@ -212,7 +205,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
TEST_SUITE sandbox
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_sandbox"
|
||||
TIMEOUT 36000
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
@@ -223,12 +216,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationTests_Periodic
|
||||
NAME AutomatedTesting::DynamicVegetationFilterTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic"
|
||||
TIMEOUT 3600
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_filter"
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
@@ -237,29 +230,104 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
## LandscapeCanvas ##
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::LandscapeCanvasTests_Main
|
||||
NAME AutomatedTesting::DynamicVegetationModifierTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/landscape_canvas
|
||||
PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
|
||||
TIMEOUT 3600
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_modifier"
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationRegressionTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_regression"
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationAreaTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_area"
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationMiscTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_misc"
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::DynamicVegetationSurfaceTagTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
|
||||
PYTEST_MARKS "SUITE_periodic and dynveg_surfacetagemitter"
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
LargeWorlds
|
||||
)
|
||||
## LandscapeCanvas ##
|
||||
# Temporarily moving all tests to periodic suite - SPEC-6553
|
||||
#ly_add_pytest(
|
||||
# NAME AutomatedTesting::LandscapeCanvasTests_Main
|
||||
# TEST_SERIAL
|
||||
# TEST_SUITE main
|
||||
# PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/landscape_canvas
|
||||
# PYTEST_MARKS "not SUITE_sandbox and not SUITE_periodic and not SUITE_benchmark"
|
||||
# TIMEOUT 1500
|
||||
# RUNTIME_DEPENDENCIES
|
||||
# AZ::AssetProcessor
|
||||
# Legacy::Editor
|
||||
# AutomatedTesting.Assets
|
||||
# COMPONENT
|
||||
# LargeWorlds
|
||||
#)
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::LandscapeCanvasTests_Periodic
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/landscape_canvas
|
||||
PYTEST_MARKS "SUITE_periodic"
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
@@ -274,7 +342,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
TEST_SERIAL
|
||||
TEST_SUITE periodic
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/gradient_signal
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
Legacy::Editor
|
||||
@@ -292,10 +360,9 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
|
||||
TEST_SUITE periodic
|
||||
TEST_SERIAL
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/editor
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
RUNTIME_DEPENDENCIES
|
||||
Legacy::Editor
|
||||
Legacy::CryRenderNULL
|
||||
AZ::AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
COMPONENT
|
||||
@@ -314,7 +381,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
# AZ::AssetProcessor
|
||||
# AZ::AssetProcessorBatch
|
||||
# AutomatedTesting.GameLauncher
|
||||
# Legacy::CryRenderNULL
|
||||
#)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
#
|
||||
# This is a pytest module to test the in-Editor Python API from ViewPane.h
|
||||
#
|
||||
import pytest
|
||||
pytest.importorskip('ly_test_tools')
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
from hydra_utils import launch_test_case
|
||||
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
|
||||
@pytest.mark.parametrize('project', ['AutomatedTesting'])
|
||||
@pytest.mark.parametrize('level', ['auto_test'])
|
||||
class TestLegacyCryMaterialsCommandsAutomation(object):
|
||||
|
||||
def test_Legacy_CryMaterials(self, request, editor, level, launcher_platform):
|
||||
|
||||
unexpected_lines=[]
|
||||
expected_lines = [
|
||||
# "Material Settings/Shader updated correctly", # Disabled, SPEC-3590
|
||||
# "Material Settings/Surface Type updated correctly", # Disabled, SPEC-3590
|
||||
"Texture Maps/Diffuse/Tiling/IsTileU updated correctly",
|
||||
"Texture Maps/Diffuse/Tiling/TileU updated correctly",
|
||||
"Texture Maps/Diffuse/Rotator/Type updated correctly",
|
||||
"Texture Maps/Diffuse/Rotator/Amplitude updated correctly",
|
||||
"Texture Maps/Diffuse/Oscillator/AmplitudeU updated correctly",
|
||||
"Opacity Settings/Opacity updated correctly",
|
||||
"Opacity Settings/AlphaTest updated correctly",
|
||||
"Opacity Settings/Additive updated correctly",
|
||||
"Lighting Settings/Diffuse Color updated correctly",
|
||||
"Lighting Settings/Specular Color updated correctly",
|
||||
"Lighting Settings/Emissive Intensity updated correctly",
|
||||
"Lighting Settings/Emissive Color updated correctly",
|
||||
"Advanced/Allow layer activation updated correctly",
|
||||
"Advanced/2 Sided updated correctly",
|
||||
"Advanced/No Shadow updated correctly",
|
||||
"Advanced/Use Scattering updated correctly",
|
||||
"Advanced/Hide After Breaking updated correctly",
|
||||
"Advanced/Fog Volume Shading Quality High updated correctly",
|
||||
"Advanced/Blend Terrain Color updated correctly",
|
||||
"Advanced/Voxel Coverage updated correctly",
|
||||
"Advanced/Propagate Opacity Settings updated correctly",
|
||||
"Advanced/Propagate Lighting Settings updated correctly",
|
||||
"Advanced/Propagate Advanced Settings updated correctly",
|
||||
"Advanced/Propagate Texture Maps updated correctly",
|
||||
"Advanced/Propagate Shader Params updated correctly",
|
||||
"Advanced/Propagate Shader Generation updated correctly",
|
||||
"Advanced/Propagate Vertex Deformation updated correctly",
|
||||
# "Shader Params/Blend Factor updated correctly", # Disabled, SPEC-3590
|
||||
# "Shader Params/Indirect bounce color updated correctly", # Disabled, SPEC-3590
|
||||
"Vertex Deformation/Type updated correctly",
|
||||
"Vertex Deformation/Wave Length X updated correctly",
|
||||
"Vertex Deformation/Wave X/Level updated correctly",
|
||||
"Vertex Deformation/Wave X/Amplitude updated correctly",
|
||||
"Vertex Deformation/Wave X/Phase updated correctly",
|
||||
"Vertex Deformation/Wave X/Frequency updated correctly"
|
||||
]
|
||||
|
||||
test_case_file = os.path.join(os.path.dirname(__file__), 'CryMaterialsCommands_test_case.py')
|
||||
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
|
||||
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
"""
|
||||
|
||||
# Tests the legacy Python API for CryMaterials while the Editor is running
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.legacy.material as material
|
||||
import azlmbr.math as math
|
||||
|
||||
materialName = 'materials/ter_layer_green'
|
||||
print(f'Starting CryMaterial test case using material {materialName}')
|
||||
|
||||
|
||||
def MaterialPropertyTest(property, value, doReset=True):
|
||||
try:
|
||||
# get old value and attempt to set new value
|
||||
oldValue = material.get_property(materialName, property)
|
||||
if oldValue == value:
|
||||
print(f'>>> `{property}` already set to {oldValue}')
|
||||
return
|
||||
material.set_property(materialName, property, value)
|
||||
|
||||
# test that the set new value worked
|
||||
newValue = material.get_property(materialName, property)
|
||||
if oldValue != newValue:
|
||||
print(f"{property} updated correctly")
|
||||
|
||||
# reset back to old value
|
||||
if doReset:
|
||||
material.set_property(materialName, property, oldValue)
|
||||
except:
|
||||
print(f'!!! hit an exception when setting `{property}` to {value}')
|
||||
|
||||
|
||||
color = math.Color()
|
||||
color.r = 255.0
|
||||
color.g = 128.0
|
||||
color.b = 64.0
|
||||
color.a = 0.0
|
||||
|
||||
# Material Settings
|
||||
# MaterialPropertyTest("Material Settings/Shader", "Geometrybeam") # Disabled, SPEC-3590
|
||||
# MaterialPropertyTest("Material Settings/Surface Type", "grass") # Disabled, SPEC-3590
|
||||
|
||||
# Texture Maps
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/IsTileU", False)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/IsTileV", False)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/TileU", 0.42)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Rotator/Type", 'Oscillated Rotation')
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Rotator/Amplitude", 42.0)
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Oscillator/TypeU", 'Fixed Moving')
|
||||
MaterialPropertyTest("Texture Maps/Diffuse/Oscillator/AmplitudeU", 42.0)
|
||||
|
||||
# Vertex Deformation
|
||||
MaterialPropertyTest("Vertex Deformation/Type", 'Sin Wave')
|
||||
MaterialPropertyTest("Vertex Deformation/Wave Length X", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Type", 'Perlin 3D')
|
||||
MaterialPropertyTest("Vertex Deformation/Noise Scale", math.Vector3(1.1, 2.2, 3.3))
|
||||
|
||||
# Opacity Settings
|
||||
MaterialPropertyTest("Opacity Settings/Opacity", 42)
|
||||
MaterialPropertyTest("Opacity Settings/AlphaTest", 2)
|
||||
MaterialPropertyTest("Opacity Settings/Additive", True)
|
||||
|
||||
# Lighting Settings
|
||||
MaterialPropertyTest("Lighting Settings/Diffuse Color", color)
|
||||
MaterialPropertyTest("Lighting Settings/Specular Color", color)
|
||||
MaterialPropertyTest("Lighting Settings/Emissive Intensity", 42.0)
|
||||
MaterialPropertyTest("Lighting Settings/Emissive Color", color)
|
||||
MaterialPropertyTest("Lighting Settings/Specular Level", 2.0)
|
||||
|
||||
# Advanced
|
||||
MaterialPropertyTest("Advanced/Allow layer activation", False)
|
||||
MaterialPropertyTest("Advanced/2 Sided", True)
|
||||
MaterialPropertyTest("Advanced/No Shadow", True)
|
||||
MaterialPropertyTest("Advanced/Use Scattering", True)
|
||||
MaterialPropertyTest("Advanced/Hide After Breaking", True)
|
||||
MaterialPropertyTest("Advanced/Fog Volume Shading Quality High", True)
|
||||
MaterialPropertyTest("Advanced/Blend Terrain Color", True)
|
||||
MaterialPropertyTest("Advanced/Voxel Coverage", 0.42)
|
||||
# --- MaterialPropertyTest("Advanced/Link to Material", "materials/ter_layer_blue") # Works, but clears on UI refresh
|
||||
MaterialPropertyTest("Advanced/Propagate Opacity Settings", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Lighting Settings", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Advanced Settings", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Texture Maps", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Shader Params", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Shader Generation", True)
|
||||
MaterialPropertyTest("Advanced/Propagate Vertex Deformation", True)
|
||||
|
||||
# Shader parameters vary with each Shader, just testing a couple of them...
|
||||
# MaterialPropertyTest("Shader Params/Blend Factor", 7.0, False) # Disabled, SPEC-3590
|
||||
# MaterialPropertyTest("Shader Params/Indirect bounce color", color, False) # Disabled, SPEC-3590
|
||||
|
||||
### These values are reset to False when set. Left them here commented for reference.
|
||||
# MaterialPropertyTest("Shader Generation Params/Dust & Turbulence", True)
|
||||
# MaterialPropertyTest("Shader Generation Params/Receive Shadows", True)
|
||||
# MaterialPropertyTest("Shader Generation Params/UV Vignetting", True)
|
||||
|
||||
# Vertex Deformation
|
||||
MaterialPropertyTest("Vertex Deformation/Type", "Sin Wave")
|
||||
MaterialPropertyTest("Vertex Deformation/Wave Length X", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Level", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Amplitude", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Phase", 42.0)
|
||||
MaterialPropertyTest("Vertex Deformation/Wave X/Frequency", 42.0)
|
||||
|
||||
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
|
||||
@@ -100,7 +100,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
TEST_SERIAL
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
TEST_SUITE periodic
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
@@ -123,7 +123,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/missing_dependency_tests.py
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
TEST_SERIAL
|
||||
TIMEOUT 3600
|
||||
TIMEOUT 1500
|
||||
TEST_SUITE periodic
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessorBatch
|
||||
|
||||
+8
-17
@@ -161,20 +161,6 @@ def run():
|
||||
# Deletion/Undo/Redo test
|
||||
verify_deletion_undo_redo(self.component_name, entity_obj)
|
||||
|
||||
# Area Light Component
|
||||
area_light = "Area Light"
|
||||
ComponentTests(
|
||||
area_light, lambda entity_obj: verify_required_component_addition(
|
||||
entity_obj, ["Capsule Shape"], area_light))
|
||||
|
||||
# Decal Component
|
||||
material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal (Atom)", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# DepthOfField Component
|
||||
camera_entity = hydra.Entity("camera_entity")
|
||||
camera_entity.create_entity(math.Vector3(512.0, 512.0, 34.0), ["Camera"])
|
||||
@@ -185,6 +171,14 @@ def run():
|
||||
lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Camera Entity", camera_entity.id))
|
||||
|
||||
# Decal Component
|
||||
material_asset_path = os.path.join("AutomatedTesting", "Materials", "basic_grey.material")
|
||||
material_asset = asset.AssetCatalogRequestBus(
|
||||
bus.Broadcast, "GetAssetIdByPath", material_asset_path, math.Uuid(), False)
|
||||
ComponentTests(
|
||||
"Decal (Atom)", lambda entity_obj: verify_set_property(
|
||||
entity_obj, "Controller|Configuration|Material", material_asset))
|
||||
|
||||
# Directional Light Component
|
||||
ComponentTests(
|
||||
"Directional Light",
|
||||
@@ -213,9 +207,6 @@ def run():
|
||||
# Physical Sky Component
|
||||
ComponentTests("Physical Sky")
|
||||
|
||||
# Point Light Component
|
||||
ComponentTests("Point Light")
|
||||
|
||||
# PostFX Layer Component
|
||||
ComponentTests("PostFX Layer")
|
||||
|
||||
|
||||
@@ -27,194 +27,6 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsMain(object):
|
||||
|
||||
@pytest.mark.test_case_id(
|
||||
"C32078117", # Area Light
|
||||
"C32078130", # Display Mapper
|
||||
"C32078129", # Light
|
||||
"C32078131", # Radius Weight Modifier
|
||||
"C32078127", # PostFX Layer
|
||||
"C32078126", # Point Light
|
||||
"C32078125", # Physical Sky
|
||||
"C32078115", # Global Skylight (IBL)
|
||||
"C32078121", # Exposure Control
|
||||
"C32078120", # Directional Light
|
||||
"C32078119", # DepthOfField
|
||||
"C32078118") # Decal
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
# Area Light Component
|
||||
"Area Light Entity successfully created",
|
||||
"Area Light_test: Component added to the entity: True",
|
||||
"Area Light_test: Component removed after UNDO: True",
|
||||
"Area Light_test: Component added after REDO: True",
|
||||
"Area Light_test: Entered game mode: True",
|
||||
"Area Light_test: Entity enabled after adding required components: True",
|
||||
"Area Light_test: Entity is hidden: True",
|
||||
"Area Light_test: Entity is shown: True",
|
||||
"Area Light_test: Entity deleted: True",
|
||||
"Area Light_test: UNDO entity deletion works: True",
|
||||
"Area Light_test: REDO entity deletion works: True",
|
||||
# Decal Component
|
||||
"Decal (Atom) Entity successfully created",
|
||||
"Decal (Atom)_test: Component added to the entity: True",
|
||||
"Decal (Atom)_test: Component removed after UNDO: True",
|
||||
"Decal (Atom)_test: Component added after REDO: True",
|
||||
"Decal (Atom)_test: Entered game mode: True",
|
||||
"Decal (Atom)_test: Exit game mode: True",
|
||||
"Decal (Atom) Controller|Configuration|Material: SUCCESS",
|
||||
"Decal (Atom)_test: Entity is hidden: True",
|
||||
"Decal (Atom)_test: Entity is shown: True",
|
||||
"Decal (Atom)_test: Entity deleted: True",
|
||||
"Decal (Atom)_test: UNDO entity deletion works: True",
|
||||
"Decal (Atom)_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
"DepthOfField_test: Component removed after UNDO: True",
|
||||
"DepthOfField_test: Component added after REDO: True",
|
||||
"DepthOfField_test: Entered game mode: True",
|
||||
"DepthOfField_test: Exit game mode: True",
|
||||
"DepthOfField_test: Entity disabled initially: True",
|
||||
"DepthOfField_test: Entity enabled after adding required components: True",
|
||||
"DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
|
||||
"DepthOfField_test: Entity is hidden: True",
|
||||
"DepthOfField_test: Entity is shown: True",
|
||||
"DepthOfField_test: Entity deleted: True",
|
||||
"DepthOfField_test: UNDO entity deletion works: True",
|
||||
"DepthOfField_test: REDO entity deletion works: True",
|
||||
# Directional Light Component
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light_test: Component added to the entity: True",
|
||||
"Directional Light_test: Component removed after UNDO: True",
|
||||
"Directional Light_test: Component added after REDO: True",
|
||||
"Directional Light_test: Entered game mode: True",
|
||||
"Directional Light_test: Exit game mode: True",
|
||||
"Directional Light Controller|Configuration|Shadow|Camera: SUCCESS",
|
||||
"Directional Light_test: Entity is hidden: True",
|
||||
"Directional Light_test: Entity is shown: True",
|
||||
"Directional Light_test: Entity deleted: True",
|
||||
"Directional Light_test: UNDO entity deletion works: True",
|
||||
"Directional Light_test: REDO entity deletion works: True",
|
||||
# Exposure Control Component
|
||||
"Exposure Control Entity successfully created",
|
||||
"Exposure Control_test: Component added to the entity: True",
|
||||
"Exposure Control_test: Component removed after UNDO: True",
|
||||
"Exposure Control_test: Component added after REDO: True",
|
||||
"Exposure Control_test: Entered game mode: True",
|
||||
"Exposure Control_test: Exit game mode: True",
|
||||
"Exposure Control_test: Entity disabled initially: True",
|
||||
"Exposure Control_test: Entity enabled after adding required components: True",
|
||||
"Exposure Control_test: Entity is hidden: True",
|
||||
"Exposure Control_test: Entity is shown: True",
|
||||
"Exposure Control_test: Entity deleted: True",
|
||||
"Exposure Control_test: UNDO entity deletion works: True",
|
||||
"Exposure Control_test: REDO entity deletion works: True",
|
||||
# Global Skylight (IBL) Component
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL)_test: Component added to the entity: True",
|
||||
"Global Skylight (IBL)_test: Component removed after UNDO: True",
|
||||
"Global Skylight (IBL)_test: Component added after REDO: True",
|
||||
"Global Skylight (IBL)_test: Entered game mode: True",
|
||||
"Global Skylight (IBL)_test: Exit game mode: True",
|
||||
"Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
|
||||
"Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
|
||||
"Global Skylight (IBL)_test: Entity is hidden: True",
|
||||
"Global Skylight (IBL)_test: Entity is shown: True",
|
||||
"Global Skylight (IBL)_test: Entity deleted: True",
|
||||
"Global Skylight (IBL)_test: UNDO entity deletion works: True",
|
||||
"Global Skylight (IBL)_test: REDO entity deletion works: True",
|
||||
# Physical Sky Component
|
||||
"Physical Sky Entity successfully created",
|
||||
"Physical Sky component was added to entity",
|
||||
"Entity has a Physical Sky component",
|
||||
"Physical Sky_test: Component added to the entity: True",
|
||||
"Physical Sky_test: Component removed after UNDO: True",
|
||||
"Physical Sky_test: Component added after REDO: True",
|
||||
"Physical Sky_test: Entered game mode: True",
|
||||
"Physical Sky_test: Exit game mode: True",
|
||||
"Physical Sky_test: Entity is hidden: True",
|
||||
"Physical Sky_test: Entity is shown: True",
|
||||
"Physical Sky_test: Entity deleted: True",
|
||||
"Physical Sky_test: UNDO entity deletion works: True",
|
||||
"Physical Sky_test: REDO entity deletion works: True",
|
||||
# Point Light Component
|
||||
"Point Light Entity successfully created",
|
||||
"Point Light_test: Component added to the entity: True",
|
||||
"Point Light_test: Component removed after UNDO: True",
|
||||
"Point Light_test: Component added after REDO: True",
|
||||
"Point Light_test: Entered game mode: True",
|
||||
"Point Light_test: Exit game mode: True",
|
||||
"Point Light_test: Entity is hidden: True",
|
||||
"Point Light_test: Entity is shown: True",
|
||||
"Point Light_test: Entity deleted: True",
|
||||
"Point Light_test: UNDO entity deletion works: True",
|
||||
"Point Light_test: REDO entity deletion works: True",
|
||||
# PostFX Layer Component
|
||||
"PostFX Layer Entity successfully created",
|
||||
"PostFX Layer_test: Component added to the entity: True",
|
||||
"PostFX Layer_test: Component removed after UNDO: True",
|
||||
"PostFX Layer_test: Component added after REDO: True",
|
||||
"PostFX Layer_test: Entered game mode: True",
|
||||
"PostFX Layer_test: Exit game mode: True",
|
||||
"PostFX Layer_test: Entity is hidden: True",
|
||||
"PostFX Layer_test: Entity is shown: True",
|
||||
"PostFX Layer_test: Entity deleted: True",
|
||||
"PostFX Layer_test: UNDO entity deletion works: True",
|
||||
"PostFX Layer_test: REDO entity deletion works: True",
|
||||
# Radius Weight Modifier Component
|
||||
"Radius Weight Modifier Entity successfully created",
|
||||
"Radius Weight Modifier_test: Component added to the entity: True",
|
||||
"Radius Weight Modifier_test: Component removed after UNDO: True",
|
||||
"Radius Weight Modifier_test: Component added after REDO: True",
|
||||
"Radius Weight Modifier_test: Entered game mode: True",
|
||||
"Radius Weight Modifier_test: Exit game mode: True",
|
||||
"Radius Weight Modifier_test: Entity is hidden: True",
|
||||
"Radius Weight Modifier_test: Entity is shown: True",
|
||||
"Radius Weight Modifier_test: Entity deleted: True",
|
||||
"Radius Weight Modifier_test: UNDO entity deletion works: True",
|
||||
"Radius Weight Modifier_test: REDO entity deletion works: True",
|
||||
# Light Component
|
||||
"Light Entity successfully created",
|
||||
"Light_test: Component added to the entity: True",
|
||||
"Light_test: Component removed after UNDO: True",
|
||||
"Light_test: Component added after REDO: True",
|
||||
"Light_test: Entered game mode: True",
|
||||
"Light_test: Exit game mode: True",
|
||||
"Light_test: Entity is hidden: True",
|
||||
"Light_test: Entity is shown: True",
|
||||
"Light_test: Entity deleted: True",
|
||||
"Light_test: UNDO entity deletion works: True",
|
||||
"Light_test: REDO entity deletion works: True",
|
||||
# Display Mapper Component
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper_test: Component added to the entity: True",
|
||||
"Display Mapper_test: Component removed after UNDO: True",
|
||||
"Display Mapper_test: Component added after REDO: True",
|
||||
"Display Mapper_test: Entered game mode: True",
|
||||
"Display Mapper_test: Exit game mode: True",
|
||||
"Display Mapper_test: Entity is hidden: True",
|
||||
"Display Mapper_test: Entity is shown: True",
|
||||
"Display Mapper_test: Entity deleted: True",
|
||||
"Display Mapper_test: UNDO entity deletion works: True",
|
||||
"Display Mapper_test: REDO entity deletion works: True",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"failed to open",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=EDITOR_TIMEOUT,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
# It requires at least one test
|
||||
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
|
||||
@@ -19,6 +19,170 @@ import pytest
|
||||
@pytest.mark.parametrize("level", ["auto_test"])
|
||||
class TestAtomEditorComponentsSandbox(object):
|
||||
|
||||
# It requires at least one test
|
||||
def test_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
@pytest.mark.test_case_id(
|
||||
"C32078117", # Area Light
|
||||
"C32078130", # Display Mapper
|
||||
"C32078129", # Light
|
||||
"C32078131", # Radius Weight Modifier
|
||||
"C32078127", # PostFX Layer
|
||||
"C32078126", # Point Light
|
||||
"C32078125", # Physical Sky
|
||||
"C32078115", # Global Skylight (IBL)
|
||||
"C32078121", # Exposure Control
|
||||
"C32078120", # Directional Light
|
||||
"C32078119", # DepthOfField
|
||||
"C32078118") # Decal
|
||||
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
# Decal Component
|
||||
"Decal (Atom) Entity successfully created",
|
||||
"Decal (Atom)_test: Component added to the entity: True",
|
||||
"Decal (Atom)_test: Component removed after UNDO: True",
|
||||
"Decal (Atom)_test: Component added after REDO: True",
|
||||
"Decal (Atom)_test: Entered game mode: True",
|
||||
"Decal (Atom)_test: Exit game mode: True",
|
||||
"Decal (Atom) Controller|Configuration|Material: SUCCESS",
|
||||
"Decal (Atom)_test: Entity is hidden: True",
|
||||
"Decal (Atom)_test: Entity is shown: True",
|
||||
"Decal (Atom)_test: Entity deleted: True",
|
||||
"Decal (Atom)_test: UNDO entity deletion works: True",
|
||||
"Decal (Atom)_test: REDO entity deletion works: True",
|
||||
# DepthOfField Component
|
||||
"DepthOfField Entity successfully created",
|
||||
"DepthOfField_test: Component added to the entity: True",
|
||||
"DepthOfField_test: Component removed after UNDO: True",
|
||||
"DepthOfField_test: Component added after REDO: True",
|
||||
"DepthOfField_test: Entered game mode: True",
|
||||
"DepthOfField_test: Exit game mode: True",
|
||||
"DepthOfField_test: Entity disabled initially: True",
|
||||
"DepthOfField_test: Entity enabled after adding required components: True",
|
||||
"DepthOfField Controller|Configuration|Camera Entity: SUCCESS",
|
||||
"DepthOfField_test: Entity is hidden: True",
|
||||
"DepthOfField_test: Entity is shown: True",
|
||||
"DepthOfField_test: Entity deleted: True",
|
||||
"DepthOfField_test: UNDO entity deletion works: True",
|
||||
"DepthOfField_test: REDO entity deletion works: True",
|
||||
# Directional Light Component
|
||||
"Directional Light Entity successfully created",
|
||||
"Directional Light_test: Component added to the entity: True",
|
||||
"Directional Light_test: Component removed after UNDO: True",
|
||||
"Directional Light_test: Component added after REDO: True",
|
||||
"Directional Light_test: Entered game mode: True",
|
||||
"Directional Light_test: Exit game mode: True",
|
||||
"Directional Light Controller|Configuration|Shadow|Camera: SUCCESS",
|
||||
"Directional Light_test: Entity is hidden: True",
|
||||
"Directional Light_test: Entity is shown: True",
|
||||
"Directional Light_test: Entity deleted: True",
|
||||
"Directional Light_test: UNDO entity deletion works: True",
|
||||
"Directional Light_test: REDO entity deletion works: True",
|
||||
# Exposure Control Component
|
||||
"Exposure Control Entity successfully created",
|
||||
"Exposure Control_test: Component added to the entity: True",
|
||||
"Exposure Control_test: Component removed after UNDO: True",
|
||||
"Exposure Control_test: Component added after REDO: True",
|
||||
"Exposure Control_test: Entered game mode: True",
|
||||
"Exposure Control_test: Exit game mode: True",
|
||||
"Exposure Control_test: Entity disabled initially: True",
|
||||
"Exposure Control_test: Entity enabled after adding required components: True",
|
||||
"Exposure Control_test: Entity is hidden: True",
|
||||
"Exposure Control_test: Entity is shown: True",
|
||||
"Exposure Control_test: Entity deleted: True",
|
||||
"Exposure Control_test: UNDO entity deletion works: True",
|
||||
"Exposure Control_test: REDO entity deletion works: True",
|
||||
# Global Skylight (IBL) Component
|
||||
"Global Skylight (IBL) Entity successfully created",
|
||||
"Global Skylight (IBL)_test: Component added to the entity: True",
|
||||
"Global Skylight (IBL)_test: Component removed after UNDO: True",
|
||||
"Global Skylight (IBL)_test: Component added after REDO: True",
|
||||
"Global Skylight (IBL)_test: Entered game mode: True",
|
||||
"Global Skylight (IBL)_test: Exit game mode: True",
|
||||
"Global Skylight (IBL) Controller|Configuration|Diffuse Image: SUCCESS",
|
||||
"Global Skylight (IBL) Controller|Configuration|Specular Image: SUCCESS",
|
||||
"Global Skylight (IBL)_test: Entity is hidden: True",
|
||||
"Global Skylight (IBL)_test: Entity is shown: True",
|
||||
"Global Skylight (IBL)_test: Entity deleted: True",
|
||||
"Global Skylight (IBL)_test: UNDO entity deletion works: True",
|
||||
"Global Skylight (IBL)_test: REDO entity deletion works: True",
|
||||
# Physical Sky Component
|
||||
"Physical Sky Entity successfully created",
|
||||
"Physical Sky component was added to entity",
|
||||
"Entity has a Physical Sky component",
|
||||
"Physical Sky_test: Component added to the entity: True",
|
||||
"Physical Sky_test: Component removed after UNDO: True",
|
||||
"Physical Sky_test: Component added after REDO: True",
|
||||
"Physical Sky_test: Entered game mode: True",
|
||||
"Physical Sky_test: Exit game mode: True",
|
||||
"Physical Sky_test: Entity is hidden: True",
|
||||
"Physical Sky_test: Entity is shown: True",
|
||||
"Physical Sky_test: Entity deleted: True",
|
||||
"Physical Sky_test: UNDO entity deletion works: True",
|
||||
"Physical Sky_test: REDO entity deletion works: True",
|
||||
# PostFX Layer Component
|
||||
"PostFX Layer Entity successfully created",
|
||||
"PostFX Layer_test: Component added to the entity: True",
|
||||
"PostFX Layer_test: Component removed after UNDO: True",
|
||||
"PostFX Layer_test: Component added after REDO: True",
|
||||
"PostFX Layer_test: Entered game mode: True",
|
||||
"PostFX Layer_test: Exit game mode: True",
|
||||
"PostFX Layer_test: Entity is hidden: True",
|
||||
"PostFX Layer_test: Entity is shown: True",
|
||||
"PostFX Layer_test: Entity deleted: True",
|
||||
"PostFX Layer_test: UNDO entity deletion works: True",
|
||||
"PostFX Layer_test: REDO entity deletion works: True",
|
||||
# Radius Weight Modifier Component
|
||||
"Radius Weight Modifier Entity successfully created",
|
||||
"Radius Weight Modifier_test: Component added to the entity: True",
|
||||
"Radius Weight Modifier_test: Component removed after UNDO: True",
|
||||
"Radius Weight Modifier_test: Component added after REDO: True",
|
||||
"Radius Weight Modifier_test: Entered game mode: True",
|
||||
"Radius Weight Modifier_test: Exit game mode: True",
|
||||
"Radius Weight Modifier_test: Entity is hidden: True",
|
||||
"Radius Weight Modifier_test: Entity is shown: True",
|
||||
"Radius Weight Modifier_test: Entity deleted: True",
|
||||
"Radius Weight Modifier_test: UNDO entity deletion works: True",
|
||||
"Radius Weight Modifier_test: REDO entity deletion works: True",
|
||||
# Light Component
|
||||
"Light Entity successfully created",
|
||||
"Light_test: Component added to the entity: True",
|
||||
"Light_test: Component removed after UNDO: True",
|
||||
"Light_test: Component added after REDO: True",
|
||||
"Light_test: Entered game mode: True",
|
||||
"Light_test: Exit game mode: True",
|
||||
"Light_test: Entity is hidden: True",
|
||||
"Light_test: Entity is shown: True",
|
||||
"Light_test: Entity deleted: True",
|
||||
"Light_test: UNDO entity deletion works: True",
|
||||
"Light_test: REDO entity deletion works: True",
|
||||
# Display Mapper Component
|
||||
"Display Mapper Entity successfully created",
|
||||
"Display Mapper_test: Component added to the entity: True",
|
||||
"Display Mapper_test: Component removed after UNDO: True",
|
||||
"Display Mapper_test: Component added after REDO: True",
|
||||
"Display Mapper_test: Entered game mode: True",
|
||||
"Display Mapper_test: Exit game mode: True",
|
||||
"Display Mapper_test: Entity is hidden: True",
|
||||
"Display Mapper_test: Entity is shown: True",
|
||||
"Display Mapper_test: Entity deleted: True",
|
||||
"Display Mapper_test: UNDO entity deletion works: True",
|
||||
"Display Mapper_test: REDO entity deletion works: True",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"failed to open",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_AddedToEntity.py",
|
||||
timeout=EDITOR_TIMEOUT,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
+5
-12
@@ -114,11 +114,8 @@ class TestDynamicSliceInstanceSpawner(EditorTestHelper):
|
||||
# This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
|
||||
# 20 instances per 16 meters
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', True)
|
||||
general.idle_wait(1.0)
|
||||
num_expected_instances = 20 * 20
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
property_tree_success = property_tree_success and (num_found == num_expected_instances)
|
||||
property_tree_success = property_tree_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and property_tree_success
|
||||
self.log(f'Property Tree spawner type test: {property_tree_success}')
|
||||
|
||||
@@ -127,10 +124,8 @@ class TestDynamicSliceInstanceSpawner(EditorTestHelper):
|
||||
# Since we have an empty slice path, we should have 0 instances once we disable 'Allow Empty Assets'
|
||||
num_expected_instances = 0
|
||||
allow_empty_assets_success = allow_empty_assets_success and spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
general.idle_wait(1.0)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
self.log(f'Allow Empty Assets test: Found {num_found} instances -- Expected {num_expected_instances} instances')
|
||||
allow_empty_assets_success = allow_empty_assets_success and (num_found == num_expected_instances)
|
||||
self.log('Allow Empty Assets test:')
|
||||
allow_empty_assets_success = allow_empty_assets_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and allow_empty_assets_success
|
||||
self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
|
||||
@@ -143,10 +138,8 @@ class TestDynamicSliceInstanceSpawner(EditorTestHelper):
|
||||
descriptor = hydra.get_component_property_value(spawner_entity.components[2], 'Configuration|Embedded Assets|[0]')
|
||||
descriptor.spawner = dynamic_slice_spawner
|
||||
spawns_slices_success = spawns_slices_success and spawner_entity.get_set_test(2, "Configuration|Embedded Assets|[0]", descriptor)
|
||||
general.idle_wait(1.0)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
self.log(f'Spawn dynamic slices test: Found {num_found} instances -- Expected {num_expected_instances} instances')
|
||||
spawns_slices_success = spawns_slices_success and (num_found == num_expected_instances)
|
||||
self.log('Spawn dynamic slices test:')
|
||||
spawns_slices_success = spawns_slices_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and spawns_slices_success
|
||||
self.log(f'Spawn dynamic slices test: {spawns_slices_success}')
|
||||
|
||||
|
||||
+2
-8
@@ -100,21 +100,15 @@ class TestEmptyInstanceSpawner(EditorTestHelper):
|
||||
|
||||
# This should result in 400 instances, since our box is 16 m x 16 m and by default the veg system plants
|
||||
# 20 instances per 16 meters
|
||||
general.idle_wait(2.0)
|
||||
num_expected_instances = 20 * 20
|
||||
box = azlmbr.shape.ShapeComponentRequestsBus(bus.Event, 'GetEncompassingAabb', spawner_entity.id)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
property_tree_success = property_tree_success and (num_found == num_expected_instances)
|
||||
property_tree_success = property_tree_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and property_tree_success
|
||||
self.log(f'Found {num_found} instances -- Expected {num_expected_instances} instances')
|
||||
self.log(f'Property Tree spawner type test: {property_tree_success}')
|
||||
|
||||
# 6) Validate that the "Allow Empty Assets" setting doesn't affect the EmptyInstanceSpawner
|
||||
allow_empty_assets_success = True
|
||||
spawner_entity.get_set_test(0, 'Configuration|Allow Empty Assets', False)
|
||||
general.idle_wait(2.0)
|
||||
num_found = azlmbr.areasystem.AreaSystemRequestBus(bus.Broadcast, 'GetInstanceCountInAabb', box)
|
||||
allow_empty_assets_success = allow_empty_assets_success and (num_found == num_expected_instances)
|
||||
allow_empty_assets_success = allow_empty_assets_success and self.wait_for_condition(lambda: dynveg.validate_instance_count_in_entity_shape(spawner_entity.id, num_expected_instances), 5.0)
|
||||
self.test_success = self.test_success and allow_empty_assets_success
|
||||
self.log(f'Allow Empty Assets test: {allow_empty_assets_success}')
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ class TestAltitudeFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id('C4814463', 'C4847477')
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_AltitudeFilter_ComponentAndOverrides_InstancesPlantAtSpecifiedAltitude(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
@@ -61,6 +62,7 @@ class TestAltitudeFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4847476")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_AltitudeFilter_ShapeSample_InstancesPlantAtSpecifiedAltitude(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
@@ -85,6 +87,7 @@ class TestAltitudeFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4847478")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
@pytest.mark.xfail # LYN-3275
|
||||
def test_AltitudeFilter_FilterStageToggle(self, request, editor, level, workspace, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
@@ -52,6 +52,7 @@ class TestAreaComponents(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2627900", "C2627905", "C2627904")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_AreaComponents_SliceCreationVisibilityToggleWorks(self, request, editor, level, workspace,
|
||||
launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestAssetListCombiner(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4762374", "C4762373")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_AssetListCombiner_CombinedDescriptorsExpressInConfiguredArea(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ class TestAssetWeightSelector(object):
|
||||
|
||||
@pytest.mark.test_case_id("C6269654", "C4762368")
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_AssetWeightSelector_InstancesExpressBasedOnWeight(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -40,6 +40,7 @@ class TestDebugger(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2789148")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_Debugger_DebugCVarsWork(self, request, editor, level, workspace, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestDistanceBetweenFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4851066")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_DistanceBetweenFilter_InstancesPlantAtSpecifiedRadius(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -58,6 +59,7 @@ class TestDistanceBetweenFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4814458")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_DistanceBetweenFilterOverrides_InstancesPlantAtSpecifiedRadius(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ class Test_DynVeg_Regressions(object):
|
||||
|
||||
@pytest.mark.test_case_id("C29470845")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_regression
|
||||
def test_SurfaceDataRefreshes_RemainsStable(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
+6
-1
@@ -41,7 +41,8 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
return console
|
||||
|
||||
@pytest.mark.test_case_id("C28851763")
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
def test_DynamicSliceInstanceSpawner_DynamicSliceSpawnerWorks(self, request, editor, level, workspace, project,
|
||||
launcher_platform):
|
||||
@@ -66,6 +67,7 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
@pytest.mark.test_case_id('C2574330')
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
def test_DynamicSliceInstanceSpawner_Embedded_E2E_Editor(self, workspace, request, editor, level, project,
|
||||
launcher_platform):
|
||||
@@ -85,6 +87,7 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
@pytest.mark.test_case_id('C2574330')
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows'])
|
||||
@pytest.mark.skip # ATOM-14703
|
||||
def test_DynamicSliceInstanceSpawner_Embedded_E2E_Launcher(self, workspace, launcher, level,
|
||||
@@ -101,6 +104,7 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
|
||||
@pytest.mark.test_case_id('C4762367')
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
def test_DynamicSliceInstanceSpawner_External_E2E_Editor(self, workspace, request, editor, level, project,
|
||||
launcher_platform):
|
||||
@@ -119,6 +123,7 @@ class TestDynamicSliceInstanceSpawner(object):
|
||||
|
||||
@pytest.mark.test_case_id('C4762367')
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows'])
|
||||
@pytest.mark.skip # ATOM-14703
|
||||
def test_DynamicSliceInstanceSpawner_External_E2E_Launcher(self, workspace, launcher, level,
|
||||
|
||||
@@ -36,13 +36,9 @@ class TestEmptyInstanceSpawner(object):
|
||||
|
||||
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
|
||||
|
||||
# Main suite needs at least one test
|
||||
@pytest.mark.SUITE_main
|
||||
def test_EmptyInstanceSpawner_Dummy(self, request, editor, level, workspace, project, launcher_platform):
|
||||
pass
|
||||
|
||||
@pytest.mark.test_case_id("C28851762")
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
def test_EmptyInstanceSpawner_EmptySpawnerWorks(self, request, editor, level, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class TestInstanceSpawnerPriority(object):
|
||||
|
||||
@pytest.mark.test_case_id("C5747383", "C4762382")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_InstanceSpawnerPriority_LayerAndSubPriority_HigherValuesPlantOverLower(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
|
||||
@@ -20,17 +20,10 @@ import pytest
|
||||
|
||||
pytest.importorskip("ly_test_tools")
|
||||
|
||||
import time as time
|
||||
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
import ly_test_tools.launchers.launcher_helper as launcher_helper
|
||||
import ly_remote_console.remote_console_commands as remote_console_commands
|
||||
import ly_test_tools.environment.waiter as waiter
|
||||
import ly_test_tools.environment.file_system as file_system
|
||||
import ly_remote_console.remote_console_commands as remote_console_commands
|
||||
from ly_remote_console.remote_console_commands import send_command_and_expect_response as send_command_and_expect_response
|
||||
|
||||
import automatedtesting_shared.screenshot_utils as screenshot_utils
|
||||
from automatedtesting_shared.network_utils import check_for_listening_port
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
|
||||
|
||||
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
|
||||
@@ -58,6 +51,7 @@ class TestLayerBlender(object):
|
||||
@pytest.mark.test_case_id("C2627906")
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
def test_LayerBlender_E2E_Editor(self, workspace, request, editor, project, level, launcher_platform):
|
||||
# Make sure temp level doesn't already exist
|
||||
@@ -95,6 +89,7 @@ class TestLayerBlender(object):
|
||||
@pytest.mark.test_case_id("C2627906")
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.xfail
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows'])
|
||||
def test_LayerBlender_E2E_Launcher(self, workspace, project, launcher, level, remote_console_instance,
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestLayerBlocker(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2793772")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
def test_LayerBlocker_InstancesBlockedInConfiguredArea(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -40,6 +40,7 @@ class TestLayerSpawner(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4762381")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_LayerSpawner_InheritBehaviorFlag(self, request, editor, level, workspace, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -60,6 +61,7 @@ class TestLayerSpawner(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2802020")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_LayerSpawner_InstancesPlantInAllSupportedShapes(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -101,6 +103,7 @@ class TestLayerSpawner(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4765973")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
@pytest.mark.xfail # LYN-3275
|
||||
def test_LayerSpawner_FilterStageToggle(self, request, editor, level, workspace, launcher_platform):
|
||||
|
||||
@@ -122,6 +125,7 @@ class TestLayerSpawner(object):
|
||||
|
||||
@pytest.mark.test_case_id("C30000751")
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.dynveg_misc
|
||||
@pytest.mark.skip # ATOM-14828
|
||||
def test_LayerSpawner_InstancesRefreshUsingCorrectViewportCamera(self, request, editor, level, launcher_platform):
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class TestMeshBlocker(object):
|
||||
"""
|
||||
@pytest.mark.test_case_id("C3980834")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.xfail # LYN-3273
|
||||
def test_MeshBlocker_InstancesBlockedByMesh(self, request, editor, level, launcher_platform):
|
||||
expected_lines = [
|
||||
@@ -70,6 +71,7 @@ class TestMeshBlocker(object):
|
||||
"""
|
||||
@pytest.mark.test_case_id("C4766030")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_area
|
||||
@pytest.mark.xfail # LYN-3273
|
||||
def test_MeshBlocker_InstancesBlockedByMeshHeightTuning(self, request, editor, level, launcher_platform):
|
||||
expected_lines = [
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestMeshSurfaceTagEmitter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2908172")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_surfacetagemitter
|
||||
def test_MeshSurfaceTagEmitter_DependentOnMeshComponent(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -66,6 +67,7 @@ class TestMeshSurfaceTagEmitter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2908174")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_surfacetagemitter
|
||||
def test_MeshSurfaceTagEmitter_SurfaceTagsAddRemoveSuccessfully(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ class TestPhysXColliderSurfaceTagEmitter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C29053640")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_surfacetagemitter
|
||||
def test_PhysXColliderSurfaceTagEmitter_E2E_Editor(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestPositionModifier(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4874099", "C4814461")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
def test_PositionModifier_ComponentAndOverrides_InstancesPlantAtSpecifiedOffsets(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
@@ -60,6 +61,7 @@ class TestPositionModifier(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4874100")
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.dynveg_modifier
|
||||
@pytest.mark.xfail # LYN-3275
|
||||
def test_PositionModifier_AutoSnapToSurfaceWorks(self, request, editor, level, launcher_platform):
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ class TestRotationModifier(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4896922")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
def test_RotationModifier_InstancesRotateWithinRange(self, request, editor, level, launcher_platform) -> None:
|
||||
"""
|
||||
Launches editor and run test script to test that rotation modifier works for all axis.
|
||||
@@ -71,6 +72,7 @@ class TestRotationModifier(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4814460")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
def test_RotationModifierOverrides_InstancesRotateWithinRange(self, request, editor, level, launcher_platform) -> None:
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -41,6 +41,7 @@ class TestScaleOverrideWorksSuccessfully(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4814462")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
def test_ScaleModifierOverrides_InstancesProperlyScale(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -70,6 +71,7 @@ class TestScaleOverrideWorksSuccessfully(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4896937")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
def test_ScaleModifier_InstancesProperlyScale(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestShapeIntersectionFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4874094")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_ShapeIntersectionFilter_InstancesPlantInAssignedShape(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
@@ -41,6 +41,7 @@ class TestSlopeAlignmentModifier(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4896941")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
@pytest.mark.skip # ATOM-14299
|
||||
def test_SlopeAlignmentModifier_InstanceSurfaceAlignment(self, request, editor, level, launcher_platform):
|
||||
|
||||
@@ -63,6 +64,7 @@ class TestSlopeAlignmentModifier(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4814459")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_modifier
|
||||
@pytest.mark.skip # ATOM-14299
|
||||
def test_SlopeAlignmentModifierOverrides_InstanceSurfaceAlignment(self, request, editor, level, launcher_platform):
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ class TestSlopeFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4874097")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_SlopeFilter_FilterStageToggle(self, request, editor, level, workspace, launcher_platform):
|
||||
cfg_args = [level]
|
||||
|
||||
@@ -70,6 +71,7 @@ class TestSlopeFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C4814464", "C4874096")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
@pytest.mark.skip # LYN-2211
|
||||
def test_SlopeFilter_ComponentAndOverrides_InstancesPlantOnValidSlopes(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
@@ -40,6 +40,7 @@ class TestSurfaceMaskFilter(object):
|
||||
|
||||
# Simple validation test to ensure that SurfaceTag can be created, set to a value, and compared to another SurfaceTag.
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_SurfaceMaskFilter_BasicSurfaceTagCreation(self, request, level, editor, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -61,6 +62,7 @@ class TestSurfaceMaskFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2561342")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_SurfaceMaskFilter_ExclusiveSurfaceTags_Function(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -93,6 +95,7 @@ class TestSurfaceMaskFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2561341")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_SurfaceMaskFilter_InclusiveSurfaceTags_Function(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -125,6 +128,7 @@ class TestSurfaceMaskFilter(object):
|
||||
|
||||
@pytest.mark.test_case_id("C3711666")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_filter
|
||||
def test_SurfaceMaskFilterOverrides_MultipleDescriptorOverridesPlantAsExpected(self, request, editor, level,
|
||||
launcher_platform):
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class TestSystemSettings(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2646869")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_SystemSettings_SectorPointDensity(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
@@ -64,6 +65,7 @@ class TestSystemSettings(object):
|
||||
|
||||
@pytest.mark.test_case_id("C2646870")
|
||||
@pytest.mark.SUITE_periodic
|
||||
@pytest.mark.dynveg_misc
|
||||
def test_SystemSettings_SectorSize(self, request, editor, level, launcher_platform):
|
||||
|
||||
expected_lines = [
|
||||
|
||||
+25
-5
@@ -57,6 +57,7 @@ def C18243589_Joints_BallSoftLimitsConstrained():
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import math
|
||||
|
||||
import ImportPathHelper as imports
|
||||
|
||||
@@ -95,13 +96,33 @@ def C18243589_Joints_BallSoftLimitsConstrained():
|
||||
Report.info_vector3(follower.position, "follower initial position:")
|
||||
leadInitialPosition = lead.position
|
||||
followerInitialPosition = follower.position
|
||||
|
||||
followerMovedAboveJoint = False
|
||||
#calculate the start vector from follower and lead positions
|
||||
normalizedStartPos = JointsHelper.getRelativeVector(lead.position, follower.position)
|
||||
normalizedStartPos = normalizedStartPos.GetNormalizedSafe()
|
||||
#the targeted angle to reach between the initial vector and the current follower-lead vector
|
||||
TARGET_ANGLE_DEG = 45
|
||||
targetAngle = math.radians(TARGET_ANGLE_DEG)
|
||||
angleAchieved = 0.0
|
||||
|
||||
# 4) Wait for several seconds
|
||||
general.idle_wait(1.0) # wait for lead and follower to move
|
||||
def checkAngleMet():
|
||||
#calculate the current follower-lead vector
|
||||
normalVec = JointsHelper.getRelativeVector(lead.position, follower.position)
|
||||
normalVec = normalVec.GetNormalizedSafe()
|
||||
#dot product + acos to get the angle
|
||||
angleAchieved = math.acos(normalizedStartPos.Dot(normalVec))
|
||||
#is it above target?
|
||||
return angleAchieved > targetAngle
|
||||
|
||||
MAX_WAIT_TIME = 2.0 #seconds
|
||||
followerMovedAboveJoint = helper.wait_for_condition(checkAngleMet, MAX_WAIT_TIME)
|
||||
|
||||
# 5) Check to see if lead and follower behaved as expected
|
||||
Report.info_vector3(lead.position, "lead position after 1 second:")
|
||||
Report.info_vector3(follower.position, "follower position after 1 second:")
|
||||
Report.info_vector3(lead.position, "lead position:")
|
||||
Report.info_vector3(follower.position, "follower position:")
|
||||
angleAchievedDeg = math.degrees(angleAchieved)
|
||||
Report.info(f"Angle achieved {angleAchievedDeg:.2f} Target {TARGET_ANGLE_DEG:.2f}")
|
||||
|
||||
leadPositionDelta = lead.position.Subtract(leadInitialPosition)
|
||||
leadRemainedStill = JointsHelper.vector3SmallerThanScalar(leadPositionDelta, FLOAT_EPSILON)
|
||||
@@ -111,7 +132,6 @@ def C18243589_Joints_BallSoftLimitsConstrained():
|
||||
followerMovedinXYZ = JointsHelper.vector3LargerThanScalar(followerPositionDelta, FLOAT_EPSILON)
|
||||
Report.critical_result(Tests.check_follower_position, followerMovedinXYZ)
|
||||
|
||||
followerMovedAboveJoint = follower.position.z > (followerInitialPosition.z + 2.5) # (followerInitialPosition.z + 2.5) is the z position past the 45 degree limit. This is to show that the follower swinged past the 45 degree cone limit, above the joint position.
|
||||
Report.critical_result(Tests.check_follower_above_joint, followerMovedAboveJoint)
|
||||
|
||||
# 6) Exit Game Mode
|
||||
|
||||
+38
-15
@@ -20,7 +20,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
class Tests():
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
find_cylinder = ("Cylinder entity found", "Cylinder entity not found")
|
||||
find_terrain = ("Terrain found", "Terrain not found")
|
||||
create_terrain = ("Terrain entity created successfully", "Failed to create Terrain Entity")
|
||||
find_terrain = ("Terrain entity found", "Terrain entity not found")
|
||||
add_physx_shape_collider = ("Added PhysX Shape Collider", "Failed to add PhysX Shape Collider")
|
||||
add_box_shape = ("Added Box Shape", "Failed to add Box Shape")
|
||||
cylinder_above_terrain = ("Cylinder position above ground", "Cylinder is not above the ground")
|
||||
time_out = ("No time out occurred", "A time out occurred, please validate level setup")
|
||||
touched_ground = ("Touched ground before time out", "Did not touch ground before time out")
|
||||
@@ -40,11 +43,12 @@ def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
|
||||
Once game mode is entered, the cylinder should fall toward and collide with the terrain.
|
||||
|
||||
Steps:
|
||||
1) Open level and enter game mode
|
||||
2) Retrieve entities and positions
|
||||
3) Wait for cylinder to collide with terrain OR time out
|
||||
4) Exit game mode
|
||||
5) Close the editor
|
||||
1) Open level and create terrain Entity.
|
||||
2) Enter Game Mode.
|
||||
3) Retrieve entities and positions
|
||||
4) Wait for cylinder to collide with terrain OR time out
|
||||
5) Exit game mode
|
||||
6) Close the editor
|
||||
|
||||
:return:
|
||||
"""
|
||||
@@ -54,29 +58,48 @@ def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
|
||||
import ImportPathHelper as imports
|
||||
|
||||
imports.init()
|
||||
|
||||
from editor_python_test_tools.editor_entity_utils import EditorEntity
|
||||
import azlmbr.legacy.general as general
|
||||
import azlmbr.bus
|
||||
import azlmbr.math as math
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
|
||||
# Global time out
|
||||
TIME_OUT = 1.0
|
||||
|
||||
# 1) Open level / Enter game mode
|
||||
# 1) Open level
|
||||
helper.init_idle()
|
||||
helper.open_level("Physics", "C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain")
|
||||
|
||||
# Create terrain entity
|
||||
terrain = EditorEntity.create_editor_entity_at([30.0, 30.0, 33.96], "Terrain")
|
||||
Report.result(Tests.create_terrain, terrain.id.IsValid())
|
||||
|
||||
terrain.add_component("PhysX Shape Collider")
|
||||
Report.result(Tests.add_physx_shape_collider, terrain.has_component("PhysX Shape Collider"))
|
||||
|
||||
box_shape_component = terrain.add_component("Box Shape")
|
||||
Report.result(Tests.add_box_shape, terrain.has_component("Box Shape"))
|
||||
|
||||
box_shape_component.set_component_property_value("Box Shape|Box Configuration|Dimensions",
|
||||
math.Vector3(1024.0, 1024.0, 0.01))
|
||||
|
||||
# 2)Enter game mode
|
||||
helper.enter_game_mode(Tests.enter_game_mode)
|
||||
|
||||
# 2) Retrieve entities and positions
|
||||
# 3) Retrieve entities and positions
|
||||
cylinder_id = general.find_game_entity("PhysX_Cylinder")
|
||||
Report.critical_result(Tests.find_cylinder, cylinder_id.IsValid())
|
||||
|
||||
|
||||
terrain_id = general.find_game_entity("Terrain")
|
||||
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
|
||||
|
||||
terrain_id = general.find_game_entity("PhysX_Terrain")
|
||||
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
|
||||
|
||||
cylinder_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTM", cylinder_id).GetPosition()
|
||||
terrain_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTM", terrain_id).GetPosition()
|
||||
cylinder_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", cylinder_id)
|
||||
#Cylinder position is 64,84,35
|
||||
terrain_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", terrain_id)
|
||||
Report.info_vector3(cylinder_pos, "Cylinder:")
|
||||
Report.info_vector3(terrain_pos, "Terrain:")
|
||||
Report.critical_result(
|
||||
@@ -104,13 +127,13 @@ def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
|
||||
handler.connect(cylinder_id)
|
||||
handler.add_callback("OnCollisionBegin", on_collision_begin)
|
||||
|
||||
# 3) Wait for the cylinder to hit the ground OR time out
|
||||
# 4) Wait for the cylinder to hit the ground OR time out
|
||||
test_completed = helper.wait_for_condition((lambda: TouchGround.value), TIME_OUT)
|
||||
|
||||
Report.critical_result(Tests.time_out, test_completed)
|
||||
Report.result(Tests.touched_ground, TouchGround.value)
|
||||
|
||||
# 4) Exit game mode
|
||||
# 5) Exit game mode
|
||||
helper.exit_game_mode(Tests.exit_game_mode)
|
||||
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ def C5932042_PhysXForceRegion_LinearDamping():
|
||||
|
||||
# Constants
|
||||
CLOSE_ENOUGH = 0.001
|
||||
TIME_OUT = 2.0
|
||||
TIME_OUT = 3.0
|
||||
INITIAL_VELOCITY = azmath.Vector3(0.0, 0.0, -10.0)
|
||||
|
||||
# 1) Open level / Enter game mode
|
||||
|
||||
@@ -27,6 +27,13 @@ def vector3LargerThanScalar(vec3Value, scalarValue):
|
||||
vec3Value.y > scalarValue and
|
||||
vec3Value.z > scalarValue)
|
||||
|
||||
def getRelativeVector(vecA, vecB):
|
||||
relativeVec = vecA
|
||||
relativeVec.x = relativeVec.x - vecB.x
|
||||
relativeVec.y = relativeVec.y - vecB.y
|
||||
relativeVec.z = relativeVec.z - vecB.z
|
||||
return relativeVec
|
||||
|
||||
|
||||
# Entity class for joints tests
|
||||
class JointEntity:
|
||||
|
||||
@@ -34,4 +34,61 @@ class TestAutomation(TestAutomationBase):
|
||||
|
||||
def test_C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC(self, request, workspace, editor, launcher_platform):
|
||||
from . import C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4044459_Material_DynamicFriction(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4044459_Material_DynamicFriction as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4976243_Collision_SameCollisionGroupDiffCollisionLayers(self, request, workspace, editor,
|
||||
launcher_platform):
|
||||
from . import C4976243_Collision_SameCollisionGroupDiffCollisionLayers as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C14654881_CharacterController_SwitchLevels(self, request, workspace, editor, launcher_platform):
|
||||
from . import C14654881_CharacterController_SwitchLevels as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_C17411467_AddPhysxRagdollComponent(self, request, workspace, editor, launcher_platform):
|
||||
from . import C17411467_AddPhysxRagdollComponent as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12712453_ScriptCanvas_MultipleRaycastNode(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12712453_ScriptCanvas_MultipleRaycastNode as test_module
|
||||
# Fixme: unexpected_lines = ["Assert"] + test_module.Lines.unexpected
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C4982593_PhysXCollider_CollisionLayer.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C4982593_PhysXCollider_CollisionLayerTest(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982593_PhysXCollider_CollisionLayerTest as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C18243586_Joints_HingeLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
|
||||
from . import C18243586_Joints_HingeLeadFollowerCollide as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982803_Enable_PxMesh_Option(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982803_Enable_PxMesh_Option as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain(self, request, workspace, editor, launcher_platform):
|
||||
from . import C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
@@ -52,11 +52,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4976207_PhysXRigidBodies_KinematicBehavior as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932041_PhysXForceRegion_LocalSpaceForceOnRigidBodies as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932042_PhysXForceRegion_LinearDamping(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932042_PhysXForceRegion_LinearDamping as test_module
|
||||
@@ -92,11 +87,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4976194_RigidBody_PhysXComponentIsValid as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4044459_Material_DynamicFriction(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4044459_Material_DynamicFriction as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5932045_ForceRegion_Spline(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5932045_ForceRegion_Spline as test_module
|
||||
@@ -208,26 +198,11 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C18981526_Material_RestitutionCombinePriority as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15308217_NoCrash_LevelSwitch(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15308217_NoCrash_LevelSwitch as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12868580_ForceRegion_SplineModifiedTransform(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12868580_ForceRegion_SplineModifiedTransform as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4976243_Collision_SameCollisionGroupDiffCollisionLayers(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4976243_Collision_SameCollisionGroupDiffCollisionLayers as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12712455_ScriptCanvas_ShapeCastVerification(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12712455_ScriptCanvas_ShapeCastVerification as test_module
|
||||
@@ -248,17 +223,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C6131473_StaticSlice_OnDynamicSliceSpawn as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982798_Collider_ColliderRotationOffset(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982798_Collider_ColliderRotationOffset as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C12712453_ScriptCanvas_MultipleRaycastNode(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12712453_ScriptCanvas_MultipleRaycastNode as test_module
|
||||
# Fixme: unexpected_lines = ["Assert"] + test_module.Lines.unexpected
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5959808_ForceRegion_PositionOffset(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5959808_ForceRegion_PositionOffset as test_module
|
||||
@@ -275,7 +239,7 @@ class TestAutomation(TestAutomationBase):
|
||||
def test_C13895144_Ragdoll_ChangeLevel(self, request, workspace, editor, launcher_platform):
|
||||
from . import C13895144_Ragdoll_ChangeLevel as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
|
||||
@revert_physics_config
|
||||
def test_C5968759_ForceRegion_ExertsSeveralForcesOnRigidBody(self, request, workspace, editor, launcher_platform):
|
||||
from . import C5968759_ForceRegion_ExertsSeveralForcesOnRigidBody as test_module
|
||||
@@ -290,6 +254,8 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4044697_Material_PerfaceMaterialValidation as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason="This test will sometimes fail as the ball will continue to roll before the timeout is reached.")
|
||||
@revert_physics_config
|
||||
def test_C4976202_RigidBody_StopsWhenBelowKineticThreshold(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4976202_RigidBody_StopsWhenBelowKineticThreshold as test_module
|
||||
@@ -305,11 +271,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C5296614_PhysXMaterial_ColliderShape as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C6090547_ForceRegion_ParentChildForceRegions(self, request, workspace, editor, launcher_platform):
|
||||
from . import C6090547_ForceRegion_ParentChildForceRegions as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982595_Collider_TriggerDisablesCollision(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982595_Collider_TriggerDisablesCollision as test_module
|
||||
@@ -320,11 +281,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C14976307_Gravity_SetGravityWorks as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C14654881_CharacterController_SwitchLevels(self, request, workspace, editor, launcher_platform):
|
||||
from . import C14654881_CharacterController_SwitchLevels as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15556261_PhysXMaterials_CharacterControllerMaterialAssignment(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15556261_PhysXMaterials_CharacterControllerMaterialAssignment as test_module
|
||||
@@ -374,18 +330,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4044461_Material_Restitution as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C4982593_PhysXCollider_CollisionLayer.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C4982593_PhysXCollider_CollisionLayerTest(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982593_PhysXCollider_CollisionLayerTest as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C3510644_Collider_CollisionGroups.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C3510644_Collider_CollisionGroups(self, request, workspace, editor, launcher_platform):
|
||||
from . import C3510644_Collider_CollisionGroups as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxdefaultsceneconfiguration.setreg','C14902097_ScriptCanvas_PreUpdateEvent.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C14902097_ScriptCanvas_PreUpdateEvent(self, request, workspace, editor, launcher_platform):
|
||||
@@ -415,11 +359,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C18243589_Joints_BallSoftLimitsConstrained as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C18243586_Joints_HingeLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
|
||||
from . import C18243586_Joints_HingeLeadFollowerCollide as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C18243591_Joints_BallLeadFollowerCollide(self, request, workspace, editor, launcher_platform):
|
||||
from . import C18243591_Joints_BallLeadFollowerCollide as test_module
|
||||
@@ -441,21 +380,11 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C14861500_DefaultSetting_ColliderShape as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C19578021_ShapeCollider_CanBeAdded(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19578021_ShapeCollider_CanBeAdded as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C19723164_ShapeCollider_WontCrashEditor(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19723164_ShapeColliders_WontCrashEditor as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982803_Enable_PxMesh_Option(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982803_Enable_PxMesh_Option as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982800_PhysXColliderShape_CanBeSelected(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982800_PhysXColliderShape_CanBeSelected as test_module
|
||||
@@ -471,10 +400,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from . import C4982802_PhysXColliderShape_CanBeSelected as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_C17411467_AddPhysxRagdollComponent(self, request, workspace, editor, launcher_platform):
|
||||
from . import C17411467_AddPhysxRagdollComponent as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_C12905528_ForceRegion_WithNonTriggerCollider(self, request, workspace, editor, launcher_platform):
|
||||
from . import C12905528_ForceRegion_WithNonTriggerCollider as test_module
|
||||
# Fixme: expected_lines = ["[Warning] (PhysX Force Region) - Please ensure collider component marked as trigger exists in entity"]
|
||||
@@ -522,4 +447,35 @@ class TestAutomation(TestAutomationBase):
|
||||
|
||||
def test_C100000_RigidBody_EnablingGravityWorksPoC(self, request, workspace, editor, launcher_platform):
|
||||
from . import C100000_RigidBody_EnablingGravityWorksPoC as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
@fm.file_override('physxsystemconfiguration.setreg','C3510644_Collider_CollisionGroups.setreg', 'AutomatedTesting/Registry')
|
||||
def test_C3510644_Collider_CollisionGroups(self, request, workspace, editor, launcher_platform):
|
||||
from . import C3510644_Collider_CollisionGroups as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C4982798_Collider_ColliderRotationOffset(self, request, workspace, editor, launcher_platform):
|
||||
from . import C4982798_Collider_ColliderRotationOffset as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15308217_NoCrash_LevelSwitch(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15308217_NoCrash_LevelSwitch as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C6090547_ForceRegion_ParentChildForceRegions(self, request, workspace, editor, launcher_platform):
|
||||
from . import C6090547_ForceRegion_ParentChildForceRegions as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C19578021_ShapeCollider_CanBeAdded(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19578021_ShapeCollider_CanBeAdded as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@revert_physics_config
|
||||
def test_C15425929_Undo_Redo(self, request, workspace, editor, launcher_platform):
|
||||
from . import C15425929_Undo_Redo as test_module
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
"""
|
||||
|
||||
# This suite consists of all test cases that are passing and have been verified.
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .FileManagement import FileManagement as fm
|
||||
from ly_test_tools import LAUNCHERS
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
|
||||
|
||||
from base import TestAutomationBase
|
||||
|
||||
|
||||
revert_physics_config = fm.file_revert_list(['physxdebugconfiguration.setreg', 'physxdefaultsceneconfiguration.setreg', 'physxsystemconfiguration.setreg'], 'AutomatedTesting/Registry')
|
||||
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation(TestAutomationBase):
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536274_GetCollisionName_PrintsName(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536274_GetCollisionName_PrintsName as test_module
|
||||
# Fixme: expected_lines=["Layer Name: Right"]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536277_GetCollisionName_PrintsNothing(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536277_GetCollisionName_PrintsNothing as test_module
|
||||
# All groups present in the PhysX Collider that could show up in test
|
||||
# Fixme: collision_groups = ["All", "None", "All_NoTouchBend", "All_3", "None_1", "All_NoTouchBend_1", "All_2", "None_1_1", "All_NoTouchBend_1_1", "All_1", "None_1_1_1", "All_NoTouchBend_1_1_1", "All_4", "None_1_1_1_1", "All_NoTouchBend_1_1_1_1", "GroupLeft", "GroupRight"]
|
||||
# Fixme: for group in collision_groups:
|
||||
# Fixme: unexpected_lines.append(f"GroupName: {group}")
|
||||
# Fixme: expected_lines=["GroupName: "]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
"""
|
||||
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
its licensors.
|
||||
|
||||
For complete copyright and license terms please see the LICENSE at the root of this
|
||||
distribution (the "License"). All use of this software is governed by the License,
|
||||
or, if provided, by the license below or the license accompanying this file. Do not
|
||||
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
"""
|
||||
|
||||
# This suite consists of all test cases that are passing and have been verified.
|
||||
|
||||
import pytest
|
||||
import os
|
||||
import sys
|
||||
|
||||
from .FileManagement import FileManagement as fm
|
||||
from ly_test_tools import LAUNCHERS
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
|
||||
|
||||
from base import TestAutomationBase
|
||||
|
||||
|
||||
revert_physics_config = fm.file_revert_list(['physxdebugconfiguration.setreg', 'physxdefaultsceneconfiguration.setreg', 'physxsystemconfiguration.setreg'], 'AutomatedTesting/Registry')
|
||||
|
||||
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
@pytest.mark.parametrize("project", ["AutomatedTesting"])
|
||||
class TestAutomation(TestAutomationBase):
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536274_GetCollisionName_PrintsName(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536274_GetCollisionName_PrintsName as test_module
|
||||
# Fixme: expected_lines=["Layer Name: Right"]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
## Seems to be flaky, need to investigate
|
||||
def test_C19536277_GetCollisionName_PrintsNothing(self, request, workspace, editor, launcher_platform):
|
||||
from . import C19536277_GetCollisionName_PrintsNothing as test_module
|
||||
# All groups present in the PhysX Collider that could show up in test
|
||||
# Fixme: collision_groups = ["All", "None", "All_NoTouchBend", "All_3", "None_1", "All_NoTouchBend_1", "All_2", "None_1_1", "All_NoTouchBend_1_1", "All_1", "None_1_1_1", "All_NoTouchBend_1_1_1", "All_4", "None_1_1_1_1", "All_NoTouchBend_1_1_1_1", "GroupLeft", "GroupRight"]
|
||||
# Fixme: for group in collision_groups:
|
||||
# Fixme: unexpected_lines.append(f"GroupName: {group}")
|
||||
# Fixme: expected_lines=["GroupName: "]
|
||||
self._run_test(request, workspace, editor, test_module)
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:231d5ac32c95334eeb1cbf77ea0bceae1d8010de3290dfdbd991abb46d18bae6
|
||||
size 6844
|
||||
oid sha256:83af66a6db4ff2b4df7212099b661a96668cfb326d8984e41b16506ec0062141
|
||||
size 5844
|
||||
|
||||
@@ -38,6 +38,13 @@
|
||||
"Gems/PrimitiveAssets"
|
||||
]
|
||||
},
|
||||
"MaterialEditor":
|
||||
{
|
||||
"SourcePaths":
|
||||
[
|
||||
"Gems/Atom/Tools/MaterialEditor"
|
||||
]
|
||||
},
|
||||
"UiBasics":
|
||||
{
|
||||
"SourcePaths":
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Please read README.md for an explanation on why scenesrg.srgi and viewsrg.srgi are
|
||||
// located in this folder (And how you can optionally customize your own scenesrg.srgi
|
||||
// and viewsrg.srgi in your game project).
|
||||
|
||||
#include <Atom/Features/SrgSemantics.azsli>
|
||||
|
||||
partial ShaderResourceGroup RayTracingSceneSrg : SRG_RayTracingScene
|
||||
{
|
||||
/* Intentionally Empty. Helps define the SrgSemantic for RayTracingSceneSrg once.*/
|
||||
};
|
||||
|
||||
#define AZ_COLLECTING_PARTIAL_SRGS
|
||||
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/RayTracingSceneSrgAll.azsli>
|
||||
#undef AZ_COLLECTING_PARTIAL_SRGS
|
||||
+4
-2
@@ -75,7 +75,9 @@ foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(scripts)
|
||||
if(NOT INSTALLED_ENGINE)
|
||||
add_subdirectory(scripts)
|
||||
endif()
|
||||
|
||||
# SPEC-1417 will investigate and fix this
|
||||
if(NOT PAL_PLATFORM_NAME STREQUAL "Mac")
|
||||
@@ -125,5 +127,5 @@ if(NOT INSTALLED_ENGINE)
|
||||
ly_setup_o3de_install()
|
||||
|
||||
# IMPORTANT: must be included last
|
||||
include(cmake/CPack.cmake)
|
||||
include(cmake/Packaging.cmake)
|
||||
endif()
|
||||
|
||||
@@ -9,8 +9,5 @@
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
add_subdirectory(Cry3DEngine)
|
||||
add_subdirectory(CryCommon)
|
||||
add_subdirectory(CryFont)
|
||||
add_subdirectory(CrySystem)
|
||||
add_subdirectory(RenderDll)
|
||||
|
||||
@@ -1,733 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Light sources manager
|
||||
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
|
||||
#include "3dEngine.h"
|
||||
#include "ObjMan.h"
|
||||
#include "VisAreas.h"
|
||||
#include "AABBSV.h"
|
||||
#include "LightEntity.h"
|
||||
#include "ObjectsTree.h"
|
||||
#include "ClipVolumeManager.h"
|
||||
|
||||
ILightSource* C3DEngine::CreateLightSource()
|
||||
{
|
||||
// construct new object
|
||||
CLightEntity* pLightEntity = new CLightEntity();
|
||||
|
||||
m_lstStaticLights.Add(pLightEntity);
|
||||
|
||||
return pLightEntity;
|
||||
}
|
||||
|
||||
void C3DEngine::DeleteLightSource(ILightSource* pLightSource)
|
||||
{
|
||||
if (m_lstStaticLights.Delete((CLightEntity*)pLightSource) || pLightSource == m_pSun)
|
||||
{
|
||||
if (pLightSource == m_pSun)
|
||||
{
|
||||
m_pSun = NULL;
|
||||
}
|
||||
|
||||
delete pLightSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(!"Light object not found");
|
||||
}
|
||||
}
|
||||
|
||||
void CLightEntity::Release(bool)
|
||||
{
|
||||
Get3DEngine()->UnRegisterEntityDirect(this);
|
||||
Get3DEngine()->DeleteLightSource(this);
|
||||
}
|
||||
|
||||
void CLightEntity::SetLightProperties(const CDLight& light)
|
||||
{
|
||||
C3DEngine* engine = Get3DEngine();
|
||||
|
||||
m_light = light;
|
||||
|
||||
m_bShadowCaster = (m_light.m_Flags & DLF_CASTSHADOW_MAPS) != 0;
|
||||
|
||||
m_light.m_fBaseRadius = m_light.m_fRadius;
|
||||
m_light.m_fLightFrustumAngle = CLAMP(m_light.m_fLightFrustumAngle, 0.f, (LIGHT_PROJECTOR_MAX_FOV / 2.f));
|
||||
|
||||
if (!(m_light.m_Flags & (DLF_PROJECT | DLF_AREA_LIGHT)))
|
||||
{
|
||||
m_light.m_fLightFrustumAngle = 90.f / 2.f;
|
||||
}
|
||||
|
||||
m_light.m_pOwner = this;
|
||||
|
||||
if (m_light.m_Flags & DLF_ATTACH_TO_SUN)
|
||||
{
|
||||
m_dwRndFlags |= ERF_RENDER_ALWAYS | ERF_HUD;
|
||||
}
|
||||
|
||||
engine->GetLightEntities()->Delete((ILightSource*)this);
|
||||
|
||||
PodArray<ILightSource*>& lightEntities = *engine->GetLightEntities();
|
||||
|
||||
//on consoles we force all lights (except sun) to be deferred
|
||||
if (GetCVars()->e_DynamicLightsForceDeferred && !(m_light.m_Flags & (DLF_SUN | DLF_POST_3D_RENDERER)))
|
||||
{
|
||||
m_light.m_Flags |= DLF_DEFERRED_LIGHT;
|
||||
}
|
||||
|
||||
if (light.m_Flags & DLF_DEFERRED_LIGHT)
|
||||
{
|
||||
lightEntities.Add((ILightSource*)this);
|
||||
}
|
||||
else
|
||||
{
|
||||
lightEntities.InsertBefore((ILightSource*)this, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void C3DEngine::ResetCasterCombinationsCache()
|
||||
{
|
||||
for (int nSunInUse = 0; nSunInUse < 2; nSunInUse++)
|
||||
{
|
||||
// clear user counters
|
||||
for (ShadowFrustumListsCacheUsers::iterator it = m_FrustumsCacheUsers[nSunInUse].begin(); it != m_FrustumsCacheUsers[nSunInUse].end(); ++it)
|
||||
{
|
||||
it->second = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C3DEngine::DeleteAllStaticLightSources()
|
||||
{
|
||||
for (int i = 0; i < m_lstStaticLights.Count(); i++)
|
||||
{
|
||||
delete m_lstStaticLights[i];
|
||||
}
|
||||
m_lstStaticLights.Reset();
|
||||
|
||||
m_pSun = NULL;
|
||||
}
|
||||
|
||||
void C3DEngine::InitShadowFrustums(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
assert(passInfo.IsGeneralPass());
|
||||
FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
|
||||
AZ_TRACE_METHOD();
|
||||
|
||||
if (m_pSun)
|
||||
{
|
||||
CDLight* pLight = &m_pSun->GetLightProperties();
|
||||
CLightEntity* pLightEntity = (CLightEntity*)pLight->m_pOwner;
|
||||
|
||||
if (passInfo.RenderShadows() && (pLight->m_Flags & DLF_CASTSHADOW_MAPS) && pLight->m_Id >= 0)
|
||||
{
|
||||
pLightEntity->UpdateGSMLightSourceShadowFrustum(passInfo);
|
||||
|
||||
if (pLightEntity->m_pShadowMapInfo)
|
||||
{
|
||||
pLight->m_pShadowMapFrustums = pLightEntity->m_pShadowMapInfo->pGSM;
|
||||
}
|
||||
}
|
||||
|
||||
_smart_ptr<IMaterial> pMat = pLightEntity->GetMaterial();
|
||||
if (pMat)
|
||||
{
|
||||
pLight->m_Shader = pMat->GetShaderItem();
|
||||
}
|
||||
|
||||
// update copy of light ion the renderer
|
||||
if (pLight->m_Id >= 0)
|
||||
{
|
||||
CDLight* pRndLight = NULL;
|
||||
GetRenderer()->EF_Query(EFQ_LightSource, pLight->m_Id, pRndLight);
|
||||
assert(pLight->m_Id == pRndLight->m_Id);
|
||||
pRndLight->m_pShadowMapFrustums = pLight->m_pShadowMapFrustums;
|
||||
pRndLight->m_Shader = pLight->m_Shader;
|
||||
pRndLight->m_Flags = pLight->m_Flags;
|
||||
}
|
||||
|
||||
// add per object shadow frustums
|
||||
m_nCustomShadowFrustumCount = 0;
|
||||
if (passInfo.RenderShadows() && GetCVars()->e_ShadowsPerObject > 0)
|
||||
{
|
||||
const uint nFrustumCount = m_lstPerObjectShadows.size();
|
||||
if (nFrustumCount > m_lstCustomShadowFrustums.size())
|
||||
{
|
||||
m_lstCustomShadowFrustums.resize(nFrustumCount);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < nFrustumCount; ++i)
|
||||
{
|
||||
if (m_lstPerObjectShadows[i].pCaster)
|
||||
{
|
||||
ShadowMapFrustum* pFr = &m_lstCustomShadowFrustums[i];
|
||||
pFr->m_eFrustumType = ShadowMapFrustum::e_PerObject;
|
||||
|
||||
CLightEntity::ProcessPerObjectFrustum(pFr, &m_lstPerObjectShadows[i], m_pSun, passInfo);
|
||||
++m_nCustomShadowFrustumCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (passInfo.RenderShadows())
|
||||
{
|
||||
ResetCasterCombinationsCache();
|
||||
}
|
||||
}
|
||||
|
||||
void C3DEngine::AddPerObjectShadow(IShadowCaster* pCaster, float fConstBias, float fSlopeBias, float fJitter, const Vec3& vBBoxScale, uint nTexSize)
|
||||
{
|
||||
SPerObjectShadow* pOS = GetPerObjectShadow(pCaster);
|
||||
if (!pOS)
|
||||
{
|
||||
pOS = &m_lstPerObjectShadows.AddNew();
|
||||
}
|
||||
|
||||
pOS->pCaster = pCaster;
|
||||
pOS->fConstBias = fConstBias;
|
||||
pOS->fSlopeBias = fSlopeBias;
|
||||
pOS->fJitter = fJitter;
|
||||
pOS->vBBoxScale = vBBoxScale;
|
||||
pOS->nTexSize = nTexSize;
|
||||
}
|
||||
|
||||
void C3DEngine::RemovePerObjectShadow(IShadowCaster* pCaster)
|
||||
{
|
||||
SPerObjectShadow* pOS = GetPerObjectShadow(pCaster);
|
||||
if (pOS)
|
||||
{
|
||||
FRAME_PROFILER("C3DEngine::RemovePerObjectShadow", GetSystem(), PROFILE_3DENGINE);
|
||||
|
||||
size_t nIndex = (size_t)(pOS - m_lstPerObjectShadows.begin());
|
||||
m_lstPerObjectShadows.Delete(nIndex);
|
||||
}
|
||||
}
|
||||
|
||||
struct SPerObjectShadow* C3DEngine::GetPerObjectShadow(IShadowCaster* pCaster)
|
||||
{
|
||||
for (int i = 0; i < m_lstPerObjectShadows.Count(); ++i)
|
||||
{
|
||||
if (m_lstPerObjectShadows[i].pCaster == pCaster)
|
||||
{
|
||||
return &m_lstPerObjectShadows[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void C3DEngine::GetCustomShadowMapFrustums(ShadowMapFrustum*& arrFrustums, int& nFrustumCount)
|
||||
{
|
||||
arrFrustums = m_lstCustomShadowFrustums.begin();
|
||||
nFrustumCount = m_nCustomShadowFrustumCount;
|
||||
}
|
||||
|
||||
// delete pLight->m_pProjCamera;
|
||||
//pLight->m_pProjCamera=0;
|
||||
//if(pLight->m_pShader)
|
||||
// SAFE_RELEASE(pLight->m_pShader);
|
||||
namespace
|
||||
{
|
||||
static inline bool CmpCastShadowFlag(const CDLight* p1, const CDLight* p2)
|
||||
{
|
||||
// move sun first
|
||||
if ((p1->m_Flags & DLF_SUN) > (p2->m_Flags & DLF_SUN))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((p1->m_Flags & DLF_SUN) < (p2->m_Flags & DLF_SUN))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// move shadow casters first
|
||||
if ((p1->m_Flags & DLF_CASTSHADOW_MAPS) > (p2->m_Flags & DLF_CASTSHADOW_MAPS))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((p1->m_Flags & DLF_CASTSHADOW_MAPS) < (p2->m_Flags & DLF_CASTSHADOW_MAPS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// get some sorting consistency for shadow casters
|
||||
if (p1->m_pOwner > p2->m_pOwner)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (p1->m_pOwner < p2->m_pOwner)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void C3DEngine::SubmitSun(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
assert(passInfo.IsGeneralPass());
|
||||
FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
|
||||
AZ_TRACE_METHOD();
|
||||
|
||||
if (m_pSun)
|
||||
{
|
||||
CDLight* light = &m_pSun->GetLightProperties();
|
||||
|
||||
GetRenderer()->EF_ADDDlight(light, passInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void C3DEngine::RemoveEntityLightSources(IRenderNode* pEntity)
|
||||
{
|
||||
for (int i = 0; i < m_lstStaticLights.Count(); i++)
|
||||
{
|
||||
if (m_lstStaticLights[i] == pEntity)
|
||||
{
|
||||
m_lstStaticLights.Delete(i);
|
||||
if (pEntity == m_pSun)
|
||||
{
|
||||
m_pSun = NULL;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ILightSource* C3DEngine::GetSunEntity()
|
||||
{
|
||||
return m_pSun;
|
||||
}
|
||||
|
||||
void C3DEngine::OnCasterDeleted(IShadowCaster* pCaster)
|
||||
{
|
||||
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_3DENGINE);
|
||||
{ // make sure pointer to object will not be used somewhere in the renderer
|
||||
if (m_pSun)
|
||||
{
|
||||
m_pSun->OnCasterDeleted(pCaster);
|
||||
}
|
||||
|
||||
if (GetRenderer()->GetActiveGPUCount() > 1)
|
||||
{
|
||||
if (ShadowFrustumMGPUCache* pFrustumCache = GetRenderer()->GetShadowFrustumMGPUCache())
|
||||
{
|
||||
pFrustumCache->DeleteFromCache(pCaster);
|
||||
}
|
||||
}
|
||||
|
||||
// remove from per object shadows list
|
||||
RemovePerObjectShadow(pCaster);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CLightVolumesMgr::Init()
|
||||
{
|
||||
m_bUpdateLightVolumes = false;
|
||||
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
|
||||
{
|
||||
m_pLightVolumes[i].reserve(LV_MAX_COUNT);
|
||||
m_pLightVolsInfo[i].reserve(LV_MAX_COUNT);
|
||||
}
|
||||
memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
|
||||
memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
|
||||
}
|
||||
|
||||
void CLightVolumesMgr::Reset()
|
||||
{
|
||||
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
|
||||
{
|
||||
stl::free_container(m_pLightVolumes[i]);
|
||||
}
|
||||
|
||||
m_bUpdateLightVolumes = false;
|
||||
memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
|
||||
memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint16 CLightVolumesMgr::RegisterVolume(const Vec3& vPos, f32 fRadius, uint8 nClipVolumeRef, const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
|
||||
|
||||
IF ((m_bUpdateLightVolumes && (lightVolsInfo.size() < LV_MAX_COUNT)) && fRadius < 256.0f, 1)
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
int32 nPosx = (int32)(floorf(vPos.x * LV_CELL_RSIZEX));
|
||||
int32 nPosy = (int32)(floorf(vPos.y * LV_CELL_RSIZEY));
|
||||
int32 nPosz = (int32)(floorf(vPos.z * LV_CELL_RSIZEZ));
|
||||
|
||||
// Check if world cell has any light volume, else add new one
|
||||
uint16 nHashIndex = GetWorldHashBucketKey(nPosx, nPosy, nPosz);
|
||||
uint16* pCurrentVolumeID = &m_nWorldCells[nHashIndex];
|
||||
|
||||
while (*pCurrentVolumeID != 0)
|
||||
{
|
||||
SLightVolInfo& sVolInfo = *lightVolsInfo[*pCurrentVolumeID - 1];
|
||||
|
||||
int32 nVolumePosx = (int32)(floorf(sVolInfo.vVolume.x * LV_CELL_RSIZEX));
|
||||
int32 nVolumePosy = (int32)(floorf(sVolInfo.vVolume.y * LV_CELL_RSIZEY));
|
||||
int32 nVolumePosz = (int32)(floorf(sVolInfo.vVolume.z * LV_CELL_RSIZEZ));
|
||||
|
||||
if (nPosx == nVolumePosx &&
|
||||
nPosy == nVolumePosy &&
|
||||
nPosz == nVolumePosz &&
|
||||
nClipVolumeRef == sVolInfo.nClipVolumeID)
|
||||
{
|
||||
return (uint16) * pCurrentVolumeID;
|
||||
}
|
||||
|
||||
pCurrentVolumeID = &sVolInfo.nNextVolume;
|
||||
}
|
||||
|
||||
// create new volume
|
||||
SLightVolInfo* pLightVolInfo = new SLightVolInfo(vPos, fRadius, nClipVolumeRef);
|
||||
lightVolsInfo.push_back(pLightVolInfo);
|
||||
*pCurrentVolumeID = lightVolsInfo.size();
|
||||
|
||||
return *pCurrentVolumeID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CLightVolumesMgr::RegisterLight(const CDLight& pDL, uint32 nLightID, [[maybe_unused]] const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
IF ((m_bUpdateLightVolumes && !(pDL.m_Flags & LV_DLF_LIGHTVOLUMES_MASK)), 1)
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
const f32 fColCheck = (f32) fsel(pDL.m_Color.r + pDL.m_Color.g + pDL.m_Color.b - 0.333f, 1.0f, 0.0f); //light color > threshold
|
||||
const f32 fRadCheck = (f32) fsel(pDL.m_fRadius - 0.5f, 1.0f, 0.0f); //light radius > threshold
|
||||
if (fColCheck * fRadCheck)
|
||||
{
|
||||
//if the radius is large than certain value, all the the world light cells will be lighted anyway. So we just add the light to all the cells
|
||||
//the input radius restriction will be added too
|
||||
if(floorf(pDL.m_fRadius*LV_LIGHT_CELL_R_SIZE) > LV_LIGHTS_WORLD_BUCKET_SIZE)
|
||||
{
|
||||
for (int32 idx = 0; idx < LV_LIGHTS_WORLD_BUCKET_SIZE; idx++)
|
||||
{
|
||||
SLightCell& lightCell = m_pWorldLightCells[idx];
|
||||
CryPrefetch(&lightCell);
|
||||
if (lightCell.nLightCount < LV_LIGHTS_MAX_COUNT)
|
||||
{
|
||||
lightCell.nLightID[lightCell.nLightCount] = nLightID;
|
||||
lightCell.nLightCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int32 nMiny = (int32)(floorf((pDL.m_Origin.y - pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
|
||||
int32 nMaxy = (int32)(floorf((pDL.m_Origin.y + pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
|
||||
int32 nMinx = (int32)(floorf((pDL.m_Origin.x - pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
|
||||
int32 nMaxx = (int32)(floorf((pDL.m_Origin.x + pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
|
||||
|
||||
// Register light into all cells touched by light radius
|
||||
for (int32 y = nMiny, ymax = nMaxy; y <= ymax; ++y)
|
||||
{
|
||||
for (int32 x = nMinx, xmax = nMaxx; x <= xmax; ++x)
|
||||
{
|
||||
SLightCell& lightCell = m_pWorldLightCells[GetWorldHashBucketKey(x, y, 1, LV_LIGHTS_WORLD_BUCKET_SIZE)];
|
||||
CryPrefetch(&lightCell);
|
||||
if (lightCell.nLightCount < LV_LIGHTS_MAX_COUNT)
|
||||
{
|
||||
//only if the las light added to the cell wasn't the same light
|
||||
if (!(lightCell.nLightCount > 0 && lightCell.nLightID[lightCell.nLightCount - 1] == nLightID))
|
||||
{
|
||||
lightCell.nLightID[lightCell.nLightCount] = nLightID;
|
||||
lightCell.nLightCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CLightVolumesMgr::AddLight(const SRenderLight& pLight, const SLightVolInfo* __restrict pVolInfo, SLightVolume& pVolume)
|
||||
{
|
||||
// Check for clip volume
|
||||
if (pLight.m_nStencilRef[0] == pVolInfo->nClipVolumeID || pLight.m_nStencilRef[1] == pVolInfo->nClipVolumeID ||
|
||||
pLight.m_nStencilRef[0] == CClipVolumeManager::AffectsEverythingStencilRef)
|
||||
{
|
||||
const Vec4* __restrict vLight = (Vec4*) &pLight.m_Origin.x;
|
||||
const Vec4& vVolume = pVolInfo->vVolume;
|
||||
const f32 fDimCheck = (f32) fsel(vLight->w - vVolume.w * 0.1f, 1.0f, 0.0f); //light radius not more than 10x smaller than volume radius
|
||||
const f32 fOverlapCheck = (f32) fsel(sqr(vVolume.x - vLight->x) + sqr(vVolume.y - vLight->y) + sqr(vVolume.z - vLight->z) - sqr(vVolume.w + vLight->w), 0.0f, 1.0f);// touches volumes
|
||||
if (fDimCheck * fOverlapCheck)
|
||||
{
|
||||
float fAttenuationBulbSize = pLight.m_fAttenuationBulbSize;
|
||||
Vec3 lightColor = *((Vec3*)&pLight.m_Color);
|
||||
|
||||
// Adjust light intensity so that the intended brightness is reached 1 meter from the light's surface
|
||||
IF (!(pLight.m_Flags & (DLF_AREA_LIGHT | DLF_AMBIENT)), 1)
|
||||
{
|
||||
fAttenuationBulbSize = max(fAttenuationBulbSize, 0.001f);
|
||||
|
||||
// Solve I * 1 / (1 + d/lightsize)^2 = 1
|
||||
float intensityMul = 1.0f + 1.0f / fAttenuationBulbSize;
|
||||
intensityMul *= intensityMul;
|
||||
lightColor *= intensityMul;
|
||||
}
|
||||
|
||||
pVolume.pData.push_back();
|
||||
SLightVolume::SLightData& lightData = pVolume.pData[pVolume.pData.size() - 1];
|
||||
lightData.vPos = *vLight;
|
||||
lightData.vColor = Vec4(lightColor, fAttenuationBulbSize);
|
||||
lightData.vParams = Vec4(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
IF (pLight.m_Flags & DLF_PROJECT, 1)
|
||||
{
|
||||
lightData.vParams = Vec4(pLight.m_ObjMatrix.GetColumn0(), cos_tpl(DEG2RAD(pLight.m_fLightFrustumAngle)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CLightVolumesMgr::Update(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
uint32 nThreadID = passInfo.ThreadID();
|
||||
DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[nThreadID];
|
||||
|
||||
if (!m_bUpdateLightVolumes || lightVolsInfo.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
TArray<SRenderLight>* pLights = GetRenderer()->EF_GetDeferredLights(passInfo);
|
||||
const uint32 nLightCount = pLights->size();
|
||||
|
||||
uint32 nLightVols = lightVolsInfo.size();
|
||||
LightVolumeVector& lightVols = m_pLightVolumes[nThreadID];
|
||||
uint32 existingLightVolsCount = 0; //This is 0, that just means we will be overwriting all existing light volumes
|
||||
|
||||
//If this is a recursive pass (not the first time that this is called this frame), we're just going to be adding on new light volumes to the existing collection
|
||||
if (passInfo.IsRecursivePass())
|
||||
{
|
||||
existingLightVolsCount = lightVols.size();
|
||||
|
||||
//If no new light volumes have been added, don't bother updating
|
||||
if (nLightVols == existingLightVolsCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lightVols.resize(nLightVols);
|
||||
|
||||
if (!nLightCount)
|
||||
{
|
||||
//Start out existingLightVolsCount to avoid clearing out existing light volumes when we don't need to
|
||||
for (uint32 v = existingLightVolsCount; v < nLightVols; ++v)
|
||||
{
|
||||
lightVols[v].pData.resize(0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const int MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE = 1024;
|
||||
|
||||
if (nLightCount > MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, "More lights in the scene (%d) than supported by the Light Volume Update function (%d). Extra lights will be ignored.",
|
||||
nLightCount, MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE);
|
||||
}
|
||||
|
||||
//This can be a uint8 array because nLightVols should never be greater than 256(LV_MAX_COUNT)
|
||||
assert(LV_MAX_COUNT <= 256);
|
||||
uint8 lightProcessedStateArray[MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE];
|
||||
|
||||
//Start at the number of light volumes that already exist so that we don't end up re-updating light volumes unnecessarily.
|
||||
for (uint32 v = existingLightVolsCount; v < nLightVols; ++v)
|
||||
{
|
||||
const Vec4* __restrict vBVol = &lightVolsInfo[v]->vVolume;
|
||||
int32 nMiny = (int32)(floorf((vBVol->y - vBVol->w) * LV_LIGHT_CELL_R_SIZE));
|
||||
int32 nMaxy = (int32)(floorf((vBVol->y + vBVol->w) * LV_LIGHT_CELL_R_SIZE));
|
||||
int32 nMinx = (int32)(floorf((vBVol->x - vBVol->w) * LV_LIGHT_CELL_R_SIZE));
|
||||
int32 nMaxx = (int32)(floorf((vBVol->x + vBVol->w) * LV_LIGHT_CELL_R_SIZE));
|
||||
|
||||
lightVols[v].pData.resize(0);
|
||||
|
||||
// Loop through active light cells touching bounding volume (~avg 2 cells)
|
||||
for (int32 y = nMiny, ymax = nMaxy; y <= ymax; ++y)
|
||||
{
|
||||
for (int32 x = nMinx, xmax = nMaxx; x <= xmax; ++x)
|
||||
{
|
||||
const SLightCell& lightCell = m_pWorldLightCells[GetWorldHashBucketKey(x, y, 1, LV_LIGHTS_WORLD_BUCKET_SIZE)];
|
||||
CryPrefetch(&lightCell);
|
||||
|
||||
const SRenderLight& pFirstDL = (*pLights)[lightCell.nLightID[0]];
|
||||
CryPrefetch(&pFirstDL);
|
||||
CryPrefetch(&pFirstDL.m_ObjMatrix);
|
||||
for (uint32 l = 0; (l < lightCell.nLightCount) & (lightVols[v].pData.size() < LIGHTVOLUME_MAXLIGHTS); ++l)
|
||||
{
|
||||
const int32 nLightId = lightCell.nLightID[l];
|
||||
|
||||
//Only allow IDs < MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE to continue or else we'll overflow access to
|
||||
//lightProcessedStateArray[MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE]. Skipping the extra lights shouldn't really matter
|
||||
//since A) folks won't be using that many lights, and B) for the case of light emitting particles, they tend to be grouped
|
||||
//so that the individual contributions tend to bleed together anyway.
|
||||
if (nLightId >= MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (static_cast<uint32>(nLightId) < nLightCount)
|
||||
{
|
||||
const SRenderLight& pDL = (*pLights)[nLightId];
|
||||
const int32 nNextLightId = lightCell.nLightID[(l + 1) & (LIGHTVOLUME_MAXLIGHTS - 1)];
|
||||
const SRenderLight& pNextDL = (*pLights)[nNextLightId];
|
||||
CryPrefetch(&pNextDL);
|
||||
CryPrefetch(&pNextDL.m_ObjMatrix);
|
||||
|
||||
IF(lightProcessedStateArray[nLightId] != v + 1, 1)
|
||||
{
|
||||
lightProcessedStateArray[nLightId] = v + 1;
|
||||
AddLight(pDL, &*lightVolsInfo[v], lightVols[v]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CLightVolumesMgr::Clear(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
|
||||
|
||||
m_bUpdateLightVolumes = false;
|
||||
if (GetCVars()->e_LightVolumes && passInfo.IsGeneralPass() && GetCVars()->e_DynamicLights)
|
||||
{
|
||||
memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
|
||||
memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
|
||||
|
||||
//Clean up volume info data
|
||||
for (size_t i = 0; i < lightVolsInfo.size(); ++i)
|
||||
{
|
||||
delete lightVolsInfo[i];
|
||||
}
|
||||
|
||||
m_pLightVolsInfo[passInfo.ThreadID()].clear();
|
||||
m_bUpdateLightVolumes = (GetCVars()->e_LightVolumes == 1) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CLightVolumesMgr::GetLightVolumes(threadID nThreadID, SLightVolume*& pLightVols, uint32& nNumVols)
|
||||
{
|
||||
pLightVols = 0;
|
||||
nNumVols = 0;
|
||||
if (GetCVars()->e_LightVolumes == 1 && GetCVars()->e_DynamicLights && !m_pLightVolumes[nThreadID].empty())
|
||||
{
|
||||
pLightVols = &m_pLightVolumes[nThreadID][0];
|
||||
nNumVols = m_pLightVolumes[nThreadID].size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C3DEngine::GetLightVolumes(threadID nThreadID, SLightVolume*& pLightVols, uint32& nNumVols)
|
||||
{
|
||||
m_LightVolumesMgr.GetLightVolumes(nThreadID, pLightVols, nNumVols);
|
||||
}
|
||||
|
||||
uint16 C3DEngine::RegisterVolumeForLighting(const Vec3& vPos, f32 fRadius, uint8 nClipVolumeRef, const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
return m_LightVolumesMgr.RegisterVolume(vPos, fRadius, nClipVolumeRef, passInfo);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _RELEASE
|
||||
void CLightVolumesMgr::DrawDebug(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
|
||||
|
||||
IRenderer* pRenderer = GetRenderer();
|
||||
IRenderAuxGeom* pAuxGeom = GetRenderer()->GetIRenderAuxGeom();
|
||||
if (!pAuxGeom || !passInfo.IsGeneralPass())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ColorF cWhite = ColorF(1, 1, 1, 1);
|
||||
ColorF cBad = ColorF(1.0f, 0.0, 0.0f, 1.0f);
|
||||
ColorF cWarning = ColorF(1.0f, 1.0, 0.0f, 1.0f);
|
||||
ColorF cGood = ColorF(0.0f, 0.5, 1.0f, 1.0f);
|
||||
ColorF cSingleCell = ColorF(0.0f, 1.0, 0.0f, 1.0f);
|
||||
|
||||
const uint32 nLightVols = lightVolsInfo.size();
|
||||
LightVolumeVector& lightVols = m_pLightVolumes[passInfo.ThreadID()];
|
||||
const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
|
||||
|
||||
float fYLine = 8.0f, fYStep = 20.0f;
|
||||
GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, (float*)&cWhite.r, false, "Light Volumes Info (count %d)", nLightVols);
|
||||
|
||||
for (uint32 v = 0; v < nLightVols; ++v) // draw each light volume
|
||||
{
|
||||
SLightVolume& lv = lightVols[v];
|
||||
SLightVolInfo& lvInfo = *lightVolsInfo[v];
|
||||
|
||||
ColorF& cCol = (lv.pData.size() >= 10) ? cBad : ((lv.pData.size() >= 5) ? cWarning : cGood);
|
||||
const Vec3 vPos = Vec3(lvInfo.vVolume.x, lvInfo.vVolume.y, lvInfo.vVolume.z);
|
||||
const float fCamDistSq = (vPos - vCamPos).len2();
|
||||
cCol.a = max(0.25f, min(1.0f, 1024.0f / (fCamDistSq + 1e-6f)));
|
||||
|
||||
pRenderer->DrawLabelEx(vPos, 1.3f, (float*)&cCol.r, true, true, "Id: %d\nPos: %.2f %.2f %.2f\nRadius: %.2f\nLights: %d\nOutLights: %d",
|
||||
v, vPos.x, vPos.y, vPos.z, lvInfo.vVolume.w, lv.pData.size(), (*(int32*)&lvInfo.vVolume.w) & (1 << 31) ? 1 : 0);
|
||||
|
||||
if (GetCVars()->e_LightVolumesDebug == 2)
|
||||
{
|
||||
const float fSideSize = 0.707f * sqrtf(lvInfo.vVolume.w * lvInfo.vVolume.w * 2);
|
||||
pAuxGeom->DrawAABB(AABB(vPos - Vec3(fSideSize), vPos + Vec3(fSideSize)), false, cCol, eBBD_Faceted);
|
||||
}
|
||||
|
||||
if (GetCVars()->e_LightVolumesDebug == 3)
|
||||
{
|
||||
cBad.a = 1.0f;
|
||||
const Vec3 vCellPos = Vec3(floorf((lvInfo.vVolume.x) * LV_CELL_RSIZEX) * LV_CELL_SIZEX,
|
||||
floorf((lvInfo.vVolume.y) * LV_CELL_RSIZEY) * LV_CELL_SIZEY,
|
||||
floorf((lvInfo.vVolume.z) * LV_CELL_RSIZEZ) * LV_CELL_SIZEZ);
|
||||
|
||||
const Vec3 vMin = vCellPos;
|
||||
const Vec3 vMax = vMin + Vec3(LV_CELL_SIZEX, LV_CELL_SIZEY, LV_CELL_SIZEZ);
|
||||
pAuxGeom->DrawAABB(AABB(vMin, vMax), false, cBad, eBBD_Faceted);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
#include "3DEngineMemory.h"
|
||||
|
||||
// Static CTemporaryPool instance
|
||||
CTemporaryPool* CTemporaryPool::s_Instance = NULL;
|
||||
|
||||
namespace util
|
||||
{
|
||||
void* pool_allocate(size_t nSize)
|
||||
{
|
||||
return CTemporaryPool::Get()->Allocate(nSize, 8);
|
||||
}
|
||||
void pool_free(void* ptr)
|
||||
{
|
||||
return CTemporaryPool::Get()->Free(ptr);
|
||||
}
|
||||
}
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H
|
||||
#pragma once
|
||||
|
||||
// The type of pool responsible for temporary allocations within the 3dengine
|
||||
//
|
||||
// Note: The header is included here for reasons of devirtualization. If
|
||||
// included directly from the precompiled header in 3dEngine, the gamedll will
|
||||
// fail to compile!
|
||||
#include <CryPool/PoolAlloc.h>
|
||||
#include <InplaceFactory.h>
|
||||
|
||||
using NCryPoolAlloc::CFirstFit; // speed of allocations are crucial, so simply use the first fitting free allocation
|
||||
using NCryPoolAlloc::CInPlace; //
|
||||
using NCryPoolAlloc::CMemoryDynamic; // the pool itself will be dynamically allocated
|
||||
using NCryPoolAlloc::CListItemInPlace; // use inplace items
|
||||
|
||||
// Tempororary Pool Holder
|
||||
class CTemporaryPool
|
||||
{
|
||||
private:
|
||||
// Access granted for 3dEngine to create, destroy and maintain the temporary
|
||||
// pool for the 3d engine
|
||||
friend class C3DEngine;
|
||||
|
||||
// The static pool instance - one pool to rule them all (temp allocations at least)
|
||||
static CTemporaryPool* s_Instance;
|
||||
|
||||
// The type of the backing temporary pool
|
||||
typedef CFirstFit<CInPlace<CMemoryDynamic>, CListItemInPlace> TTemporaryPool;
|
||||
TTemporaryPool Pool;
|
||||
|
||||
// A non-recursive critical section guards the pool against concurrent access
|
||||
typedef CryCriticalSectionNonRecursive TTemporaryPoolLock;
|
||||
TTemporaryPoolLock Lock;
|
||||
|
||||
// Initialize the pool manager.
|
||||
//
|
||||
// Allocates the backing storage and initializes the temporary pool
|
||||
// itself. The backing storage is aligned to 16 bytes to reduce the amount of
|
||||
// cachelines crossed by the temporary pool
|
||||
static bool Initialize(size_t poolSize)
|
||||
{
|
||||
// Create the object instance
|
||||
s_Instance = new CTemporaryPool();
|
||||
if (!s_Instance)
|
||||
{
|
||||
CryFatalError("CTemporaryPool::Init(): could not create an instance of CTemporaryPool");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate the backing storage
|
||||
uint8* tempPool = reinterpret_cast<uint8*>(CryModuleMemalign(poolSize, 16));
|
||||
if (!tempPool)
|
||||
{
|
||||
CryFatalError("CTemporaryPool::Init(): could not allocate %" PRISIZE_T " bytes for temportary pool", poolSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the actual pool
|
||||
s_Instance->Pool.InitMem(poolSize, tempPool);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Shutdown the temporary pool manager.
|
||||
//
|
||||
// Frees the temporary pool
|
||||
static bool Shutdown()
|
||||
{
|
||||
if (s_Instance == NULL)
|
||||
{
|
||||
CryFatalError("CTemporaryPool::Shutdown(): no temporary pool instance present");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
CTemporaryPool& instance = *s_Instance;
|
||||
if (instance.Pool.Data())
|
||||
{
|
||||
CryModuleMemalignFree(instance.Pool.Data());
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
|
||||
delete s_Instance;
|
||||
s_Instance = NULL;
|
||||
return !error;
|
||||
}
|
||||
|
||||
// Templated construct helper member function using an inplace factory
|
||||
//
|
||||
// Called from the templated New<T, Expr> function below. Returns a typed
|
||||
// pointer to the inplace constructed object.
|
||||
template<typename T, typename InPlaceFactory>
|
||||
T* Construct(const InPlaceFactory& factory, void* storage)
|
||||
{
|
||||
return reinterpret_cast<T*>(factory.template apply<T>(storage));
|
||||
}
|
||||
|
||||
// Templated destruct helper member function.
|
||||
//
|
||||
// Calls the object's destructor and returns a void pointer to the storage
|
||||
template<typename T>
|
||||
void* Destruct(T* obj)
|
||||
{
|
||||
obj->~T();
|
||||
return reinterpret_cast<void*>(obj);
|
||||
}
|
||||
|
||||
// Empty private constructor/destructors to prevent clients from creating and
|
||||
// destroying instances of CTemporaryPool (there should only be one instance
|
||||
// in the 3DEngine).
|
||||
CTemporaryPool() {};
|
||||
~CTemporaryPool() {};
|
||||
|
||||
public:
|
||||
|
||||
// Allocate a block of memory with the given size and alignment
|
||||
void* Allocate(size_t size, size_t align)
|
||||
{
|
||||
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
|
||||
void* pData = Pool.Allocate<void*>(size, align);
|
||||
if (pData == NULL)
|
||||
{
|
||||
CryFatalError("**** could not allocate %" PRISIZE_T " bytes from temporary pool", size);
|
||||
}
|
||||
return Pool.Resolve<void*>(pData);
|
||||
};
|
||||
|
||||
// Allocates memory and constructs object of type 'T'
|
||||
//
|
||||
// Note: This method is respects the alignment of 'T' via C99 alignof()
|
||||
template<typename T, typename Expr>
|
||||
T* New(const Expr& expr)
|
||||
{
|
||||
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
|
||||
void* pObjStorage = Pool.Allocate<void*>(sizeof(T), alignof(T));
|
||||
if (pObjStorage == NULL)
|
||||
{
|
||||
CryFatalError("**** could not allocate %d bytes from temporary pool",
|
||||
(int)sizeof (T));
|
||||
}
|
||||
return Construct<T>(expr, pObjStorage);
|
||||
};
|
||||
|
||||
// Allocates memory and constructs object of type 'T'
|
||||
//
|
||||
// Note: This method is respects the alignment of 'T' via C99 alignof()
|
||||
template<typename T>
|
||||
T* New()
|
||||
{
|
||||
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
|
||||
void* pObjStorage = Pool.Allocate<void*>(sizeof(T), alignof(T));
|
||||
if (pObjStorage == NULL)
|
||||
{
|
||||
CryFatalError("**** could not allocate %d bytes from temporary pool",
|
||||
(int)sizeof (T));
|
||||
}
|
||||
return Construct<T>(InplaceFactory(), pObjStorage);
|
||||
};
|
||||
|
||||
// Frees a block of memory from the temporary pool
|
||||
//
|
||||
void Free(void* ptr)
|
||||
{
|
||||
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
|
||||
Pool.Free(ptr);
|
||||
}
|
||||
|
||||
|
||||
// Destroys an object of type 'T' and frees the underlying block of memory
|
||||
template<typename T>
|
||||
void Delete(T* ptr)
|
||||
{
|
||||
AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
|
||||
Pool.Free(Destruct<T>(ptr));
|
||||
}
|
||||
|
||||
// Static function to retrieve the static instance of CTemporaryPool
|
||||
static CTemporaryPool* Get() { return s_Instance; };
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(Pool.Data(), Pool.MemSize());
|
||||
}
|
||||
};
|
||||
|
||||
// A stl compliant scratch allocator that uses the given temporary pool.
|
||||
template <class Type>
|
||||
class scratch_allocator
|
||||
{
|
||||
public:
|
||||
typedef Type value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef const value_type* const_pointer;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
template <class value_type1>
|
||||
struct rebind
|
||||
{
|
||||
typedef scratch_allocator<value_type1> other;
|
||||
};
|
||||
|
||||
scratch_allocator() {}
|
||||
template <class value_type1>
|
||||
scratch_allocator(const scratch_allocator<value_type1>&) {}
|
||||
scratch_allocator(const scratch_allocator<value_type>&) {}
|
||||
~scratch_allocator() {}
|
||||
|
||||
pointer address(reference x) const {return &x; }
|
||||
const_pointer address(const_reference x) const { return &x; }
|
||||
|
||||
// Note: size can be zero - return value will be null in that case
|
||||
value_type* allocate(size_type n, const void* = 0)
|
||||
{
|
||||
if (n != 0)
|
||||
{
|
||||
size_type buf_size = n * sizeof(value_type);
|
||||
|
||||
void* ret = CTemporaryPool::Get()->Allocate(
|
||||
buf_size,
|
||||
alignof(value_type));
|
||||
|
||||
return reinterpret_cast<value_type*>(ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Note: size can be zero.
|
||||
void deallocate(pointer p, [[maybe_unused]] size_type n)
|
||||
{
|
||||
if (p != NULL)
|
||||
{
|
||||
CTemporaryPool::Get()->Free(p);
|
||||
}
|
||||
}
|
||||
|
||||
size_type max_size() const { return size_t(-1) / sizeof(value_type); }
|
||||
|
||||
void construct(pointer p, const_reference val)
|
||||
{ new (reinterpret_cast<void*>(p))value_type(val); }
|
||||
|
||||
void destroy(pointer p) { p->~value_type(); }
|
||||
|
||||
void cleanup() {}
|
||||
|
||||
size_t get_heap_size() { return 0; }
|
||||
|
||||
size_t get_wasted_in_allocation() { return 0; }
|
||||
|
||||
size_t get_wasted_in_blocks() { return 0; }
|
||||
};
|
||||
|
||||
|
||||
// A scratch vector type to use the stl vector
|
||||
template<typename Type>
|
||||
class scratch_vector
|
||||
: public std::vector<Type, scratch_allocator<Type> >
|
||||
{
|
||||
};
|
||||
|
||||
namespace util
|
||||
{
|
||||
extern void* pool_allocate(size_t nSize);
|
||||
extern void pool_free(void* ptr);
|
||||
}
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,574 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Implementation of I3DEngine interface methods
|
||||
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
#include <MathConversion.h>
|
||||
|
||||
#include "3dEngine.h"
|
||||
|
||||
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||
|
||||
#include "VisAreas.h"
|
||||
#include "ObjMan.h"
|
||||
#include "Ocean.h"
|
||||
|
||||
#include "DecalManager.h"
|
||||
#include "IndexedMesh.h"
|
||||
#include "AABBSV.h"
|
||||
|
||||
#include "MatMan.h"
|
||||
|
||||
#include "CullBuffer.h"
|
||||
#include "CGF/CGFLoader.h"
|
||||
#include "CGF/ReadOnlyChunkFile.h"
|
||||
|
||||
#include "CloudRenderNode.h"
|
||||
#include "CloudsManager.h"
|
||||
#include "SkyLightManager.h"
|
||||
#include "FogVolumeRenderNode.h"
|
||||
#include "DecalRenderNode.h"
|
||||
#include "TimeOfDay.h"
|
||||
#include "LightEntity.h"
|
||||
#include "FogVolumeRenderNode.h"
|
||||
#include "ObjectsTree.h"
|
||||
#include "WaterVolumeRenderNode.h"
|
||||
#include "DistanceCloudRenderNode.h"
|
||||
#include "VolumeObjectRenderNode.h"
|
||||
#include "RenderMeshMerger.h"
|
||||
#include "DeferredCollisionEvent.h"
|
||||
#include "OpticsManager.h"
|
||||
#include "ClipVolumeManager.h"
|
||||
#include "Environment/OceanEnvironmentBus.h"
|
||||
|
||||
|
||||
#if !defined(EXCLUDE_DOCUMENTATION_PURPOSE)
|
||||
#include "PrismRenderNode.h"
|
||||
#endif // EXCLUDE_DOCUMENTATION_PURPOSE
|
||||
|
||||
//Platform specific includes
|
||||
#if defined(WIN32) || defined(WIN64)
|
||||
#include "CryWindows.h"
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void C3DEngine::CheckAddLight(CDLight* pLight, const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
if (pLight->m_Id < 0)
|
||||
{
|
||||
GetRenderer()->EF_ADDDlight(pLight, passInfo);
|
||||
assert(pLight->m_Id >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
float C3DEngine::GetLightAmount(CDLight* pLight, const AABB& objBox)
|
||||
{
|
||||
// find amount of light
|
||||
float fDist = sqrt_tpl(Distance::Point_AABBSq(pLight->m_Origin, objBox));
|
||||
float fLightAttenuation = (pLight->m_Flags & DLF_DIRECTIONAL) ? 1.f : 1.f - (fDist) / (pLight->m_fRadius);
|
||||
if (fLightAttenuation < 0)
|
||||
{
|
||||
fLightAttenuation = 0;
|
||||
}
|
||||
|
||||
float fLightAmount =
|
||||
(pLight->m_Color.r + pLight->m_Color.g + pLight->m_Color.b) * 0.233f +
|
||||
(pLight->GetSpecularMult()) * 0.1f;
|
||||
|
||||
return fLightAmount * fLightAttenuation;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
float C3DEngine::GetWaterLevel()
|
||||
{
|
||||
if (OceanToggle::IsActive())
|
||||
{
|
||||
return OceanRequest::GetOceanLevel();
|
||||
}
|
||||
return m_pOcean ? m_pOcean->GetWaterLevel() : WATER_LEVEL_UNKNOWN;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool C3DEngine::IsTessellationAllowed(const CRenderObject* pObj, const SRenderingPassInfo& passInfo, bool bIgnoreShadowPass) const
|
||||
{
|
||||
#ifdef MESH_TESSELLATION_ENGINE
|
||||
assert(pObj && GetCVars());
|
||||
bool rendererTessellation;
|
||||
GetRenderer()->EF_Query(EFQ_MeshTessellation, rendererTessellation);
|
||||
if (pObj->m_fDistance < GetCVars()->e_TessellationMaxDistance
|
||||
&& GetCVars()->e_Tessellation
|
||||
&& rendererTessellation
|
||||
&& !(pObj->m_ObjFlags & FOB_DISSOLVE)) // dissolve is not working with tessellation for now
|
||||
{
|
||||
bool bAllowTessellation = true;
|
||||
|
||||
// Check if rendering into shadow map and enable tessellation only if allowed
|
||||
if (!bIgnoreShadowPass && passInfo.IsShadowPass())
|
||||
{
|
||||
if (IsTessellationAllowedForShadowMap(passInfo))
|
||||
{
|
||||
// NOTE: This might be useful for game projects
|
||||
// Use tessellation only for objects visible in main view
|
||||
// Shadows will switch to non-tessellated when caster gets out of view
|
||||
IRenderNode* pRN = (IRenderNode*)pObj->m_pRenderNode;
|
||||
if (pRN)
|
||||
{
|
||||
bAllowTessellation = (pRN->IsRenderNode() && (pRN->GetDrawFrame() > passInfo.GetFrameID() - 10));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bAllowTessellation = false;
|
||||
}
|
||||
}
|
||||
|
||||
return bAllowTessellation;
|
||||
}
|
||||
#endif //#ifdef MESH_TESSELLATION_ENGINE
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void C3DEngine::CreateRNTmpData(CRNTmpData** ppInfo, IRenderNode* pRNode, const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
// m_checkCreateRNTmpData lock scope
|
||||
{
|
||||
AUTO_LOCK(m_checkCreateRNTmpData);
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
if (*ppInfo)
|
||||
{
|
||||
return; // check if another thread already intialized ppInfo
|
||||
}
|
||||
// make sure element is allocated
|
||||
if (m_LTPRootFree.pNext == &m_LTPRootFree)
|
||||
{
|
||||
CRNTmpData* pNew = new CRNTmpData; //m_RNTmpDataPools.GetNewElement();
|
||||
pNew->Link(&m_LTPRootFree);
|
||||
}
|
||||
|
||||
// move element from m_LTPRootFree to m_LTPRootUsed
|
||||
CRNTmpData* pElem = m_LTPRootFree.pNext;
|
||||
pElem->Unlink();
|
||||
pElem->Link(&m_LTPRootUsed);
|
||||
|
||||
pElem->pOwnerRef = ppInfo;
|
||||
pElem->nFrameInfoId = GetFrameInfoId(ppInfo, passInfo.GetMainFrameID());
|
||||
|
||||
assert(!pElem->pOwnerRef || !(*pElem->pOwnerRef));
|
||||
memset(&pElem->userData, 0, sizeof(pElem->userData));
|
||||
|
||||
|
||||
// Add a memory barrier that the write to nFrameInfoID is visible
|
||||
// before *ppInfo is written, else we have a race condtition in
|
||||
// CheckCreateRNTmpData as we don't use a lock there
|
||||
// for performance reasons
|
||||
MemoryBarrier();
|
||||
|
||||
*ppInfo = pElem;
|
||||
}
|
||||
|
||||
if (pRNode)
|
||||
{
|
||||
pRNode->OnRenderNodeBecomeVisible(passInfo); // Internally uses the just assigned RNTmpData pointer i.e IRenderNode::m_pRNTmpData ...
|
||||
|
||||
if (IVisArea* pVisArea = pRNode->GetEntityVisArea())
|
||||
{
|
||||
pRNode->m_pRNTmpData->userData.m_pClipVolume = pVisArea;
|
||||
}
|
||||
else if (GetClipVolumeManager()->IsClipVolumeRequired(pRNode))
|
||||
{
|
||||
GetClipVolumeManager()->UpdateEntityClipVolume(pRNode->GetPos(), pRNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void C3DEngine::RenderRenderNode_ShadowPass(IShadowCaster* pShadowCaster, const SRenderingPassInfo& passInfo, [[maybe_unused]] AZ::LegacyJobExecutor* pJobExecutor)
|
||||
{
|
||||
assert(passInfo.IsShadowPass());
|
||||
|
||||
SRendItemSorter rendItemSorter = SRendItemSorter::CreateShadowPassRendItemSorter(passInfo);
|
||||
|
||||
if (!pShadowCaster->IsRenderNode())
|
||||
{
|
||||
const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
|
||||
const AABB objBox = pShadowCaster->GetBBoxVirtual();
|
||||
|
||||
SRendParams rParams;
|
||||
rParams.fDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
|
||||
rParams.lodValue = pShadowCaster->ComputeLod(0, passInfo);
|
||||
rParams.rendItemSorter = rendItemSorter.GetValue();
|
||||
|
||||
pShadowCaster->Render(rParams, passInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
IRenderNode* pRenderNode = static_cast<IRenderNode*>(pShadowCaster);
|
||||
if ((pRenderNode->m_dwRndFlags & ERF_HIDDEN) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int nStaticObjectLod = -1;
|
||||
if (passInfo.GetShadowMapType() == SRenderingPassInfo::SHADOW_MAP_CACHED)
|
||||
{
|
||||
nStaticObjectLod = GetCVars()->e_ShadowsCacheObjectLod;
|
||||
}
|
||||
else if (passInfo.GetShadowMapType() == SRenderingPassInfo::SHADOW_MAP_CACHED_MGPU_COPY)
|
||||
{
|
||||
nStaticObjectLod = pRenderNode->m_cStaticShadowLod;
|
||||
}
|
||||
|
||||
Get3DEngine()->CheckCreateRNTmpData(&pRenderNode->m_pRNTmpData, pRenderNode, passInfo);
|
||||
|
||||
int wantedLod = pRenderNode->m_pRNTmpData->userData.nWantedLod;
|
||||
|
||||
if (GetCVars()->e_LodForceUpdate && m_pObjManager)
|
||||
{
|
||||
const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
|
||||
const AABB objBox = pRenderNode->GetBBoxVirtual();
|
||||
float fDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
|
||||
wantedLod = m_pObjManager->GetObjectLOD(pRenderNode, fDistance);
|
||||
}
|
||||
|
||||
if (pRenderNode->GetShadowLodBias() != IRenderNode::SHADOW_LODBIAS_DISABLE)
|
||||
{
|
||||
if (passInfo.IsShadowPass() && (pRenderNode->GetDrawFrame(0) < (passInfo.GetFrameID() - 10)))
|
||||
{
|
||||
wantedLod += GetCVars()->e_ShadowsLodBiasInvis;
|
||||
}
|
||||
wantedLod += GetCVars()->e_ShadowsLodBiasFixed;
|
||||
wantedLod += pRenderNode->GetShadowLodBias();
|
||||
}
|
||||
|
||||
if (nStaticObjectLod >= 0)
|
||||
{
|
||||
wantedLod = nStaticObjectLod;
|
||||
}
|
||||
|
||||
{
|
||||
const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
|
||||
const AABB objBox = pRenderNode->GetBBoxVirtual();
|
||||
SRendParams rParams;
|
||||
rParams.fDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
|
||||
rParams.lodValue = pRenderNode->ComputeLod(wantedLod, passInfo);
|
||||
rParams.rendItemSorter = rendItemSorter.GetValue();
|
||||
rParams.pRenderNode = pRenderNode;
|
||||
pRenderNode->Render(rParams, passInfo);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
ITimeOfDay* C3DEngine::GetTimeOfDay()
|
||||
{
|
||||
CTimeOfDay* tod = m_pTimeOfDay;
|
||||
|
||||
if (!tod)
|
||||
{
|
||||
tod = new CTimeOfDay;
|
||||
m_pTimeOfDay = tod;
|
||||
}
|
||||
|
||||
return tod;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void C3DEngine::TraceFogVolumes(const Vec3& vPos, const AABB& objBBox, SFogVolumeData& fogVolData, const SRenderingPassInfo& passInfo, bool fogVolumeShadingQuality)
|
||||
{
|
||||
CFogVolumeRenderNode::TraceFogVolumes(vPos, objBBox, fogVolData, passInfo, fogVolumeShadingQuality);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void C3DEngine::AsyncOctreeUpdate(IRenderNode* pEnt, int nSID, [[maybe_unused]] int nSIDConsideredSafe, uint32 nFrameID, bool bUnRegisterOnly)
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
#ifdef _DEBUG // crash test basically
|
||||
const char* szClass = pEnt->GetEntityClassName();
|
||||
const char* szName = pEnt->GetName();
|
||||
if (!szName[0] && !szClass[0])
|
||||
{
|
||||
Warning("I3DEngine::RegisterEntity: Entity undefined"); // do not register undefined objects
|
||||
}
|
||||
// if(strstr(szName,"Dude"))
|
||||
// int y=0;
|
||||
#endif
|
||||
|
||||
IF (bUnRegisterOnly, 0)
|
||||
{
|
||||
UnRegisterEntityImpl(pEnt);
|
||||
return;
|
||||
}
|
||||
;
|
||||
|
||||
AABB aabb;
|
||||
pEnt->FillBBox(aabb);
|
||||
float fObjRadiusSqr = aabb.GetRadiusSqr();
|
||||
EERType eERType = pEnt->GetRenderNodeType();
|
||||
|
||||
#ifdef SUPP_HMAP_OCCL
|
||||
if (pEnt->m_pRNTmpData)
|
||||
{
|
||||
pEnt->m_pRNTmpData->userData.m_OcclState.vLastVisPoint.Set(0, 0, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
const unsigned int dwRndFlags = pEnt->GetRndFlags();
|
||||
|
||||
if (!(dwRndFlags & ERF_RENDER_ALWAYS) && !(dwRndFlags & ERF_CASTSHADOWMAPS))
|
||||
{
|
||||
if (GetCVars()->e_ObjFastRegister && pEnt->m_pOcNode && ((COctreeNode*)pEnt->m_pOcNode)->IsRightNode(aabb, fObjRadiusSqr, pEnt->m_fWSMaxViewDist))
|
||||
{ // same octree node
|
||||
Vec3 vEntCenter = GetEntityRegisterPoint(pEnt);
|
||||
|
||||
IVisArea* pVisArea = pEnt->GetEntityVisArea();
|
||||
if (pVisArea && pVisArea->IsPointInsideVisArea(vEntCenter))
|
||||
{
|
||||
return; // same visarea
|
||||
}
|
||||
IVisArea* pVisAreaFromPos = (!m_pVisAreaManager || dwRndFlags & ERF_OUTDOORONLY) ? NULL : GetVisAreaManager()->GetVisAreaFromPos(vEntCenter);
|
||||
if (pVisAreaFromPos == pVisArea)
|
||||
{
|
||||
// NOTE: can only get here when pVisArea==NULL due to 'same visarea' check above. So check for changed clip volume
|
||||
if (GetClipVolumeManager()->IsClipVolumeRequired(pEnt))
|
||||
{
|
||||
GetClipVolumeManager()->UpdateEntityClipVolume(vEntCenter, pEnt);
|
||||
}
|
||||
|
||||
return; // same visarea or same outdoor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pEnt->m_pOcNode)
|
||||
{
|
||||
UnRegisterEntityImpl(pEnt);
|
||||
}
|
||||
else if (GetCVars()->e_StreamCgf && (eERType == eERType_RenderComponent || eERType == eERType_DynamicMeshRenderComponent || eERType == eERType_GeomCache))
|
||||
{ // Temporary solution: Force streaming priority update for objects that was not registered before
|
||||
// and was not visible before since usual prediction system was not able to detect them
|
||||
|
||||
if ((uint32)pEnt->GetDrawFrame(0) < nFrameID - 16)
|
||||
{
|
||||
// defer the render node streaming priority update still we have a correct 3D Engine camera
|
||||
int nElementID = m_deferredRenderComponentStreamingPriorityUpdates.Find(pEnt);
|
||||
if (nElementID == -1) // only add elements once
|
||||
{
|
||||
m_deferredRenderComponentStreamingPriorityUpdates.push_back(pEnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pEnt->m_fWSMaxViewDist = pEnt->GetMaxViewDist();
|
||||
|
||||
bool useVisAreas = true;
|
||||
|
||||
if (eERType != eERType_Light)
|
||||
{
|
||||
if (fObjRadiusSqr > sqr(MAX_VALID_OBJECT_VOLUME) || !_finite(fObjRadiusSqr))
|
||||
{
|
||||
Warning("I3DEngine::RegisterEntity: Object has invalid bbox: name: %s, class name: %s, GetRadius() = %.2f",
|
||||
pEnt->GetName(), pEnt->GetEntityClassName(), fObjRadiusSqr);
|
||||
return; // skip invalid objects - usually only objects with invalid very big scale will reach this point
|
||||
}
|
||||
|
||||
if (dwRndFlags & ERF_RENDER_ALWAYS)
|
||||
{
|
||||
if (m_lstAlwaysVisible.Find(pEnt) < 0)
|
||||
{
|
||||
m_lstAlwaysVisible.Add(pEnt);
|
||||
}
|
||||
|
||||
if (dwRndFlags & ERF_HUD)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pEnt->m_dwRndFlags & ERF_OUTDOORONLY)
|
||||
{
|
||||
useVisAreas = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLightEntity* pLight = (CLightEntity*)pEnt;
|
||||
uint32 lightFlag = pLight->m_light.m_Flags;
|
||||
if ((lightFlag & DLF_ATTACH_TO_SUN) || //If the light is attached to the sun, we need to make sure it renders even the entity is not in view port
|
||||
(lightFlag & (DLF_IGNORES_VISAREAS | DLF_DEFERRED_LIGHT | DLF_THIS_AREA_ONLY)) == (DLF_IGNORES_VISAREAS | DLF_DEFERRED_LIGHT)
|
||||
)
|
||||
{
|
||||
if (m_lstAlwaysVisible.Find(pEnt) < 0)
|
||||
{
|
||||
m_lstAlwaysVisible.Add(pEnt);
|
||||
}
|
||||
}
|
||||
|
||||
if (lightFlag & DLF_IGNORES_VISAREAS)
|
||||
{
|
||||
useVisAreas = false;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Check for occlusion proxy.
|
||||
{
|
||||
CStatObj* pStatObj = (CStatObj*)pEnt->GetEntityStatObj();
|
||||
if (pStatObj)
|
||||
{
|
||||
if (pStatObj->m_bHaveOcclusionProxy)
|
||||
{
|
||||
pEnt->m_dwRndFlags |= ERF_GOOD_OCCLUDER;
|
||||
pEnt->m_nInternalFlags |= IRenderNode::HAS_OCCLUSION_PROXY;
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
if (!useVisAreas || !(m_pVisAreaManager && m_pVisAreaManager->SetEntityArea(pEnt, aabb, fObjRadiusSqr)))
|
||||
{
|
||||
if (m_pObjectsTree == nullptr)
|
||||
{
|
||||
AZ::Aabb terrainAabb = AZ::Aabb::CreateFromPoint(AZ::Vector3::CreateZero());
|
||||
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(terrainAabb, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb);
|
||||
m_pObjectsTree = COctreeNode::Create(nSID, AABB(Vec3(0, 0, 0), Vec3(terrainAabb.GetXExtent(), terrainAabb.GetYExtent(), terrainAabb.GetZExtent())), NULL);
|
||||
}
|
||||
|
||||
m_pObjectsTree->InsertObject(pEnt, aabb, fObjRadiusSqr, aabb.GetCenter());
|
||||
}
|
||||
|
||||
// update clip volume: use vis area if we have one, otherwise check if we're in the same volume as before. check other volumes as last resort only
|
||||
if (pEnt->m_pRNTmpData)
|
||||
{
|
||||
Vec3 vEntCenter = GetEntityRegisterPoint(pEnt);
|
||||
CRNTmpData::SRNUserData& userData = pEnt->m_pRNTmpData->userData;
|
||||
|
||||
if (IVisArea* pVisArea = pEnt->GetEntityVisArea())
|
||||
{
|
||||
userData.m_pClipVolume = pVisArea;
|
||||
}
|
||||
else if (GetClipVolumeManager()->IsClipVolumeRequired(pEnt))
|
||||
{
|
||||
GetClipVolumeManager()->UpdateEntityClipVolume(vEntCenter, pEnt);
|
||||
}
|
||||
}
|
||||
|
||||
// register decals, to clean up longer not renderes decals and their render meshes
|
||||
if (eERType == eERType_Decal)
|
||||
{
|
||||
m_decalRenderNodes.push_back((IDecalRenderNode*)pEnt);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool C3DEngine::UnRegisterEntityImpl(IRenderNode* pEnt)
|
||||
{
|
||||
// make sure we don't try to update the streaming priority if an object
|
||||
// was added and removed in the same frame
|
||||
int nElementID = m_deferredRenderComponentStreamingPriorityUpdates.Find(pEnt);
|
||||
if (nElementID != -1)
|
||||
{
|
||||
m_deferredRenderComponentStreamingPriorityUpdates.DeleteFastUnsorted(nElementID);
|
||||
}
|
||||
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
#ifdef _DEBUG // crash test basically
|
||||
const char* szClass = pEnt->GetEntityClassName();
|
||||
const char* szName = pEnt->GetName();
|
||||
if (!szName[0] && !szClass[0])
|
||||
{
|
||||
Warning("C3DEngine::RegisterEntity: Entity undefined");
|
||||
}
|
||||
#endif
|
||||
|
||||
EERType eRenderNodeType = pEnt->GetRenderNodeType();
|
||||
|
||||
bool bFound = false;
|
||||
|
||||
if (pEnt->m_pOcNode)
|
||||
{
|
||||
bFound = ((COctreeNode*)pEnt->m_pOcNode)->DeleteObject(pEnt);
|
||||
}
|
||||
|
||||
if (pEnt->m_dwRndFlags & ERF_RENDER_ALWAYS || (eRenderNodeType == eERType_Light) || (eRenderNodeType == eERType_FogVolume))
|
||||
{
|
||||
m_lstAlwaysVisible.Delete(pEnt);
|
||||
}
|
||||
|
||||
if (eRenderNodeType == eERType_Decal)
|
||||
{
|
||||
std::vector<IDecalRenderNode*>::iterator it = std::find(m_decalRenderNodes.begin(), m_decalRenderNodes.end(), (IDecalRenderNode*)pEnt);
|
||||
if (it != m_decalRenderNodes.end())
|
||||
{
|
||||
m_decalRenderNodes.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
if (CClipVolumeManager* pClipVolumeManager = GetClipVolumeManager())
|
||||
{
|
||||
pClipVolumeManager->UnregisterRenderNode(pEnt);
|
||||
}
|
||||
|
||||
return bFound;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
Vec3 C3DEngine::GetEntityRegisterPoint(IRenderNode* pEnt)
|
||||
{
|
||||
AABB aabb;
|
||||
pEnt->FillBBox(aabb);
|
||||
|
||||
Vec3 vPoint;
|
||||
|
||||
if (pEnt->m_dwRndFlags & ERF_REGISTER_BY_POSITION)
|
||||
{
|
||||
vPoint = pEnt->GetPos();
|
||||
|
||||
if (pEnt->GetRenderNodeType() != eERType_Light)
|
||||
{
|
||||
// check for valid position
|
||||
if (aabb.GetDistanceSqr(vPoint) > sqr(128.f))
|
||||
{
|
||||
Warning("I3DEngine::RegisterEntity: invalid entity position: Name: %s, Class: %s, Pos=(%.1f,%.1f,%.1f), BoxMin=(%.1f,%.1f,%.1f), BoxMax=(%.1f,%.1f,%.1f)",
|
||||
pEnt->GetName(), pEnt->GetEntityClassName(),
|
||||
pEnt->GetPos().x, pEnt->GetPos().y, pEnt->GetPos().z,
|
||||
pEnt->GetBBox().min.x, pEnt->GetBBox().min.y, pEnt->GetBBox().min.z,
|
||||
pEnt->GetBBox().max.x, pEnt->GetBBox().max.y, pEnt->GetBBox().max.z
|
||||
);
|
||||
}
|
||||
// clamp by bbox
|
||||
vPoint.CheckMin(aabb.max);
|
||||
vPoint.CheckMax(aabb.min + Vec3(0, 0, .5f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vPoint = aabb.GetCenter();
|
||||
}
|
||||
|
||||
return vPoint;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
Vec3 C3DEngine::GetSunDirNormalized() const
|
||||
{
|
||||
return m_vSunDirNormalized;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
|
||||
#include "3dEngine.h"
|
||||
#include "Ocean.h"
|
||||
#include "StatObj.h"
|
||||
#include "ObjMan.h"
|
||||
#include "MatMan.h"
|
||||
#include "VisAreas.h"
|
||||
#include "ObjectsTree.h"
|
||||
|
||||
#include <CryPath.h>
|
||||
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||
#include <MathConversion.h>
|
||||
#include <StatObjBus.h>
|
||||
#include <PakLoadDataUtils.h>
|
||||
#include <AzCore/Console/IConsole.h>
|
||||
|
||||
|
||||
#define SIGC_HIDEABILITY BIT(3)
|
||||
#define SIGC_HIDEABILITYSECONDARY BIT(4)
|
||||
#define SIGC_PROCEDURALLYANIMATED BIT(6)
|
||||
#define SIGC_CASTSHADOW BIT(7) // Deprecated
|
||||
#define SIGC_RECVSHADOW BIT(8)
|
||||
#define SIGC_DYNAMICDISTANCESHADOWS BIT(9)
|
||||
#define SIGC_USEALPHABLENDING BIT(10)
|
||||
#define SIGC_RANDOMROTATION BIT(12)
|
||||
#define SIGC_ALLOWINDOOR BIT(13)
|
||||
|
||||
// Bits 13-14 reserved for player hideability
|
||||
#define SIGC_PLAYERHIDEABLE_LOWBIT (13)
|
||||
#define SIGC_PLAYERHIDEABLE_MASK BIT(13) | BIT(14)
|
||||
|
||||
#define SIGC_CASTSHADOW_MINSPEC_SHIFT (15)
|
||||
|
||||
// Get the number of bits needed for the maximum spec level
|
||||
#define SIGC_CASTSHADOW_MINSPEC_MASK_NUM_BITS_NEEDED (IntegerLog2(uint32(END_CONFIG_SPEC_ENUM - 1)) + 1)
|
||||
|
||||
// Create a mask based on the number of bits needed
|
||||
#define SIGC_CASTSHADOW_MINSPEC_MASK_BITS ((1 << SIGC_CASTSHADOW_MINSPEC_MASK_NUM_BITS_NEEDED) - 1)
|
||||
#define SIGC_CASTSHADOW_MINSPEC_MASK (SIGC_CASTSHADOW_MINSPEC_MASK_BITS << SIGC_CASTSHADOW_MINSPEC_SHIFT)
|
||||
|
||||
AZ_CVAR(float, bg_DefaultMaxOctreeWorldSize, 4096.0f, nullptr, AZ::ConsoleFunctorFlags::NeedsReload, "Default world size to use for the octree when terrain is not present.");
|
||||
|
||||
bool C3DEngine::CreateOctree(float maxRootOctreeNodeSize)
|
||||
{
|
||||
float rootOctreeNodeSize = (maxRootOctreeNodeSize > 0.0f) ? maxRootOctreeNodeSize : bg_DefaultMaxOctreeWorldSize;
|
||||
COctreeNode* newOctreeNode = COctreeNode::Create(DEFAULT_SID, AABB(Vec3(0), Vec3(rootOctreeNodeSize)), NULL);
|
||||
if (!newOctreeNode)
|
||||
{
|
||||
Error("Failed to create octree with initial world size=%f", rootOctreeNodeSize);
|
||||
return false;
|
||||
}
|
||||
SetObjectTree(newOctreeNode);
|
||||
Cry3DEngineBase::GetObjManager()->GetListStaticTypes().PreAllocate(1, 1);
|
||||
Cry3DEngineBase::GetObjManager()->GetListStaticTypes()[DEFAULT_SID].Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void C3DEngine::DestroyOctree()
|
||||
{
|
||||
COctreeNode* objectTree = GetObjectTree();
|
||||
if (objectTree)
|
||||
{
|
||||
delete objectTree;
|
||||
SetObjectTree(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
#define RAD2BYTE(x) ((x)*255.0f / float(g_PI2))
|
||||
#define BYTE2RAD(x) ((x)* float(g_PI2) / 255.0f)
|
||||
|
||||
#include "TypeInfo_impl.h"
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : objects container, streaming, common part for indoor and outdoor sectors
|
||||
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
|
||||
CBasicArea::~CBasicArea()
|
||||
{
|
||||
delete m_pObjectsTree;
|
||||
m_pObjectsTree = NULL;
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_BASICAREA_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_BASICAREA_H
|
||||
#pragma once
|
||||
|
||||
#define COPY_MEMBER_SAVE(_dst, _src, _name) { (_dst)->_name = (_src)->_name; }
|
||||
#define COPY_MEMBER_LOAD(_dst, _src, _name) { (_dst)->_name = (_src)->_name; }
|
||||
|
||||
enum EObjList
|
||||
{
|
||||
DYNAMIC_OBJECTS = 0,
|
||||
STATIC_OBJECTS,
|
||||
PROC_OBJECTS,
|
||||
ENTITY_LISTS_NUM
|
||||
};
|
||||
|
||||
struct SRNInfo
|
||||
{
|
||||
SRNInfo()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
SRNInfo(IRenderNode* _pNode)
|
||||
{
|
||||
fMaxViewDist = _pNode->m_fWSMaxViewDist;
|
||||
AABB aabbBox = _pNode->GetBBox();
|
||||
objSphere.center = aabbBox.GetCenter();
|
||||
objSphere.radius = aabbBox.GetRadius();
|
||||
pNode = _pNode;
|
||||
nRType = _pNode->GetRenderNodeType();
|
||||
|
||||
/*#ifdef _DEBUG
|
||||
erType = _pNode->GetRenderNodeType();
|
||||
cry_strcpy(szName, _pNode->GetName());
|
||||
#endif*/
|
||||
}
|
||||
|
||||
bool operator == (const IRenderNode* _pNode) const { return (pNode == _pNode); }
|
||||
bool operator == (const SRNInfo& rOther) const { return (pNode == rOther.pNode); }
|
||||
|
||||
float fMaxViewDist;
|
||||
Sphere objSphere;
|
||||
IRenderNode* pNode;
|
||||
EERType nRType;
|
||||
/*#ifdef _DEBUG
|
||||
EERType erType;
|
||||
char szName[32];
|
||||
#endif*/
|
||||
};
|
||||
|
||||
struct SCasterInfo
|
||||
{
|
||||
SCasterInfo()
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
SCasterInfo(IRenderNode* _pNode, float fMaxDist)
|
||||
{
|
||||
fMaxCastingDist = fMaxDist;
|
||||
objBox = _pNode->GetBBox();
|
||||
objSphere.center = objBox.GetCenter();
|
||||
objSphere.radius = objBox.GetRadius();
|
||||
pNode = _pNode;
|
||||
nRType = _pNode->GetRenderNodeType();
|
||||
nRenderNodeFlags = _pNode->GetRndFlags();
|
||||
bCanExecuteAsRenderJob = _pNode->CanExecuteRenderAsJob();
|
||||
}
|
||||
|
||||
SCasterInfo(IRenderNode* _pNode, float fMaxDist, EERType renderNodeType)
|
||||
{
|
||||
fMaxCastingDist = fMaxDist;
|
||||
_pNode->FillBBox(objBox);
|
||||
objSphere.center = objBox.GetCenter();
|
||||
objSphere.radius = objBox.GetRadius();
|
||||
pNode = _pNode;
|
||||
nRType = renderNodeType;
|
||||
nRenderNodeFlags = _pNode->GetRndFlags();
|
||||
bCanExecuteAsRenderJob = _pNode->CanExecuteRenderAsJob();
|
||||
}
|
||||
|
||||
bool operator == (const IRenderNode* _pNode) const { return (pNode == _pNode); }
|
||||
bool operator == (const SCasterInfo& rOther) const { return (pNode == rOther.pNode); }
|
||||
|
||||
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const { /*nothing*/}
|
||||
|
||||
float fMaxCastingDist;
|
||||
Sphere objSphere;
|
||||
AABB objBox;
|
||||
IRenderNode* pNode;
|
||||
uint32 nGSMFrameId;
|
||||
EERType nRType;
|
||||
bool bCanExecuteAsRenderJob;
|
||||
uint32 nRenderNodeFlags;
|
||||
};
|
||||
|
||||
#define UPDATE_PTR_AND_SIZE(_pData, _nDataSize, _SIZE_PLUS) \
|
||||
{ \
|
||||
_pData += (_SIZE_PLUS); \
|
||||
_nDataSize -= (_SIZE_PLUS); \
|
||||
assert(_nDataSize >= 0); \
|
||||
} \
|
||||
|
||||
enum EAreaType
|
||||
{
|
||||
eAreaType_Undefined,
|
||||
eAreaType_OcNode,
|
||||
eAreaType_VisArea
|
||||
};
|
||||
|
||||
struct CBasicArea
|
||||
: public Cry3DEngineBase
|
||||
{
|
||||
CBasicArea()
|
||||
{
|
||||
m_boxArea.min = m_boxArea.max = Vec3(0, 0, 0);
|
||||
m_pObjectsTree = NULL;
|
||||
}
|
||||
|
||||
~CBasicArea();
|
||||
|
||||
void CompileObjects(int nListId); // optimize objects lists for rendering
|
||||
|
||||
class COctreeNode* m_pObjectsTree;
|
||||
|
||||
AABB m_boxArea; // bbox containing everything in sector including child sectors
|
||||
AABB m_boxStatics; // bbox containing only objects in STATIC_OBJECTS list of this node and height-map
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_BASICAREA_H
|
||||
@@ -1,19 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
#include "CCullRenderer.h"
|
||||
|
||||
namespace NAsyncCull
|
||||
{
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,818 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
#include "CCullThread.h"
|
||||
#include "ObjMan.h"
|
||||
#include "CCullRenderer.h"
|
||||
#include <AzCore/Jobs/Job.h>
|
||||
#include <AzCore/Jobs/JobFunction.h>
|
||||
|
||||
typedef NAsyncCull::CCullRenderer<CULL_SIZEX, CULL_SIZEY> tdCullRasterizer;
|
||||
|
||||
volatile static NAsyncCull::tdVertexCache g_VertexCache;
|
||||
uint8 g_RasterizerBuffer[sizeof(tdCullRasterizer) + 16];
|
||||
tdCullRasterizer* g_Rasterizer;
|
||||
#define RASTERIZER (*g_Rasterizer)
|
||||
|
||||
namespace NAsyncCull
|
||||
{
|
||||
const NVMath::vec4 MaskNot3 = NVMath::Vec4(~3u, ~0u, ~0u, ~0u);
|
||||
|
||||
CCullThread::CCullThread()
|
||||
: m_Enabled(false)
|
||||
, m_Active(false)
|
||||
, m_nPrepareState(IDLE)
|
||||
, m_OCMMeshCount(0)
|
||||
, m_OCMInstCount(0)
|
||||
, m_OCMOffsetInstances(0)
|
||||
{
|
||||
size_t Buffer = reinterpret_cast<size_t>(g_RasterizerBuffer);
|
||||
Buffer += 127;
|
||||
Buffer &= ~127;
|
||||
g_Rasterizer = new(reinterpret_cast<void*>(Buffer))tdCullRasterizer();
|
||||
|
||||
m_NearPlane = 0;
|
||||
m_FarPlane = 0;
|
||||
m_NearestMax = 0;
|
||||
}
|
||||
|
||||
bool CCullThread::LoadLevel(const char* pFolderName)
|
||||
{
|
||||
m_OCMBuffer.resize(0);
|
||||
AZ::IO::HandleType fileHandle = gEnv->pCryPak->FOpen((string(pFolderName) + "/occluder.ocm").c_str(), "rbx");
|
||||
if (fileHandle == AZ::IO::InvalidHandle)
|
||||
{
|
||||
//__debugbreak();
|
||||
return false;
|
||||
}
|
||||
gEnv->pCryPak->FSeek(fileHandle, 0, SEEK_END);
|
||||
const size_t Size = gEnv->pCryPak->FTell(fileHandle);
|
||||
gEnv->pCryPak->FSeek(fileHandle, 0L, SEEK_SET);
|
||||
m_OCMBuffer.reserve(Size + 144 * 3 + 16); //48tri*9byte padding for unrolled loop in rasterization without special case (not 144 algined poly count)
|
||||
//16 for alignment
|
||||
m_OCMBuffer.resize(Size);
|
||||
size_t BufferOffset = reinterpret_cast<size_t>(&m_OCMBuffer[0]);
|
||||
BufferOffset = (BufferOffset + 15) & ~15;
|
||||
m_pOCMBufferAligned = reinterpret_cast<uint8*>(BufferOffset);
|
||||
|
||||
gEnv->pCryPak->FRead(m_pOCMBufferAligned, Size, fileHandle, false);
|
||||
gEnv->pCryPak->FClose(fileHandle);
|
||||
|
||||
const uint32 Version = Swap(*reinterpret_cast<uint32*>(&m_pOCMBufferAligned[0]));
|
||||
m_OCMMeshCount = *reinterpret_cast<uint32*>(&m_pOCMBufferAligned[4]);
|
||||
m_OCMInstCount = *reinterpret_cast<uint32*>(&m_pOCMBufferAligned[8]);
|
||||
m_OCMOffsetInstances = *reinterpret_cast<uint32*>(&m_pOCMBufferAligned[12]);
|
||||
|
||||
if (Version != ~3u && Version != ~4u)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR, "Unsupported occlusion mesh format version. Please reexport the occluder mesh.");
|
||||
stl::free_container(m_OCMBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_OCMOffsetInstances & 3)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR, "The occluder mesh contains invalid data. Please reexport the occluder mesh.");
|
||||
stl::free_container(m_OCMBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Version == ~3u) //bump to version ~4
|
||||
{
|
||||
m_OCMMeshCount = Swap(m_OCMMeshCount);
|
||||
m_OCMInstCount = Swap(m_OCMInstCount);
|
||||
m_OCMOffsetInstances = Swap(m_OCMOffsetInstances);
|
||||
PodArray<uint8> OCMBufferOut(Size * 8, Size * 8);
|
||||
uint8* pOut = &OCMBufferOut[0];
|
||||
*reinterpret_cast<uint32*>(&pOut[0]) = ~4u;//version
|
||||
*reinterpret_cast<uint32*>(&pOut[4]) = m_OCMMeshCount;
|
||||
*reinterpret_cast<uint32*>(&pOut[8]) = m_OCMInstCount;
|
||||
*reinterpret_cast<uint32*>(&pOut[12]) = m_OCMOffsetInstances;//needs to be patched at the end
|
||||
pOut += 16;
|
||||
uint8* pMeshes = &m_pOCMBufferAligned[0];//actually starts at 16, but MeshOffset is zero based
|
||||
uint8* pInstances = &m_pOCMBufferAligned[m_OCMOffsetInstances];
|
||||
std::map<uint32, uint32> Offsets;//<old Offset, new Offset>
|
||||
for (size_t a = 0; a < m_OCMInstCount; a++)
|
||||
{
|
||||
Matrix44 World(IDENTITY);
|
||||
uint8* pInstance = pInstances + a * (sizeof(int) + 12 * sizeof(float));//meshoffset+worldmatrix43
|
||||
uint32& MeshOffset = *reinterpret_cast<uint32*>(&pInstance[0]);
|
||||
float* pWorldMat = reinterpret_cast<float*>(&pInstance[4]);
|
||||
Swap(MeshOffset);
|
||||
Swap(pWorldMat[0x0]);
|
||||
Swap(pWorldMat[0x1]);
|
||||
Swap(pWorldMat[0x2]);
|
||||
Swap(pWorldMat[0x3]);
|
||||
Swap(pWorldMat[0x4]);
|
||||
Swap(pWorldMat[0x5]);
|
||||
Swap(pWorldMat[0x6]);
|
||||
Swap(pWorldMat[0x7]);
|
||||
Swap(pWorldMat[0x8]);
|
||||
Swap(pWorldMat[0x9]);
|
||||
Swap(pWorldMat[0xA]);
|
||||
Swap(pWorldMat[0xB]);
|
||||
|
||||
if (Offsets.find(MeshOffset) != Offsets.end())//already endian swapped?
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Offsets[MeshOffset] = static_cast<uint32>(pOut - &OCMBufferOut[0]);//zero based offset
|
||||
|
||||
uint8* pMesh = pMeshes + MeshOffset;
|
||||
uint16& QuadCount = *reinterpret_cast<uint16*>(pMesh);
|
||||
uint16& TriCount = *reinterpret_cast<uint16*>(pMesh + 2);
|
||||
Swap(QuadCount);
|
||||
Swap(TriCount);
|
||||
*reinterpret_cast<uint32*>(pOut) = TriCount + QuadCount / 4 * 6;
|
||||
pOut += 16;//to keep 16byte alignment
|
||||
|
||||
const size_t Quads16 = (reinterpret_cast<size_t>(pMesh + 4) + 15) & ~15;
|
||||
const size_t Tris16 = (Quads16 + QuadCount * 3 + 15) & ~15;
|
||||
const int8* pQuads = reinterpret_cast<const int8*>(Quads16);
|
||||
const int8* pTris = reinterpret_cast<const int8*>(Tris16);
|
||||
|
||||
for (size_t b = 0, S = QuadCount; b < S; b += 4)
|
||||
{
|
||||
const float x0 = *pQuads++;
|
||||
const float y0 = *pQuads++;
|
||||
const float z0 = *pQuads++;
|
||||
const float x1 = *pQuads++;
|
||||
const float y1 = *pQuads++;
|
||||
const float z1 = *pQuads++;
|
||||
const float x2 = *pQuads++;
|
||||
const float y2 = *pQuads++;
|
||||
const float z2 = *pQuads++;
|
||||
const float x3 = *pQuads++;
|
||||
const float y3 = *pQuads++;
|
||||
const float z3 = *pQuads++;
|
||||
reinterpret_cast<float*>(pOut)[0x00] = x0;
|
||||
reinterpret_cast<float*>(pOut)[0x01] = y0;
|
||||
reinterpret_cast<float*>(pOut)[0x02] = z0;
|
||||
reinterpret_cast<float*>(pOut)[0x03] = 1.f;
|
||||
reinterpret_cast<float*>(pOut)[0x04] = x2;
|
||||
reinterpret_cast<float*>(pOut)[0x05] = y2;
|
||||
reinterpret_cast<float*>(pOut)[0x06] = z2;
|
||||
reinterpret_cast<float*>(pOut)[0x07] = 1.f;
|
||||
reinterpret_cast<float*>(pOut)[0x08] = x3;
|
||||
reinterpret_cast<float*>(pOut)[0x09] = y3;
|
||||
reinterpret_cast<float*>(pOut)[0x0a] = z3;
|
||||
reinterpret_cast<float*>(pOut)[0x0b] = 1.f;
|
||||
|
||||
reinterpret_cast<float*>(pOut)[0x0c] = x2;
|
||||
reinterpret_cast<float*>(pOut)[0x0d] = y2;
|
||||
reinterpret_cast<float*>(pOut)[0x0e] = z2;
|
||||
reinterpret_cast<float*>(pOut)[0x0f] = 1.f;
|
||||
reinterpret_cast<float*>(pOut)[0x10] = x0;
|
||||
reinterpret_cast<float*>(pOut)[0x11] = y0;
|
||||
reinterpret_cast<float*>(pOut)[0x12] = z0;
|
||||
reinterpret_cast<float*>(pOut)[0x13] = 1.f;
|
||||
reinterpret_cast<float*>(pOut)[0x14] = x1;
|
||||
reinterpret_cast<float*>(pOut)[0x15] = y1;
|
||||
reinterpret_cast<float*>(pOut)[0x16] = z1;
|
||||
reinterpret_cast<float*>(pOut)[0x17] = 1.f;
|
||||
pOut += 0x18 * sizeof(float);
|
||||
}
|
||||
for (size_t c = 0, S = TriCount; c < S; c++)
|
||||
{
|
||||
const float x = *pTris++;
|
||||
const float y = *pTris++;
|
||||
const float z = *pTris++;
|
||||
reinterpret_cast<float*>(pOut)[0x00] = x;
|
||||
reinterpret_cast<float*>(pOut)[0x01] = y;
|
||||
reinterpret_cast<float*>(pOut)[0x02] = z;
|
||||
reinterpret_cast<float*>(pOut)[0x03] = 1.f;
|
||||
pOut += 4 * sizeof(float);
|
||||
}
|
||||
}
|
||||
m_OCMOffsetInstances = static_cast<uint32>(pOut - &OCMBufferOut[0]);
|
||||
const size_t InstanceSize = m_OCMInstCount * (sizeof(int) + 12 * sizeof(float));
|
||||
memcpy(pOut, pInstances, InstanceSize);
|
||||
for (size_t a = 0; a < m_OCMInstCount; a++)
|
||||
{
|
||||
uint8* pInstance = pOut + a * (sizeof(int) + 12 * sizeof(float));//meshoffset+worldmatrix43
|
||||
uint32& MeshOffset = *reinterpret_cast<uint32*>(&pInstance[0]);
|
||||
MeshOffset = Offsets[MeshOffset];
|
||||
}
|
||||
pOut += InstanceSize;
|
||||
|
||||
m_OCMBuffer.resize(pOut - &OCMBufferOut[0]);
|
||||
size_t bufferOffset = reinterpret_cast<size_t>(&m_OCMBuffer[0]);
|
||||
bufferOffset = (bufferOffset + 15) & ~15;
|
||||
m_pOCMBufferAligned = reinterpret_cast<uint8*>(bufferOffset);
|
||||
memcpy(m_pOCMBufferAligned, &OCMBufferOut[0], m_OCMBuffer.size());
|
||||
}
|
||||
|
||||
// Integrity check: each mesh data must be aligned to 4 bytes
|
||||
uint8* pInstances = &m_pOCMBufferAligned[m_OCMOffsetInstances];
|
||||
for (size_t a = 0; a < m_OCMInstCount; a++)
|
||||
{
|
||||
uint8* pInstance = pInstances + a * (sizeof(int) + 12 * sizeof(float));//meshoffset+worldmatrix43
|
||||
uint32 MeshOffset = *reinterpret_cast<uint32*>(&pInstance[0]);
|
||||
if (MeshOffset & 3)
|
||||
{
|
||||
CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR, "The occluder mesh contains invalid data. Please reexport the occluder mesh.");
|
||||
stl::free_container(m_OCMBuffer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCullThread::UnloadLevel()
|
||||
{
|
||||
stl::free_container(m_OCMBuffer);
|
||||
m_pOCMBufferAligned = NULL;
|
||||
|
||||
m_OCMMeshCount = 0;
|
||||
m_OCMInstCount = 0;
|
||||
m_OCMOffsetInstances = 0;
|
||||
}
|
||||
|
||||
void CCullThread::PrepareCullbufferAsync(const CCamera& rCamera)
|
||||
{
|
||||
Matrix44 MatProj;
|
||||
Matrix44 MatView;
|
||||
Matrix44 MatViewProj;
|
||||
|
||||
#if !defined(_RELEASE) // debug code to catch double invocations of the prepare occlusion buffer job per frame
|
||||
static int _debug = -1;
|
||||
if (_debug == -1)
|
||||
{
|
||||
_debug = gEnv->pRenderer->GetFrameID(false);
|
||||
}
|
||||
else if (_debug == gEnv->pRenderer->GetFrameID(false))
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
else
|
||||
{
|
||||
_debug = gEnv->pRenderer->GetFrameID(false);
|
||||
}
|
||||
#endif
|
||||
|
||||
const CCamera& rCam = rCamera;
|
||||
|
||||
CCamera tmp_cam = m_pRenderer->GetCamera();
|
||||
m_pRenderer->SetCamera(rCam);
|
||||
m_pRenderer->GetModelViewMatrix(reinterpret_cast<f32*>(&MatView));
|
||||
m_pRenderer->GetProjectionMatrix(reinterpret_cast<f32*>(&MatProj));
|
||||
m_pRenderer->SetCamera(tmp_cam);
|
||||
|
||||
uint32 nReverseDepthEnabled = 0;
|
||||
m_pRenderer->EF_Query(EFQ_ReverseDepthEnabled, nReverseDepthEnabled);
|
||||
|
||||
if (nReverseDepthEnabled) // Convert to regular depth again. TODO: make occlusion culler work with reverse depth
|
||||
{
|
||||
MatProj.m22 = -MatProj.m22 + MatProj.m23;
|
||||
MatProj.m32 = -MatProj.m32 + MatProj.m33;
|
||||
}
|
||||
|
||||
m_ViewDir = rCam.GetViewdir();
|
||||
MatViewProj = MatView * MatProj;
|
||||
|
||||
MatViewProj.Transpose();
|
||||
|
||||
const float SCALEX = static_cast<float>(CULL_SIZEX / 2);
|
||||
const float SCALEY = static_cast<float>(CULL_SIZEY / 2);
|
||||
const Matrix44A MatScreen(SCALEX, 0.f, 0.f, SCALEX,
|
||||
0.f, -SCALEY, 0.f, SCALEY,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f);
|
||||
m_MatScreenViewProj = MatScreen * MatViewProj;
|
||||
m_MatScreenViewProjTransposed = m_MatScreenViewProj.GetTransposed();
|
||||
m_NearPlane = rCam.GetNearPlane();
|
||||
m_FarPlane = rCam.GetFarPlane();
|
||||
m_NearestMax = m_pRenderer->GetNearestRangeMax();
|
||||
|
||||
m_Position = rCam.GetPosition();
|
||||
|
||||
HWZBuffer.ZBufferSizeX = CULL_SIZEX;
|
||||
HWZBuffer.ZBufferSizeY = CULL_SIZEY;
|
||||
|
||||
GetObjManager()->BeginCulling();
|
||||
|
||||
m_nPrepareState = PREPARE_STARTED;
|
||||
m_Enabled = false;
|
||||
m_bCheckOcclusionRequested = 0;
|
||||
|
||||
RASTERIZER.Prepare();
|
||||
|
||||
m_PrepareBufferSync.PushCompletionFence();
|
||||
m_OcclusionJobExecutor.StartJob([this]()
|
||||
{
|
||||
this->PrepareOcclusion();
|
||||
}); // legacy: job.SetPriorityLevel(JobManager::eHighPriority); job.SetBlocking();
|
||||
}
|
||||
|
||||
void CCullThread::CullStart(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
// signal rasterizer that it should stop
|
||||
m_bCheckOcclusionRequested = 1;
|
||||
|
||||
// tell the job that the PPU is ready for occlusion culling, this call will
|
||||
// start the check occlusion job if the prepare step has finished, if not
|
||||
// the prepare job itself will start the culling job
|
||||
bool bNeedJobStart = false;
|
||||
{
|
||||
AUTO_LOCK(m_FollowUpLock);
|
||||
if (m_nPrepareState == PREPARE_DONE)
|
||||
{
|
||||
m_nPrepareState = CHECK_STARTED;
|
||||
bNeedJobStart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nPrepareState = CHECK_REQUESTED;
|
||||
*((SRenderingPassInfo*)m_passInfoForCheckOcclusion) = passInfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (bNeedJobStart)
|
||||
{
|
||||
m_OcclusionJobExecutor.StartJob([this, passInfo]()
|
||||
{
|
||||
this->CheckOcclusion(passInfo);
|
||||
}); // legacy: job.SetPriorityLevel(JobManager::eHighPriority);
|
||||
}
|
||||
}
|
||||
|
||||
void CCullThread::CullEnd(bool waitForOcclusionJobCompletion)
|
||||
{
|
||||
// If no frame was rendered, we need to remove the producer added in BeginCulling
|
||||
m_PrepareBufferSync.WaitForCompletion();
|
||||
|
||||
bool bNeedRemoveProducer = false;
|
||||
{
|
||||
if (m_nPrepareState != CHECK_STARTED && m_nPrepareState != IDLE)
|
||||
{
|
||||
bNeedRemoveProducer = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bNeedRemoveProducer)
|
||||
{
|
||||
GetObjManager()->RemoveCullJobProducer();
|
||||
m_nPrepareState = IDLE; // No producer so mark us as idle
|
||||
}
|
||||
|
||||
if (waitForOcclusionJobCompletion)
|
||||
{
|
||||
m_OcclusionJobExecutor.WaitForCompletion();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CCullThread::OutputMeshList()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
float DistToBox(Vec3 Center, Vec3 Extends, Vec3 ViewPos)
|
||||
{
|
||||
Vec3 Delta = (ViewPos - Center).abs();
|
||||
Delta = (Delta - Extends);
|
||||
Delta.x = max(Delta.x, 0.f);
|
||||
Delta.y = max(Delta.y, 0.f);
|
||||
Delta.z = max(Delta.z, 0.f);
|
||||
return Delta.x * Delta.x + Delta.y * Delta.y + Delta.z * Delta.z;
|
||||
}
|
||||
|
||||
void CCullThread::RasterizeZBuffer(uint32 PolyLimit)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
|
||||
|
||||
if (m_OCMInstCount == 0)
|
||||
{
|
||||
float fRed[4] = {1, 0, 0, 1};
|
||||
gEnv->pRenderer->Draw2dLabel(1.0f, 5.0f, 1.6f, fRed, false, "OCM file failed to load -> no occlusion checking possible!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint Tmp[16 * sizeof(float) * 2 + 16];
|
||||
const uint8* pMeshes = m_pOCMBufferAligned;//actually starts at 16, but MeshOffset is zero based
|
||||
uint8* pInstances = &m_pOCMBufferAligned[m_OCMOffsetInstances];
|
||||
|
||||
Matrix44A& rTmp0 = *reinterpret_cast<Matrix44A*>((reinterpret_cast<size_t>(Tmp) + 15) & ~15);
|
||||
Matrix44A& rTmp1 = *reinterpret_cast<Matrix44A*>((reinterpret_cast<size_t>(Tmp) + 15 + 64) & ~15);
|
||||
rTmp0 = m_MatScreenViewProj.GetTransposed();
|
||||
|
||||
int Visible = 0;
|
||||
int Invisible = 0;
|
||||
uint32 Poly = 0;
|
||||
float LastDist;
|
||||
uint8* pLastInstance = 0;
|
||||
|
||||
bool Swapped = true;
|
||||
for (size_t c = 0; c < 20 && Swapped; c++)//incrementally (max 20 rounds) bubblesort instances front to back
|
||||
{
|
||||
Swapped = false;
|
||||
LastDist = -1.f;
|
||||
for (size_t a = 0; a < m_OCMInstCount; a++)
|
||||
{
|
||||
Matrix44 World(IDENTITY);
|
||||
uint8* pInstance = pInstances + a * (sizeof(int) + 12 * sizeof(float));//meshoffset+worldmatrix43
|
||||
const uint32 MeshOffset = *reinterpret_cast<const uint32*>(&pInstance[0]);
|
||||
const float* pWorldMat = reinterpret_cast<const float*>(&pInstance[4]);
|
||||
memcpy(&World, (void*)pWorldMat, 12 * sizeof(float));
|
||||
|
||||
//simple incremental bubblesort
|
||||
const float Dist = (World.GetTranslation() - m_Position).GetLength();
|
||||
if (Dist < LastDist)
|
||||
{
|
||||
PREFAST_ASSUME(pLastInstance);
|
||||
Swapped = true;
|
||||
for (size_t b = 0; b < 13; b++)
|
||||
{
|
||||
std::swap(reinterpret_cast<uint32*>(pLastInstance)[b], reinterpret_cast<uint32*>(pInstance)[b]);
|
||||
}
|
||||
}
|
||||
|
||||
LastDist = Dist;
|
||||
pLastInstance = pInstance;
|
||||
}
|
||||
}
|
||||
|
||||
const bool EarlyOut = GetCVars()->e_CoverageBufferEarlyOut == 1;
|
||||
const int64 MaxEarlyOutDelay = (int64)(GetCVars()->e_CoverageBufferEarlyOutDelay * 1000.0f);
|
||||
LastDist = -1.f;
|
||||
|
||||
ITimer* pTimer = gEnv->pTimer;
|
||||
int64 StartTime = -1;
|
||||
|
||||
for (size_t a = 0; a < m_OCMInstCount && (PolyLimit == 0 || Poly < PolyLimit); a++)
|
||||
{
|
||||
// stop if MT need to run check occlusion
|
||||
if (EarlyOut && *const_cast<volatile int*>(&m_bCheckOcclusionRequested))
|
||||
{
|
||||
if (StartTime < 0)
|
||||
{
|
||||
StartTime = pTimer->GetAsyncTime().GetMicroSecondsAsInt64();
|
||||
}
|
||||
|
||||
int64 CurTime = pTimer->GetAsyncTime().GetMicroSecondsAsInt64();
|
||||
if (CurTime - StartTime > MaxEarlyOutDelay)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Matrix44 World(IDENTITY);
|
||||
uint8* pInstance = pInstances + a * (sizeof(int) + 12 * sizeof(float));//meshoffset+worldmatrix43
|
||||
const uint32 MeshOffset = *reinterpret_cast<volatile const uint32*>(&pInstance[0]);
|
||||
const float* pWorldMat = reinterpret_cast<const float*>(&pInstance[4]);
|
||||
memcpy(&World, (void*)pWorldMat, 12 * sizeof(float));
|
||||
|
||||
Vec3 Pos = World.GetTranslation(), Extend;
|
||||
Extend.x = (fabsf(World.m00) + fabsf(World.m01) + fabsf(World.m02)) * (127.f);
|
||||
Extend.y = (fabsf(World.m10) + fabsf(World.m11) + fabsf(World.m12)) * (127.f);
|
||||
Extend.z = (fabsf(World.m20) + fabsf(World.m21) + fabsf(World.m22)) * (127.f);
|
||||
|
||||
const int InFrustum = RASTERIZER.AABBInFrustum(reinterpret_cast<NVMath::vec4*>(&rTmp0), Pos - Extend, Pos + Extend, m_Position);
|
||||
if (!InFrustum)
|
||||
{
|
||||
Invisible++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
Visible++;
|
||||
}
|
||||
|
||||
rTmp1 = (m_MatScreenViewProj * World).GetTransposed();
|
||||
const uint8* pMesh = pMeshes + MeshOffset;
|
||||
const size_t TriCount = *reinterpret_cast<const uint32*>(pMesh);
|
||||
const size_t Tris16 = (reinterpret_cast<size_t>(pMesh + 4) + 15) & ~15;
|
||||
const int8* pTris = reinterpret_cast<const int8*>(Tris16);
|
||||
if (InFrustum & 2)
|
||||
{
|
||||
RASTERIZER.Rasterize<true>(reinterpret_cast<NVMath::vec4*>(&rTmp1), reinterpret_cast<const NVMath::vec4*>(pTris), TriCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
RASTERIZER.Rasterize<false>(reinterpret_cast<NVMath::vec4*>(&rTmp1), reinterpret_cast<const NVMath::vec4*>(pTris), TriCount);
|
||||
}
|
||||
Poly += TriCount;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_RELEASE)
|
||||
void CCullThread::CoverageBufferDebugDraw()
|
||||
{
|
||||
RASTERIZER.DrawDebug(m_pRenderer, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CCullThread::PrepareOcclusion()
|
||||
{
|
||||
if (!GetCVars()->e_CameraFreeze)
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
using namespace NVMath;
|
||||
|
||||
int bHWZBuffer = GetCVars()->e_CoverageBufferReproj;
|
||||
|
||||
if (bHWZBuffer > 3 && m_OCMBuffer.empty())
|
||||
{
|
||||
bHWZBuffer = 2;
|
||||
}
|
||||
|
||||
if ((bHWZBuffer & 3) > 0)
|
||||
{
|
||||
m_Enabled = RASTERIZER.DownLoadHWDepthBuffer(m_NearPlane, m_FarPlane, m_NearestMax, GetCVars()->e_CoverageBufferBias);
|
||||
}
|
||||
else
|
||||
{
|
||||
RASTERIZER.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
m_OcclusionJobExecutor.StartJob([this]()
|
||||
{
|
||||
this->PrepareOcclusion_ReprojectZBuffer();
|
||||
}); // legacy: job.SetPriorityLevel(JobManager::eHighPriority);
|
||||
}
|
||||
|
||||
void CCullThread::PrepareOcclusion_ReprojectZBuffer()
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
|
||||
|
||||
int bHWZBuffer = GetCVars()->e_CoverageBufferReproj;
|
||||
|
||||
if (bHWZBuffer > 3 && m_OCMBuffer.empty())
|
||||
{
|
||||
bHWZBuffer = 2;
|
||||
}
|
||||
|
||||
if (!GetCVars()->e_CameraFreeze && (bHWZBuffer & 3) > 0 && m_Enabled)
|
||||
{
|
||||
enum
|
||||
{
|
||||
nLinesPerJob = 8
|
||||
};
|
||||
m_nRunningReprojJobs = tdCullRasterizer::RESOLUTION_Y / nLinesPerJob;
|
||||
m_nRunningReprojJobsAfterMerge = tdCullRasterizer::RESOLUTION_Y / nLinesPerJob;
|
||||
for (int i = 0; i < tdCullRasterizer::RESOLUTION_Y; i += nLinesPerJob)
|
||||
{
|
||||
m_OcclusionJobExecutor.StartJob([this, i]()
|
||||
{
|
||||
this->PrepareOcclusion_ReprojectZBufferLine(i, nLinesPerJob);
|
||||
}); // legacy: job.SetPriorityLevel(JobManager::eHighPriority);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_OcclusionJobExecutor.StartJob([this]()
|
||||
{
|
||||
this->PrepareOcclusion_RasterizeZBuffer();
|
||||
}); // job.SetPriorityLevel(JobManager::eHighPriority);
|
||||
}
|
||||
}
|
||||
|
||||
void CCullThread::PrepareOcclusion_ReprojectZBufferLine(int nStartLine, int nNumLines)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
|
||||
|
||||
if (!GetCVars()->e_CameraFreeze)
|
||||
{
|
||||
uint Tmp[80];
|
||||
Matrix44A& rTmp = *reinterpret_cast<Matrix44A*>((reinterpret_cast<size_t>(Tmp) + 15) & ~15);
|
||||
rTmp = m_MatScreenViewProjTransposed;
|
||||
RASTERIZER.ReprojectHWDepthBuffer(rTmp, m_NearPlane, m_FarPlane, m_NearestMax, GetCVars()->e_CoverageBufferBias, nStartLine, nNumLines);
|
||||
}
|
||||
|
||||
uint32 nRemainingJobs = CryInterlockedDecrement((volatile int*)&m_nRunningReprojJobs);
|
||||
if (nRemainingJobs == 0)
|
||||
{
|
||||
enum
|
||||
{
|
||||
nLinesPerJob = 8
|
||||
};
|
||||
for (int i = 0; i < tdCullRasterizer::RESOLUTION_Y; i += nLinesPerJob)
|
||||
{
|
||||
m_OcclusionJobExecutor.StartJob([this, i]()
|
||||
{
|
||||
this->PrepareOcclusion_ReprojectZBufferLineAfterMerge(i, nLinesPerJob);
|
||||
}); // job.SetPriorityLevel(JobManager::eHighPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCullThread::PrepareOcclusion_ReprojectZBufferLineAfterMerge(int nStartLine, int nNumLines)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
|
||||
|
||||
// merge the reprojected buffer bevore new jobs are started on it
|
||||
RASTERIZER.MergeReprojectHWDepthBuffer(nStartLine, nNumLines);
|
||||
|
||||
if (!GetCVars()->e_CameraFreeze)
|
||||
{
|
||||
uint Tmp[80];
|
||||
Matrix44A& rTmp = *reinterpret_cast<Matrix44A*>((reinterpret_cast<size_t>(Tmp) + 15) & ~15);
|
||||
rTmp = m_MatScreenViewProjTransposed;
|
||||
RASTERIZER.ReprojectHWDepthBufferAfterMerge(rTmp, m_NearPlane, m_FarPlane, m_NearestMax, GetCVars()->e_CoverageBufferBias, nStartLine, nNumLines);
|
||||
}
|
||||
|
||||
uint32 nRemainingJobs = CryInterlockedDecrement((volatile int*)&m_nRunningReprojJobsAfterMerge);
|
||||
if (nRemainingJobs == 0)
|
||||
{
|
||||
m_OcclusionJobExecutor.StartJob([this]()
|
||||
{
|
||||
this->PrepareOcclusion_RasterizeZBuffer();
|
||||
}); //job.SetPriorityLevel(JobManager::eHighPriority);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCullThread::PrepareOcclusion_RasterizeZBuffer()
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
|
||||
|
||||
m_Enabled = true;
|
||||
if (!GetCVars()->e_CameraFreeze)
|
||||
{
|
||||
int bHWZBuffer = GetCVars()->e_CoverageBufferReproj;
|
||||
int PolyLimit = GetCVars()->e_CoverageBufferRastPolyLimit;
|
||||
|
||||
if (bHWZBuffer > 3 && m_OCMBuffer.empty())
|
||||
{
|
||||
bHWZBuffer = 2;
|
||||
}
|
||||
|
||||
bool rast_z_buff = (bHWZBuffer & 4) ? true : false;
|
||||
if (rast_z_buff)
|
||||
{
|
||||
m_Enabled = true;
|
||||
RasterizeZBuffer((uint32)PolyLimit);
|
||||
}
|
||||
}
|
||||
|
||||
bool bNeedJobStart = false;
|
||||
{
|
||||
AUTO_LOCK(m_FollowUpLock);
|
||||
if (m_nPrepareState == CHECK_REQUESTED)
|
||||
{
|
||||
m_nPrepareState = CHECK_STARTED;
|
||||
bNeedJobStart = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nPrepareState = PREPARE_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
m_PrepareBufferSync.PopCompletionFence();
|
||||
if (bNeedJobStart)
|
||||
{
|
||||
m_OcclusionJobExecutor.StartJob([this]()
|
||||
{
|
||||
this->CheckOcclusion(*reinterpret_cast<SRenderingPassInfo*>(m_passInfoForCheckOcclusion));
|
||||
}); // legacy: job.SetPriorityLevel(JobManager::eHighPriority)
|
||||
}
|
||||
}
|
||||
|
||||
void CCullThread::CheckOcclusion(SRenderingPassInfo passInfo)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
|
||||
|
||||
uint8 AlignBuffer[2 * sizeof(Matrix44A) + 16];
|
||||
size_t pBuffer = (reinterpret_cast<size_t>(AlignBuffer) + 15) & ~15;
|
||||
Matrix44A& RESTRICT_REFERENCE rMatFinalT = reinterpret_cast<Matrix44A*>(pBuffer)[1];
|
||||
|
||||
|
||||
Vec3 localPostion;
|
||||
memcpy(&localPostion, &m_Position, sizeof(Vec3));
|
||||
|
||||
const AABB PosAABB = AABB(m_Position, 0.5f);
|
||||
const float Bias = GetCVars()->e_CoverageBufferAABBExpand;
|
||||
rMatFinalT = m_MatScreenViewProj.GetTransposed();
|
||||
|
||||
// Debugging stats in green to screen here with how many octree nodes pass/fail and how many terrain nodes pass/fail
|
||||
unsigned int octreeNodesCulled = 0;
|
||||
unsigned int octreeNodesVisible = 0;
|
||||
while (1)
|
||||
{
|
||||
SCheckOcclusionJobData jobData;
|
||||
GetObjManager()->PopFromCullQueue(&jobData);
|
||||
|
||||
// stop processing when beeing told so
|
||||
if (jobData.type == SCheckOcclusionJobData::QUIT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (jobData.type == SCheckOcclusionJobData::OCTREE_NODE)
|
||||
{
|
||||
AABB rAABB;
|
||||
COctreeNode* pOctTreeNode = (COctreeNode*)jobData.octTreeData.pOctTreeNode;
|
||||
|
||||
memcpy(&rAABB, &pOctTreeNode->GetObjectsBBox(), sizeof(AABB));
|
||||
float fDistance = sqrtf(Distance::Point_AABBSq(passInfo.GetCamera().GetPosition(), rAABB));
|
||||
|
||||
// Test OctTree BoundingBox
|
||||
if (TestAABB(rAABB, fDistance))
|
||||
{
|
||||
pOctTreeNode->COctreeNode::RenderContent(jobData.octTreeData.nRenderMask, passInfo, jobData.rendItemSorter, jobData.pCam);
|
||||
octreeNodesVisible++;
|
||||
}
|
||||
else
|
||||
{
|
||||
octreeNodesCulled++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__debugbreak(); // unknown culler job type
|
||||
}
|
||||
}
|
||||
|
||||
if (GetCVars()->e_CoverageBufferDebug)
|
||||
{
|
||||
float fGreen[4] = {0, 1, 0, 1};
|
||||
gEnv->pRenderer->Draw2dLabel(16.0f, 32.0f, 1.6f, fGreen, false, AZStd::string::format("Octree Nodes Culled %i, Octree Nodes Visible %i",octreeNodesCulled, octreeNodesVisible).c_str());
|
||||
}
|
||||
|
||||
GetObjManager()->RemoveCullJobProducer();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
bool CCullThread::TestAABB(const AABB& rAABB, float fEntDistance, float fVerticalExpand)
|
||||
{
|
||||
IF (GetCVars()->e_CheckOcclusion == 0, 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const AABB PosAABB = AABB(m_Position, 0.5f);
|
||||
const float Bias = GetCVars()->e_CoverageBufferAABBExpand;
|
||||
DEFINE_ALIGNED_DATA(Matrix44A, rMatFinalT(m_MatScreenViewProj.GetTransposed()), 16);
|
||||
AABB bbox(rAABB);
|
||||
|
||||
if (Bias < 0.f)
|
||||
{
|
||||
bbox.Expand((bbox.max - bbox.min) * -Bias - Vec3(Bias, Bias, Bias));
|
||||
}
|
||||
else
|
||||
{
|
||||
bbox.Expand(Vec3(Bias * fEntDistance));
|
||||
}
|
||||
|
||||
float fVerticalExpandScaled = fVerticalExpand * fEntDistance;
|
||||
bbox.min.z -= fVerticalExpandScaled;
|
||||
bbox.max.z += fVerticalExpandScaled;
|
||||
|
||||
if (!m_Enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (bbox.IsIntersectBox(PosAABB))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (RASTERIZER.TestAABB(reinterpret_cast<const NVMath::vec4*>(&rMatFinalT), bbox.min, bbox.max, m_Position))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCullThread::TestQuad(const Vec3& vCenter, const Vec3& vAxisX, const Vec3& vAxisY)
|
||||
{
|
||||
IF (GetCVars()->e_CheckOcclusion == 0, 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_Enabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DEFINE_ALIGNED_DATA(Matrix44A, rMatFinalT(m_MatScreenViewProj.GetTransposed()), 16);
|
||||
if (RASTERIZER.TestQuad(reinterpret_cast<const NVMath::vec4*>(&rMatFinalT), vCenter, vAxisX, vAxisY))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace NAsyncCull
|
||||
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CCULLTHREAD_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CCULLTHREAD_H
|
||||
#pragma once
|
||||
|
||||
#include "CryThread.h"
|
||||
#include <AzCore/Jobs/LegacyJobExecutor.h>
|
||||
|
||||
namespace NAsyncCull
|
||||
{
|
||||
class CCullThread
|
||||
: public Cry3DEngineBase
|
||||
{
|
||||
bool m_Enabled;
|
||||
bool m_Active; // used to verify that the cull job is running and no new jobs are added after the job has finished
|
||||
|
||||
public:
|
||||
enum PrepareStateT
|
||||
{
|
||||
IDLE, PREPARE_STARTED, PREPARE_DONE, CHECK_REQUESTED, CHECK_STARTED
|
||||
};
|
||||
|
||||
PrepareStateT m_nPrepareState;
|
||||
CryCriticalSection m_FollowUpLock;
|
||||
char m_passInfoForCheckOcclusion[sizeof(SRenderingPassInfo)];
|
||||
uint32 m_nRunningReprojJobs;
|
||||
uint32 m_nRunningReprojJobsAfterMerge;
|
||||
int m_bCheckOcclusionRequested;
|
||||
|
||||
private:
|
||||
AZ::LegacyJobExecutor m_OcclusionJobExecutor; // All jobs pushed against this instance to gurantee a wait on all jobs before exiting ~CCullThread
|
||||
AZ::LegacyJobExecutor m_PrepareBufferSync;
|
||||
Matrix44A m_MatScreenViewProj _ALIGN(16);
|
||||
Matrix44A m_MatScreenViewProjTransposed;
|
||||
Vec3 m_ViewDir;
|
||||
Vec3 m_Position;
|
||||
float m_NearPlane;
|
||||
float m_FarPlane;
|
||||
float m_NearestMax;
|
||||
|
||||
PodArray<uint8> m_OCMBuffer;
|
||||
uint8* m_pOCMBufferAligned;
|
||||
uint32 m_OCMMeshCount;
|
||||
uint32 m_OCMInstCount;
|
||||
uint32 m_OCMOffsetInstances;
|
||||
|
||||
template<class T>
|
||||
T Swap(T& rData)
|
||||
{
|
||||
// #if IS_LOCAL_MACHINE_BIG_ENDIAN
|
||||
PREFAST_SUPPRESS_WARNING(6326)
|
||||
switch (sizeof(T))
|
||||
{
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
SwapEndianBase(reinterpret_cast<uint16*>(&rData));
|
||||
break;
|
||||
case 4:
|
||||
SwapEndianBase(reinterpret_cast<uint32*>(&rData));
|
||||
break;
|
||||
case 8:
|
||||
SwapEndianBase(reinterpret_cast<uint64*>(&rData));
|
||||
break;
|
||||
default:
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
__builtin_unreachable();
|
||||
#else
|
||||
__assume(0);
|
||||
#endif
|
||||
}
|
||||
//#endif
|
||||
return rData;
|
||||
}
|
||||
|
||||
void RasterizeZBuffer(uint32 PolyLimit);
|
||||
void OutputMeshList();
|
||||
|
||||
public:
|
||||
|
||||
void CheckOcclusion(SRenderingPassInfo passInfo);
|
||||
void PrepareOcclusion();
|
||||
|
||||
void PrepareOcclusion_RasterizeZBuffer();
|
||||
void PrepareOcclusion_ReprojectZBuffer();
|
||||
void PrepareOcclusion_ReprojectZBufferLine(int nStartLine, int nNumLines);
|
||||
void PrepareOcclusion_ReprojectZBufferLineAfterMerge(int nStartLine, int nNumLines);
|
||||
void Init();
|
||||
|
||||
bool LoadLevel(const char* pFolderName);
|
||||
void UnloadLevel();
|
||||
|
||||
bool TestAABB(const AABB& rAABB, float fEntDistance, float fVerticalExpand = 0.0f);
|
||||
bool TestQuad(const Vec3& vCenter, const Vec3& vAxisX, const Vec3& vAxisY);
|
||||
|
||||
CCullThread();
|
||||
~CCullThread() = default;
|
||||
|
||||
|
||||
#ifndef _RELEASE
|
||||
void CoverageBufferDebugDraw();
|
||||
#endif
|
||||
|
||||
void PrepareCullbufferAsync(const CCamera& rCamera);
|
||||
void CullStart(const SRenderingPassInfo& passInfo);
|
||||
void CullEnd(bool waitForOcclusionJobCompletion = false);
|
||||
|
||||
bool IsActive() const { return m_Active; }
|
||||
void SetActive(bool bActive) { m_Active = bActive; }
|
||||
|
||||
Vec3 GetViewDir() { return m_ViewDir; };
|
||||
} _ALIGN(128);
|
||||
}
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CCULLTHREAD_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CGFLOADER_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CGFLOADER_H
|
||||
#pragma once
|
||||
|
||||
#include "../MeshCompiler/MeshCompiler.h"
|
||||
#include "ChunkFile.h"
|
||||
#include "CGFContent.h"
|
||||
|
||||
#if defined(RESOURCE_COMPILER) || defined(ENABLE_NON_COMPILED_CGF)
|
||||
#include "../../../Tools/CryCommonTools/Export/MeshUtils.h"
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class ILoaderCGFListener
|
||||
{
|
||||
public:
|
||||
virtual ~ILoaderCGFListener(){}
|
||||
virtual void Warning(const char* format) = 0;
|
||||
virtual void Error(const char* format) = 0;
|
||||
virtual bool IsValidationEnabled() { return true; }
|
||||
};
|
||||
|
||||
class CLoaderCGF
|
||||
{
|
||||
public:
|
||||
typedef void* (* AllocFncPtr)(size_t);
|
||||
typedef void (* DestructFncPtr)(void*);
|
||||
|
||||
CLoaderCGF(AllocFncPtr pAlloc = operator new, DestructFncPtr pDestruct = operator delete, bool bAllowStreamSharing = true);
|
||||
~CLoaderCGF();
|
||||
|
||||
CContentCGF* LoadCGF(const char* filename, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags = 0);
|
||||
bool LoadCGF(CContentCGF* pContentCGF, const char* filename, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags = 0);
|
||||
bool LoadCGFFromMem(CContentCGF* pContentCGF, const void* pData, size_t nDataLen, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags = 0);
|
||||
bool LoadCGFWork(CContentCGF* pContentCGF, const char* filename, IChunkFile& chunkFile, ILoaderCGFListener* pListener, unsigned long nLoadingFlags);
|
||||
|
||||
const char* GetLastError() { return m_LastError; }
|
||||
CContentCGF* GetCContentCGF() { return m_pCompiledCGF; }
|
||||
|
||||
void SetMaxWeightsPerVertex(int maxWeightsPerVertex) { m_maxWeightsPerVertex = maxWeightsPerVertex; }
|
||||
|
||||
private:
|
||||
bool LoadChunks(bool bJustGeometry);
|
||||
bool LoadExportFlagsChunk(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool LoadNodeChunk(IChunkFile::ChunkDesc* pChunkDesc, bool bJustGeometry);
|
||||
|
||||
bool LoadHelperChunk(CNodeCGF* pNode, IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool LoadGeomChunk(CNodeCGF* pNode, IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool LoadCompiledMeshChunk(CNodeCGF* pNode, IChunkFile::ChunkDesc* pChunkDesc);
|
||||
template<class MESH_CHUNK_DESC>
|
||||
bool LoadCompiledMeshChunk(CNodeCGF* pNode, IChunkFile::ChunkDesc* pChunkDesc, MESH_CHUNK_DESC chunk);
|
||||
bool LoadMeshSubsetsChunk(CMesh& mesh, IChunkFile::ChunkDesc* pChunkDesc, std::vector<std::vector<uint16> >& globalBonesPerSubset);
|
||||
bool LoadStreamDataChunk(int nChunkId, void*& pStreamData, int& nStreamType, int& nStreamIndex, int& nCount, int& nElemSize, bool& bSwapEndianness);
|
||||
template<class T, class MESH_CHUNK_DESC>
|
||||
bool LoadStreamChunk(CMesh& mesh, const MESH_CHUNK_DESC& chunk, ECgfStreamType Type, int streamIndex, CMesh::EStream MStream);
|
||||
//! Used to load data into one of two potential destination streams in CMesh determined by the element size of the data stored in the .cgf. e.g. load into either CMesh::POSITIONS or CMesh::POSITIONS16
|
||||
template<class TA, class TB, class MESH_CHUNK_DESC>
|
||||
bool LoadStreamChunk(CMesh& mesh, const MESH_CHUNK_DESC& chunk, ECgfStreamType Type, int streamIndex, CMesh::EStream MStreamA, CMesh::EStream MStreamB);
|
||||
template<class MESH_CHUNK_DESC>
|
||||
bool LoadBoneMappingStreamChunk(CMesh& mesh, const MESH_CHUNK_DESC& chunk, const std::vector<std::vector<uint16> >& globalBonesPerSubset);
|
||||
template<class MESH_CHUNK_DESC>
|
||||
bool LoadIndexStreamChunk(CMesh& mesh, const MESH_CHUNK_DESC& chunk);
|
||||
|
||||
bool LoadPhysicsDataChunk(CNodeCGF* pNode, int nPhysGeomType, int nChunkId);
|
||||
|
||||
bool LoadFoliageInfoChunk(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
|
||||
CMaterialCGF* LoadMaterialFromChunk(int nChunkId);
|
||||
|
||||
CMaterialCGF* LoadMaterialNameChunk(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
|
||||
void ProcessNodes();
|
||||
void SetupMeshSubsets(CMesh& mesh, CMaterialCGF* pMaterialCGF);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// loading of skinned meshes
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool ProcessSkinning();
|
||||
CContentCGF* MakeCompiledSkinCGF(CContentCGF* pCGF, std::vector<int>* pVertexRemapping, std::vector<int>* pIndexRemapping);
|
||||
|
||||
//old chunks
|
||||
bool ReadBoneNameList(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadMorphTargets(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadBoneInitialPos(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadBoneHierarchy(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
uint32 RecursiveBoneLoader(int nBoneParentIndex, int nBoneIndex);
|
||||
bool ReadBoneMesh(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
|
||||
//new chunks
|
||||
bool ReadCompiledBones(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadCompiledPhysicalBones(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadCompiledPhysicalProxies(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadCompiledMorphTargets(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
|
||||
bool ReadCompiledIntFaces(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadCompiledIntSkinVertice(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadCompiledExt2IntMap(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
bool ReadCompiledBonesBoxes(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
|
||||
bool ReadCompiledBreakablePhysics(IChunkFile::ChunkDesc* pChunkDesc);
|
||||
|
||||
void Warning(const char* szFormat, ...) PRINTF_PARAMS(2, 3);
|
||||
|
||||
private:
|
||||
uint32 m_IsCHR;
|
||||
uint32 m_CompiledBones;
|
||||
uint32 m_CompiledBonesBoxes;
|
||||
uint32 m_CompiledMesh;
|
||||
|
||||
uint32 m_numBonenameList;
|
||||
uint32 m_numBoneInitialPos;
|
||||
uint32 m_numMorphTargets;
|
||||
uint32 m_numBoneHierarchy;
|
||||
|
||||
std::vector<uint32> m_arrIndexToId; // the mapping BoneIndex -> BoneID
|
||||
std::vector<uint32> m_arrIdToIndex; // the mapping BoneID -> BineIndex
|
||||
std::vector<string> m_arrBoneNameTable; // names of bones
|
||||
std::vector<Matrix34> m_arrInitPose34;
|
||||
#if defined(RESOURCE_COMPILER) || defined(ENABLE_NON_COMPILED_CGF)
|
||||
std::vector<MeshUtils::VertexLinks> m_arrLinksTmp;
|
||||
std::vector<int> m_vertexOldToNew; // used to re-map uncompiled Morph Target vertices right after reading them
|
||||
#endif
|
||||
|
||||
CContentCGF* m_pCompiledCGF;
|
||||
const void* m_pBoneAnimRawData, * m_pBoneAnimRawDataEnd;
|
||||
uint32 m_numBones;
|
||||
int m_nNextBone;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
string m_LastError;
|
||||
|
||||
char m_filename[260];
|
||||
|
||||
IChunkFile* m_pChunkFile;
|
||||
CContentCGF* m_pCGF;
|
||||
|
||||
// To find really used materials
|
||||
uint16 MatIdToSubset[MAX_SUB_MATERIALS];
|
||||
int nLastChunkId;
|
||||
|
||||
ILoaderCGFListener* m_pListener;
|
||||
|
||||
bool m_bUseReadOnlyMesh;
|
||||
bool m_bAllowStreamSharing;
|
||||
|
||||
int m_maxWeightsPerVertex;
|
||||
|
||||
AllocFncPtr m_pAllocFnc;
|
||||
DestructFncPtr m_pDestructFnc;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CGFLOADER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CGFSAVER_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CGFSAVER_H
|
||||
#pragma once
|
||||
|
||||
#if defined(RESOURCE_COMPILER) || defined(INCLUDE_SAVECGF)
|
||||
|
||||
#include "CGFContent.h"
|
||||
|
||||
class CChunkFile;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CSaverCGF
|
||||
{
|
||||
public:
|
||||
CSaverCGF(CChunkFile& chunkFile);
|
||||
|
||||
void SaveContent(CContentCGF* pCGF, bool bSwapEndian, bool bStorePositionsAsF16, bool bUseQtangents, bool bStoreIndicesAsU16);
|
||||
|
||||
void SetContent(CContentCGF* pCGF);
|
||||
|
||||
const CContentCGF* GetContent() const;
|
||||
|
||||
// Enable/Disable saving of the node mesh.
|
||||
void SetMeshDataSaving(bool bEnable);
|
||||
|
||||
// Enable/Disable saving of non-mesh related data.
|
||||
void SetNonMeshDataSaving(bool bEnable);
|
||||
|
||||
// Enable/disable saving of physics meshes.
|
||||
void SetSavePhysicsMeshes(bool bEnable);
|
||||
|
||||
// Enable compaction of vertex streams (for optimised streaming)
|
||||
void SetVertexStreamCompacting(bool bEnable);
|
||||
|
||||
// Enable computation of subset texel density
|
||||
void SetSubsetTexelDensityComputing(bool bEnable);
|
||||
|
||||
void SaveNodes(bool bSwapEndian, bool bStorePositionsAsF16, bool bUseQtangents, bool bStoreIndicesAsU16);
|
||||
int SaveNode(CNodeCGF* pNode, bool bSwapEndian, bool bStorePositionsAsF16, bool bUseQtangents, bool bStoreIndicesAsU16);
|
||||
|
||||
void SaveMaterials(bool bSwapEndian);
|
||||
int SaveMaterial(CMaterialCGF* pMtl, bool bNeedSwap);
|
||||
int SaveExportFlags(bool bSwapEndian);
|
||||
|
||||
// Compiled chunks for characters
|
||||
int SaveCompiledBones(bool bSwapEndian, void* pData, int nSize, int version);
|
||||
int SaveCompiledPhysicalBones(bool bSwapEndian, void* pData, int nSize, int version);
|
||||
int SaveCompiledPhysicalProxis(bool bSwapEndian, void* pData, int nSize, uint32 numIntMorphTargets, int version);
|
||||
int SaveCompiledMorphTargets(bool bSwapEndian, void* pData, int nSize, uint32 numIntMorphTargets, int version);
|
||||
int SaveCompiledIntFaces(bool bSwapEndian, void* pData, int nSize, int version);
|
||||
int SaveCompiledIntSkinVertices(bool bSwapEndian, void* pData, int nSize, int version);
|
||||
int SaveCompiledExt2IntMap(bool bSwapEndian, void* pData, int nSize, int version);
|
||||
int SaveCompiledBoneBox(bool bSwapEndian, void* pData, int nSize, int version);
|
||||
|
||||
// Chunks for characters (for Collada->cgf export)
|
||||
int SaveBones(bool bSwapEndian, void* pData, int numBones, int nSize);
|
||||
int SaveBoneNames(bool bSwapEndian, char* boneList, int numBones, int listSize);
|
||||
int SaveBoneInitialMatrices(bool bSwapEndian, SBoneInitPosMatrix* matrices, int numBones, int nSize);
|
||||
int SaveBoneMesh(bool bSwapEndian, PhysicalProxy& proxy);
|
||||
#if defined(RESOURCE_COMPILER)
|
||||
void SaveUncompiledNodes();
|
||||
int SaveUncompiledNode(CNodeCGF* pNode);
|
||||
void SaveUncompiledMorphTargets();
|
||||
int SaveUncompiledNodeMesh(CNodeCGF* pNode);
|
||||
int SaveUncompiledHelperChunk(CNodeCGF* pNode);
|
||||
#endif
|
||||
|
||||
int SaveBreakablePhysics(bool bNeedEndianSwap);
|
||||
|
||||
int SaveController831(bool bSwapEndian, const CONTROLLER_CHUNK_DESC_0831& ctrlChunk, void* pData, int nSize);
|
||||
int SaveControllerDB905(bool bSwapEndian, const CONTROLLER_CHUNK_DESC_0905& ctrlChunk, void* pData, int nSize);
|
||||
|
||||
int SaveFoliage();
|
||||
|
||||
private:
|
||||
// Return mesh chunk id
|
||||
int SaveNodeMesh(CNodeCGF* pNode, bool bSwapEndian, bool bStorePositionsAsF16, bool bUseQTangents, bool bStoreIndicesAsU16);
|
||||
int SaveHelperChunk(CNodeCGF* pNode, bool bSwapEndian);
|
||||
int SaveMeshSubsetsChunk(CMesh& mesh, bool bSwapEndian);
|
||||
int SaveStreamDataChunk(const void* pStreamData, int nStreamType, int nStreamIndex, int nCount, int nElemSize, bool bSwapEndian);
|
||||
int SavePhysicalDataChunk(const void* pData, int nSize, bool bSwapEndian);
|
||||
|
||||
private:
|
||||
CChunkFile* m_pChunkFile;
|
||||
CContentCGF* m_pCGF;
|
||||
std::set<CNodeCGF*> m_savedNodes;
|
||||
std::set<CMaterialCGF*> m_savedMaterials;
|
||||
std::map<CMesh*, int> m_mapMeshToChunk;
|
||||
bool m_bDoNotSaveMeshData;
|
||||
bool m_bDoNotSaveNonMeshData;
|
||||
bool m_bSavePhysicsMeshes;
|
||||
bool m_bCompactVertexStreams;
|
||||
bool m_bComputeSubsetTexelDensity;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CGFSAVER_H
|
||||
@@ -1,39 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
ly_add_target(
|
||||
NAME Cry3DEngine.CGF.Static STATIC
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
cry3dengine_cgf_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME Cry3DEngine.CGF.RC.Static STATIC
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
cry3dengine_cgf_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
.
|
||||
COMPILE_DEFINITIONS
|
||||
PRIVATE
|
||||
RESOURCE_COMPILER
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::CryCommon
|
||||
)
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CHUNKDATA_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CHUNKDATA_H
|
||||
#pragma once
|
||||
|
||||
struct CChunkData
|
||||
{
|
||||
char* data;
|
||||
int size;
|
||||
|
||||
CChunkData() { data = 0; size = 0; }
|
||||
~CChunkData() { free(data); }
|
||||
|
||||
template <class T>
|
||||
void Add(const T& object)
|
||||
{
|
||||
AddData(&object, sizeof(object));
|
||||
}
|
||||
void AddData(const void* pSrcData, int nSrcDataSize)
|
||||
{
|
||||
data = (char*)realloc(data, size + nSrcDataSize);
|
||||
memcpy(data + size, pSrcData, nSrcDataSize);
|
||||
size += nSrcDataSize;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CHUNKDATA_H
|
||||
@@ -1,428 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include <platform.h>
|
||||
#include "ChunkFile.h"
|
||||
#include "ChunkFileReaders.h"
|
||||
#include "ChunkFileWriters.h"
|
||||
|
||||
#if !defined(FUNCTION_PROFILER_3DENGINE)
|
||||
#define FUNCTION_PROFILER_3DENGINE
|
||||
#endif
|
||||
|
||||
#if !defined(LOADING_TIME_PROFILE_SECTION)
|
||||
#define LOADING_TIME_PROFILE_SECTION
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
inline bool ChunkLessOffset(const IChunkFile::ChunkDesc* const p0, const IChunkFile::ChunkDesc* const p1)
|
||||
{
|
||||
return IChunkFile::ChunkDesc::LessOffset(*p0, *p1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CChunkFile::CChunkFile()
|
||||
: m_pInternalData(NULL)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
CChunkFile::~CChunkFile()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void CChunkFile::Clear()
|
||||
{
|
||||
ReleaseMemoryBuffer();
|
||||
ReleaseChunks();
|
||||
|
||||
m_nLastChunkId = 0;
|
||||
m_pInternalData = NULL;
|
||||
m_bLoaded = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CChunkFile::ChunkDesc* CChunkFile::GetChunk(int nChunkIdx)
|
||||
{
|
||||
assert(nChunkIdx >= 0 && nChunkIdx < (int)m_chunks.size());
|
||||
return m_chunks[nChunkIdx];
|
||||
}
|
||||
|
||||
const CChunkFile::ChunkDesc* CChunkFile::GetChunk(int nChunkIdx) const
|
||||
{
|
||||
assert(nChunkIdx >= 0 && nChunkIdx < (int)m_chunks.size());
|
||||
return m_chunks[nChunkIdx];
|
||||
}
|
||||
|
||||
// number of chunks
|
||||
int CChunkFile::NumChunks() const
|
||||
{
|
||||
return (int)m_chunks.size();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int CChunkFile::AddChunk(ChunkTypes chunkType, int chunkVersion, EEndianness eEndianness, const void* chunkData, int chunkSize)
|
||||
{
|
||||
ChunkDesc* const pChunk = new ChunkDesc;
|
||||
|
||||
pChunk->bSwapEndian = (eEndianness == eEndianness_NonNative);
|
||||
|
||||
// This block of code is used for debugging only
|
||||
if (false)
|
||||
{
|
||||
for (size_t i = 0, n = m_chunks.size(); i < n; ++i)
|
||||
{
|
||||
if (m_chunks[i]->bSwapEndian != pChunk->bSwapEndian)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pChunk->chunkType = chunkType;
|
||||
pChunk->chunkVersion = chunkVersion;
|
||||
|
||||
const int chunkId = ++m_nLastChunkId;
|
||||
pChunk->chunkId = chunkId;
|
||||
|
||||
pChunk->data = new char[chunkSize];
|
||||
pChunk->size = chunkSize;
|
||||
memcpy(pChunk->data, chunkData, chunkSize);
|
||||
|
||||
m_chunks.push_back(pChunk);
|
||||
m_chunkIdMap[chunkId] = pChunk;
|
||||
|
||||
return chunkId;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CChunkFile::DeleteChunkById(int nChunkId)
|
||||
{
|
||||
for (size_t i = 0, n = m_chunks.size(); i < n; ++i)
|
||||
{
|
||||
if (m_chunks[i]->chunkId == nChunkId)
|
||||
{
|
||||
m_chunkIdMap.erase(nChunkId);
|
||||
if (m_chunks[i]->data)
|
||||
{
|
||||
delete [] (char*)m_chunks[i]->data;
|
||||
m_chunks[i]->data = 0;
|
||||
}
|
||||
delete m_chunks[i];
|
||||
m_chunks.erase(m_chunks.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CChunkFile::DeleteChunksByType(ChunkTypes nChunkType)
|
||||
{
|
||||
size_t j = 0;
|
||||
for (size_t i = 0, n = m_chunks.size(); i < n; ++i)
|
||||
{
|
||||
if (m_chunks[i]->chunkType == nChunkType)
|
||||
{
|
||||
m_chunkIdMap.erase(m_chunks[i]->chunkId);
|
||||
if (m_chunks[i]->data)
|
||||
{
|
||||
delete [] (char*)m_chunks[i]->data;
|
||||
m_chunks[i]->data = 0;
|
||||
}
|
||||
delete m_chunks[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_chunks[j] = m_chunks[i];
|
||||
++j;
|
||||
}
|
||||
}
|
||||
m_chunks.resize(j);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CChunkFile::ReleaseChunks()
|
||||
{
|
||||
m_bLoaded = false;
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
if (m_chunks[i]->data)
|
||||
{
|
||||
delete [] (char*) m_chunks[i]->data;
|
||||
}
|
||||
delete m_chunks[i];
|
||||
}
|
||||
m_chunks.clear();
|
||||
m_chunkIdMap.clear();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CChunkFile::ChunkDesc* CChunkFile::FindChunkByType(ChunkTypes nChunkType)
|
||||
{
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
if (m_chunks[i]->chunkType == nChunkType)
|
||||
{
|
||||
return m_chunks[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CChunkFile::ChunkDesc* CChunkFile::FindChunkById(int nChunkId)
|
||||
{
|
||||
ChunkIdMap::iterator it = m_chunkIdMap.find(nChunkId);
|
||||
if (it != m_chunkIdMap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CChunkFile::Write(const char* filename)
|
||||
{
|
||||
if (m_chunks.empty())
|
||||
{
|
||||
m_LastError.Format("Writing *empty* chunk files is not supported (file '%s')", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate requested endianness. Kept here for debug.
|
||||
if (false)
|
||||
{
|
||||
bool bHasSwapEndianTrue = false;
|
||||
bool bHasSwapEndianFalse = false;
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
const ChunkDesc& cd = *m_chunks[i];
|
||||
if (cd.bSwapEndian)
|
||||
{
|
||||
bHasSwapEndianTrue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bHasSwapEndianFalse = true;
|
||||
}
|
||||
}
|
||||
if (bHasSwapEndianTrue && bHasSwapEndianFalse)
|
||||
{
|
||||
//Warning("Writing chunk files with *mixed* endianness is not supported (file '%s')", filename);
|
||||
}
|
||||
}
|
||||
|
||||
ChunkFile::OsFileWriter writer;
|
||||
|
||||
if (!writer.Create(filename))
|
||||
{
|
||||
m_LastError.Format("Failed to open '%s' for writing", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
ChunkFile::MemorylessChunkFileWriter wr(ChunkFile::MemorylessChunkFileWriter::eChunkFileFormat_0x746, &writer);
|
||||
wr.SetAlignment(4);
|
||||
|
||||
while (wr.StartPass())
|
||||
{
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
const ChunkDesc& cd = *m_chunks[i];
|
||||
wr.StartChunk((cd.bSwapEndian ? eEndianness_NonNative : eEndianness_Native), cd.chunkType, cd.chunkVersion, cd.chunkId);
|
||||
wr.AddChunkData(cd.data, cd.size);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wr.HasWrittenSuccessfully())
|
||||
{
|
||||
m_LastError.Format("Failed to write '%s'", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CChunkFile::WriteToMemoryBuffer(void** pData, int* nSize)
|
||||
{
|
||||
ReleaseMemoryBuffer();
|
||||
*pData = 0;
|
||||
|
||||
if (m_chunks.empty())
|
||||
{
|
||||
m_LastError.Format("Writing *empty* chunk files is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do writing in *two* stages:
|
||||
// 1) computing required size (see sizeWriter below)
|
||||
// 2) allocating and writing data (see memoryWriter below)
|
||||
|
||||
ChunkFile::SizeWriter sizeWriter;
|
||||
ChunkFile::MemoryWriter memoryWriter;
|
||||
|
||||
for (int stage = 0; stage < 2; ++stage)
|
||||
{
|
||||
ChunkFile::IWriter* pWriter;
|
||||
if (stage == 0)
|
||||
{
|
||||
sizeWriter.Start();
|
||||
pWriter = &sizeWriter;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_pInternalData == 0);
|
||||
*nSize = sizeWriter.GetPos();
|
||||
assert(*nSize > 0);
|
||||
|
||||
m_pInternalData = (char*)malloc(*nSize);
|
||||
if (m_pInternalData == 0)
|
||||
{
|
||||
m_LastError.Format("Failed to allocate %u bytes", uint(*nSize));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!memoryWriter.Start(m_pInternalData, *nSize))
|
||||
{
|
||||
assert(0);
|
||||
m_LastError.Format("Internal error");
|
||||
ReleaseMemoryBuffer();
|
||||
return false;
|
||||
}
|
||||
pWriter = &memoryWriter;
|
||||
}
|
||||
|
||||
ChunkFile::MemorylessChunkFileWriter wr(ChunkFile::MemorylessChunkFileWriter::eChunkFileFormat_0x746, pWriter);
|
||||
wr.SetAlignment(4);
|
||||
|
||||
while (wr.StartPass())
|
||||
{
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
const ChunkDesc& cd = *m_chunks[i];
|
||||
wr.StartChunk((cd.bSwapEndian ? eEndianness_NonNative : eEndianness_Native), cd.chunkType, cd.chunkVersion, cd.chunkId);
|
||||
wr.AddChunkData(cd.data, cd.size);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wr.HasWrittenSuccessfully())
|
||||
{
|
||||
m_LastError.Format("Failed to write");
|
||||
ReleaseMemoryBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(stage != 2 || memoryWriter.GetPos() == *nSize);
|
||||
}
|
||||
|
||||
*pData = m_pInternalData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CChunkFile::ReleaseMemoryBuffer()
|
||||
{
|
||||
if (m_pInternalData)
|
||||
{
|
||||
free(m_pInternalData);
|
||||
m_pInternalData = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CChunkFile::Read(const char* filename)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
ReleaseChunks();
|
||||
|
||||
// Loading chunks
|
||||
{
|
||||
ChunkFile::CryFileReader f;
|
||||
|
||||
if (!f.Open(filename))
|
||||
{
|
||||
m_LastError.Format("File %s failed to open for reading", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
const char* err = 0;
|
||||
|
||||
err = ChunkFile::GetChunkTableEntries_0x746(&f, m_chunks);
|
||||
if (err)
|
||||
{
|
||||
err = ChunkFile::GetChunkTableEntries_0x744_0x745(&f, m_chunks);
|
||||
if (!err)
|
||||
{
|
||||
err = ChunkFile::StripChunkHeaders_0x744_0x745(&f, m_chunks);
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
m_LastError = err;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
ChunkDesc& cd = *m_chunks[i];
|
||||
|
||||
assert(cd.data == 0);
|
||||
|
||||
cd.data = new char[cd.size];
|
||||
|
||||
if (!f.SetPos(cd.fileOffset) ||
|
||||
!f.Read(cd.data, cd.size))
|
||||
{
|
||||
m_LastError.Format(
|
||||
"Failed to read chunk data (offset:%u, size:%u) from file %s",
|
||||
cd.fileOffset, cd.size, filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_nLastChunkId = 0;
|
||||
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
// Add chunk to chunk map.
|
||||
m_chunkIdMap[m_chunks[i]->chunkId] = m_chunks[i];
|
||||
|
||||
// Update last chunk ID.
|
||||
if (m_chunks[i]->chunkId > m_nLastChunkId)
|
||||
{
|
||||
m_nLastChunkId = m_chunks[i]->chunkId;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_chunks.size() != m_chunkIdMap.size())
|
||||
{
|
||||
const int duplicateCount = (int)(m_chunks.size() - m_chunkIdMap.size());
|
||||
m_LastError.Format(
|
||||
"%d duplicate chunk ID%s found in file %s",
|
||||
duplicateCount, ((duplicateCount > 1) ? "s" : ""), filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bLoaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILE_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILE_H
|
||||
#pragma once
|
||||
|
||||
#include <CrySizer.h>
|
||||
#include <CryHeaders.h>
|
||||
#include <smartptr.h>
|
||||
#include <IChunkFile.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Chunk file reader.
|
||||
// Accesses a chunked file structure through file mapping object.
|
||||
// Opens a chunk file and checks for its validity.
|
||||
// If it's invalid, closes it as if there was no open operation.
|
||||
// Error handling is performed through the return value of Read():
|
||||
// it must be true for successfully open files
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CChunkFile
|
||||
: public IChunkFile
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CChunkFile();
|
||||
virtual ~CChunkFile();
|
||||
|
||||
// interface IChunkFile --------------------------------------------------
|
||||
|
||||
virtual void Release() { delete this; }
|
||||
|
||||
void Clear();
|
||||
|
||||
virtual bool IsReadOnly() const { return false; }
|
||||
virtual bool IsLoaded() const { return m_bLoaded; }
|
||||
|
||||
virtual bool Read(const char* filename);
|
||||
virtual bool ReadFromMemory([[maybe_unused]] const void* pData, [[maybe_unused]] int nDataSize) { return false; }
|
||||
|
||||
virtual bool Write(const char* filename);
|
||||
virtual bool WriteToMemoryBuffer(void** pData, int* nSize);
|
||||
virtual void ReleaseMemoryBuffer();
|
||||
|
||||
virtual int AddChunk(ChunkTypes chunkType, int chunkVersion, EEndianness eEndianness, const void* chunkData, int chunkSize);
|
||||
virtual void DeleteChunkById(int nChunkId);
|
||||
virtual void DeleteChunksByType(ChunkTypes nChunkType);
|
||||
|
||||
virtual ChunkDesc* FindChunkByType(ChunkTypes nChunkType);
|
||||
virtual ChunkDesc* FindChunkById(int nChunkId);
|
||||
|
||||
virtual int NumChunks() const;
|
||||
|
||||
virtual ChunkDesc* GetChunk(int nIndex);
|
||||
virtual const ChunkDesc* GetChunk(int nIndex) const;
|
||||
|
||||
virtual const char* GetLastError() const { return m_LastError; }
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(m_LastError);
|
||||
pSizer->AddObject(m_chunks);
|
||||
pSizer->AddObject(m_chunkIdMap);
|
||||
}
|
||||
|
||||
private:
|
||||
void ReleaseChunks();
|
||||
|
||||
private:
|
||||
// this variable contains the last error occurred in this class
|
||||
string m_LastError;
|
||||
|
||||
int m_nLastChunkId;
|
||||
std::vector<ChunkDesc*> m_chunks;
|
||||
typedef std::map<int, ChunkDesc*> ChunkIdMap;
|
||||
ChunkIdMap m_chunkIdMap;
|
||||
char* m_pInternalData;
|
||||
bool m_bLoaded;
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(CChunkFile);
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILE_H
|
||||
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILECOMPONENTS_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILECOMPONENTS_H
|
||||
#pragma once
|
||||
|
||||
#include "CryHeaders.h"
|
||||
|
||||
namespace ChunkFile
|
||||
{
|
||||
// All chunk files use *little-endian* format to store file header and chunk.
|
||||
// Chunk data are stored in either little-endian or big-endian format,
|
||||
// see kBigEndianVersionFlag.
|
||||
|
||||
struct FileHeader_0x744_0x745
|
||||
{
|
||||
char signature[7];
|
||||
char _pad_[1];
|
||||
uint32 fileType;
|
||||
uint32 version;
|
||||
uint32 chunkTableOffset;
|
||||
|
||||
enum EFileType
|
||||
{
|
||||
eFileType_Geom = 0xFFFF0000U,
|
||||
eFileType_Anim,
|
||||
};
|
||||
|
||||
static const char* GetExpectedSignature()
|
||||
{
|
||||
return "CryTek";
|
||||
}
|
||||
|
||||
bool HasValidSignature() const
|
||||
{
|
||||
return memcmp(GetExpectedSignature(), signature, sizeof(signature)) == 0;
|
||||
}
|
||||
|
||||
void Set(uint32 a_chunkTableOffset)
|
||||
{
|
||||
memcpy(signature, GetExpectedSignature(), sizeof(signature));
|
||||
_pad_[0] = 0;
|
||||
// We need to set eFileType_Geom or eFileType_Anim, but asking
|
||||
// the caller to provide us the type will complicate the code, so we
|
||||
// set eFileType_Geom only. It's ok because all our readers
|
||||
// don't differentiate between eFileType_Geom and eFileType_Anim.
|
||||
fileType = eFileType_Geom;
|
||||
version = 0x745;
|
||||
chunkTableOffset = a_chunkTableOffset;
|
||||
}
|
||||
|
||||
void SwapEndianness()
|
||||
{
|
||||
SwapEndianBase(&fileType, 1);
|
||||
SwapEndianBase(&version, 1);
|
||||
SwapEndianBase(&chunkTableOffset, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct FileHeader_0x746
|
||||
{
|
||||
char signature[4];
|
||||
uint32 version;
|
||||
uint32 chunkCount;
|
||||
uint32 chunkTableOffset;
|
||||
|
||||
static const char* GetExpectedSignature()
|
||||
{
|
||||
return "CrCh";
|
||||
}
|
||||
|
||||
static const char* GetExpectedSpeedTreeSignature()
|
||||
{
|
||||
return "STCh";
|
||||
}
|
||||
|
||||
bool HasValidSignature() const
|
||||
{
|
||||
return (memcmp(GetExpectedSignature(), signature, sizeof(signature)) == 0) ||
|
||||
(memcmp(GetExpectedSpeedTreeSignature(), signature, sizeof(signature)) == 0);
|
||||
}
|
||||
|
||||
void Set(int32 a_chunkCount, uint32 a_chunkTableOffset)
|
||||
{
|
||||
memcpy(signature, GetExpectedSignature(), sizeof(signature));
|
||||
version = 0x746;
|
||||
chunkCount = a_chunkCount;
|
||||
chunkTableOffset = a_chunkTableOffset;
|
||||
}
|
||||
|
||||
void SwapEndianness()
|
||||
{
|
||||
SwapEndianBase(&version, 1);
|
||||
SwapEndianBase(&chunkCount, 1);
|
||||
SwapEndianBase(&chunkTableOffset, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ChunkHeader_0x744_0x745
|
||||
{
|
||||
uint32 type;
|
||||
uint32 version;
|
||||
uint32 offsetInFile;
|
||||
uint32 id;
|
||||
|
||||
enum
|
||||
{
|
||||
kBigEndianVersionFlag = 0x80000000U
|
||||
};
|
||||
|
||||
void SwapEndianness()
|
||||
{
|
||||
SwapEndianBase(&type, 1);
|
||||
SwapEndianBase(&version, 1);
|
||||
SwapEndianBase(&offsetInFile, 1);
|
||||
SwapEndianBase(&id, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ChunkTableEntry_0x744
|
||||
: public ChunkHeader_0x744_0x745
|
||||
{
|
||||
void SwapEndianness()
|
||||
{
|
||||
ChunkHeader_0x744_0x745::SwapEndianness();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ChunkTableEntry_0x745
|
||||
: public ChunkHeader_0x744_0x745
|
||||
{
|
||||
uint32 size;
|
||||
|
||||
void SwapEndianness()
|
||||
{
|
||||
ChunkHeader_0x744_0x745::SwapEndianness();
|
||||
SwapEndianBase(&size, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ChunkTableEntry_0x746
|
||||
{
|
||||
uint16 type;
|
||||
uint16 version;
|
||||
uint32 id;
|
||||
uint32 size;
|
||||
uint32 offsetInFile;
|
||||
|
||||
enum
|
||||
{
|
||||
kBigEndianVersionFlag = 0x8000U
|
||||
};
|
||||
|
||||
void SwapEndianness()
|
||||
{
|
||||
SwapEndianBase(&type, 1);
|
||||
SwapEndianBase(&version, 1);
|
||||
SwapEndianBase(&id, 1);
|
||||
SwapEndianBase(&size, 1);
|
||||
SwapEndianBase(&offsetInFile, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// We need this function to strip 0x744 & 0x745 chunk headers
|
||||
// from chunk data properly: some chunks in 0x744 and 0x745 formats
|
||||
// don't have chunk headers in their data.
|
||||
// 'chunkType' is expected to be provided in the 0x746 format.
|
||||
inline bool ChunkContainsHeader_0x744_0x745(const uint16 chunkType, const uint16 chunkVersion)
|
||||
{
|
||||
switch (chunkType)
|
||||
{
|
||||
case ChunkType_SourceInfo:
|
||||
return false;
|
||||
case ChunkType_Controller:
|
||||
return (chunkVersion != CONTROLLER_CHUNK_DESC_0827::VERSION && chunkVersion != CONTROLLER_CHUNK_DESC_0830::VERSION);
|
||||
case ChunkType_BoneNameList:
|
||||
return (chunkVersion != BONENAMELIST_CHUNK_DESC_0745::VERSION);
|
||||
case ChunkType_MeshMorphTarget:
|
||||
return (chunkVersion != MESHMORPHTARGET_CHUNK_DESC_0001::VERSION);
|
||||
case ChunkType_BoneInitialPos:
|
||||
return (chunkVersion != BONEINITIALPOS_CHUNK_DESC_0001::VERSION);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline uint16 ConvertChunkTypeTo0x746(uint32 type)
|
||||
{
|
||||
if (type <= 0xFFFF)
|
||||
{
|
||||
// Input type seems to be already in 0x746 format (or it's 0)
|
||||
return type;
|
||||
}
|
||||
|
||||
// Input type seems to be in 0x745 format
|
||||
|
||||
if ((type & 0xFFFF) >= 0xF000)
|
||||
{
|
||||
// Cannot fit into resulting 0x746 type (uint16)
|
||||
return 0;
|
||||
}
|
||||
if ((type & 0xFFFF0000U) == 0xCCCC0000U)
|
||||
{
|
||||
return 0x1000 + (type & 0x0FFF);
|
||||
}
|
||||
if ((type & 0xFFFF0000U) == 0xACDC0000U)
|
||||
{
|
||||
return 0x2000 + (type & 0x0FFF);
|
||||
}
|
||||
if ((type & 0xFFFF0000U) == 0xAAFC0000U)
|
||||
{
|
||||
return 0x3000 + (type & 0x0FFF);
|
||||
}
|
||||
|
||||
// Unknown 0x745 chunk type
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline uint32 ConvertChunkTypeTo0x745(uint32 type)
|
||||
{
|
||||
if (type > 0xFFFF)
|
||||
{
|
||||
// Input type seems to be already in 0x745 format
|
||||
return type;
|
||||
}
|
||||
|
||||
// Input type seems to be in 0x746 format
|
||||
|
||||
if ((type & 0xF000) == 0x1000)
|
||||
{
|
||||
return 0xCCCC0000U + (type & 0x0FFF);
|
||||
}
|
||||
if ((type & 0xF000) == 0x2000)
|
||||
{
|
||||
return 0xACDC0000U + (type & 0x0FFF);
|
||||
}
|
||||
if ((type & 0xF000) == 0x3000)
|
||||
{
|
||||
return 0xAAFC0000U + (type & 0x0FFF);
|
||||
}
|
||||
|
||||
// Unknown 0x746 chunk type (or it's 0)
|
||||
return 0;
|
||||
}
|
||||
} // namespace ChunkFile
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILECOMPONENTS_H
|
||||
@@ -1,585 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include <platform.h>
|
||||
#include <CryFile.h>
|
||||
#include <CryHeaders.h>
|
||||
#include "ChunkFileReaders.h"
|
||||
#include "CryPath.h"
|
||||
|
||||
namespace ChunkFile
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CryFileReader::CryFileReader()
|
||||
{
|
||||
}
|
||||
|
||||
CryFileReader::~CryFileReader()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
bool CryFileReader::Open(const char* filename)
|
||||
{
|
||||
Close();
|
||||
|
||||
if (filename == 0 || filename[0] == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_f.Open(filename, "rb"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CryFileReader::Close()
|
||||
{
|
||||
m_f.Close();
|
||||
}
|
||||
|
||||
int32 CryFileReader::GetSize()
|
||||
{
|
||||
return m_f.GetLength();
|
||||
}
|
||||
|
||||
bool CryFileReader::SetPos(int32 pos)
|
||||
{
|
||||
if (pos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_offset = pos;
|
||||
return m_f.Seek(m_offset, SEEK_SET) == 0;
|
||||
}
|
||||
|
||||
bool CryFileReader::Read(void* buffer, size_t size)
|
||||
{
|
||||
return m_f.ReadRaw(buffer, size) == size;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MemoryReader::MemoryReader()
|
||||
: m_ptr(0)
|
||||
, m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryReader::~MemoryReader()
|
||||
{
|
||||
}
|
||||
|
||||
bool MemoryReader::Start(void* ptr, int32 size)
|
||||
{
|
||||
if (ptr == 0 || size <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ptr = (char*)ptr;
|
||||
m_size = size;
|
||||
m_offset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryReader::Close()
|
||||
{
|
||||
}
|
||||
|
||||
int32 MemoryReader::GetSize()
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool MemoryReader::SetPos(int32 pos)
|
||||
{
|
||||
if (pos < 0 || pos > m_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_offset = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemoryReader::Read(void* buffer, size_t size)
|
||||
{
|
||||
if (!m_ptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((size_t)m_offset + size > (size_t)m_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(buffer, &m_ptr[m_offset], size);
|
||||
m_offset += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
class ChunkListRef
|
||||
{
|
||||
std::vector<IChunkFile::ChunkDesc>& m_chunks;
|
||||
|
||||
public:
|
||||
ChunkListRef(std::vector<IChunkFile::ChunkDesc>& chunks)
|
||||
: m_chunks(chunks)
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
if (m_chunks[i].data)
|
||||
{
|
||||
delete [] (char*)m_chunks[i].data;
|
||||
m_chunks[i].data = 0;
|
||||
}
|
||||
}
|
||||
m_chunks.clear();
|
||||
}
|
||||
|
||||
void Create(size_t count)
|
||||
{
|
||||
Clear();
|
||||
m_chunks.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
m_chunks[i].data = 0;
|
||||
m_chunks[i].size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Sort()
|
||||
{
|
||||
std::sort(m_chunks.begin(), m_chunks.end(), IChunkFile::ChunkDesc::LessOffset);
|
||||
}
|
||||
|
||||
size_t GetCount() const
|
||||
{
|
||||
return m_chunks.size();
|
||||
}
|
||||
|
||||
IChunkFile::ChunkDesc& Get(size_t index)
|
||||
{
|
||||
return m_chunks[index];
|
||||
}
|
||||
};
|
||||
|
||||
class ChunkPtrListRef
|
||||
{
|
||||
std::vector<IChunkFile::ChunkDesc*>& m_chunks;
|
||||
|
||||
public:
|
||||
ChunkPtrListRef(std::vector<IChunkFile::ChunkDesc*>& chunks)
|
||||
: m_chunks(chunks)
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
if (m_chunks[i])
|
||||
{
|
||||
if (m_chunks[i]->data)
|
||||
{
|
||||
delete [] (char*)(m_chunks[i]->data);
|
||||
m_chunks[i]->data = 0;
|
||||
}
|
||||
delete m_chunks[i];
|
||||
}
|
||||
}
|
||||
m_chunks.clear();
|
||||
}
|
||||
|
||||
void Create(size_t count)
|
||||
{
|
||||
Clear();
|
||||
m_chunks.resize(count, 0);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
m_chunks[i] = new IChunkFile::ChunkDesc;
|
||||
m_chunks[i]->data = 0;
|
||||
m_chunks[i]->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Sort()
|
||||
{
|
||||
std::sort(m_chunks.begin(), m_chunks.end(), IChunkFile::ChunkDesc::LessOffsetByPtr);
|
||||
}
|
||||
|
||||
size_t GetCount() const
|
||||
{
|
||||
return m_chunks.size();
|
||||
}
|
||||
|
||||
IChunkFile::ChunkDesc& Get(size_t index)
|
||||
{
|
||||
return *m_chunks[index];
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class TListRef>
|
||||
static const char* GetChunkTableEntries_0x744_0x745_Tpl(IReader* pReader, TListRef& chunks)
|
||||
{
|
||||
chunks.Clear();
|
||||
|
||||
ChunkFile::FileHeader_0x744_0x745 header;
|
||||
|
||||
if (!pReader->SetPos(0) ||
|
||||
!pReader->Read(&header, sizeof(header)))
|
||||
{
|
||||
return "Cannot read header of chunk file";
|
||||
}
|
||||
|
||||
if (!header.HasValidSignature())
|
||||
{
|
||||
return "Unknown signature in chunk file";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
header.SwapEndianness();
|
||||
}
|
||||
|
||||
if (header.version != 0x744 && header.version != 0x745)
|
||||
{
|
||||
return "Version of chunk file is neither 0x744 nor 0x745";
|
||||
}
|
||||
|
||||
if (header.fileType != header.eFileType_Geom && header.fileType != header.eFileType_Anim)
|
||||
{
|
||||
return "Type of chunk file is neither FileType_Geom nor FileType_Anim";
|
||||
}
|
||||
|
||||
uint32 chunkCount = 0;
|
||||
{
|
||||
if (!pReader->SetPos(header.chunkTableOffset) ||
|
||||
!pReader->Read(&chunkCount, sizeof(chunkCount)))
|
||||
{
|
||||
return "Failed to read # of chunks";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
SwapEndianBase(&chunkCount, 1);
|
||||
}
|
||||
|
||||
if (chunkCount < 0 || chunkCount > 1000000)
|
||||
{
|
||||
return "Invalid # of chunks in file";
|
||||
}
|
||||
}
|
||||
|
||||
if (chunkCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
chunks.Create(chunkCount);
|
||||
|
||||
if (header.version == 0x744)
|
||||
{
|
||||
std::vector<ChunkFile::ChunkTableEntry_0x744> srcChunks;
|
||||
srcChunks.resize(chunkCount);
|
||||
|
||||
if (!pReader->Read(&srcChunks[0], sizeof(srcChunks[0]) * srcChunks.size()))
|
||||
{
|
||||
return "Failed to read chunk entries from file";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
for (uint32 i = 0; i < chunkCount; ++i)
|
||||
{
|
||||
srcChunks[i].SwapEndianness();
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < chunkCount; ++i)
|
||||
{
|
||||
IChunkFile::ChunkDesc& cd = chunks.Get(i);
|
||||
|
||||
cd.chunkType = (ChunkTypes)ConvertChunkTypeTo0x746(srcChunks[i].type);
|
||||
cd.chunkVersion = srcChunks[i].version & ~ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag;
|
||||
cd.chunkId = srcChunks[i].id;
|
||||
cd.fileOffset = srcChunks[i].offsetInFile;
|
||||
cd.bSwapEndian = (srcChunks[i].version & ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag) ? SYSTEM_IS_LITTLE_ENDIAN : SYSTEM_IS_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
chunks.Sort();
|
||||
|
||||
const uint32 endOfChunkData = (header.chunkTableOffset < chunks.Get(0).fileOffset)
|
||||
? (uint32)pReader->GetSize()
|
||||
: header.chunkTableOffset;
|
||||
|
||||
for (uint32 i = 0; i < chunkCount; ++i)
|
||||
{
|
||||
// calculate chunk size based on the next (by offset in file) chunk or
|
||||
// on the end of the chunk data portion of the file
|
||||
|
||||
const size_t nextOffsetInFile = (i + 1 < chunkCount)
|
||||
? chunks.Get(i + 1).fileOffset
|
||||
: endOfChunkData;
|
||||
|
||||
chunks.Get(i).size = nextOffsetInFile - chunks.Get(i).fileOffset;
|
||||
}
|
||||
}
|
||||
else // header.version == 0x745
|
||||
{
|
||||
std::vector<ChunkFile::ChunkTableEntry_0x745> srcChunks;
|
||||
srcChunks.resize(chunkCount);
|
||||
|
||||
if (!pReader->Read(&srcChunks[0], sizeof(srcChunks[0]) * srcChunks.size()))
|
||||
{
|
||||
return "Failed to read chunk entries from file.";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
for (uint32 i = 0; i < chunkCount; ++i)
|
||||
{
|
||||
srcChunks[i].SwapEndianness();
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < chunkCount; ++i)
|
||||
{
|
||||
IChunkFile::ChunkDesc& cd = chunks.Get(i);
|
||||
|
||||
cd.chunkType = (ChunkTypes)ConvertChunkTypeTo0x746(srcChunks[i].type);
|
||||
cd.chunkVersion = srcChunks[i].version & ~ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag;
|
||||
cd.chunkId = srcChunks[i].id;
|
||||
cd.fileOffset = srcChunks[i].offsetInFile;
|
||||
cd.size = srcChunks[i].size;
|
||||
cd.bSwapEndian = (srcChunks[i].version & ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag) ? SYSTEM_IS_LITTLE_ENDIAN : SYSTEM_IS_BIG_ENDIAN;
|
||||
}
|
||||
}
|
||||
|
||||
const uint32 fileSize = (uint32)pReader->GetSize();
|
||||
|
||||
for (uint32 i = 0; i < chunkCount; ++i)
|
||||
{
|
||||
const IChunkFile::ChunkDesc& cd = chunks.Get(i);
|
||||
|
||||
if (cd.size + cd.fileOffset > fileSize)
|
||||
{
|
||||
return "Data in chunk file are corrupted";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template <class TListRef>
|
||||
static const char* GetChunkTableEntries_0x746_Tpl(IReader* pReader, TListRef& chunks)
|
||||
{
|
||||
chunks.Clear();
|
||||
|
||||
ChunkFile::FileHeader_0x746 header;
|
||||
|
||||
if (!pReader->SetPos(0) ||
|
||||
!pReader->Read(&header, sizeof(header)))
|
||||
{
|
||||
return "Cannot read header from file.";
|
||||
}
|
||||
|
||||
if (!header.HasValidSignature())
|
||||
{
|
||||
return "Unknown signature in chunk file";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
header.SwapEndianness();
|
||||
}
|
||||
|
||||
if (header.version != 0x746)
|
||||
{
|
||||
return "Version of chunk file is not 0x746";
|
||||
}
|
||||
|
||||
if (header.chunkCount < 0 || header.chunkCount > 10000000)
|
||||
{
|
||||
return "Invalid # of chunks in file.";
|
||||
}
|
||||
|
||||
if (header.chunkCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
chunks.Create(header.chunkCount);
|
||||
|
||||
std::vector<ChunkFile::ChunkTableEntry_0x746> srcChunks;
|
||||
srcChunks.resize(header.chunkCount);
|
||||
|
||||
if (!pReader->SetPos(header.chunkTableOffset) ||
|
||||
!pReader->Read(&srcChunks[0], sizeof(srcChunks[0]) * srcChunks.size()))
|
||||
{
|
||||
return "Failed to read chunk entries from file";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
for (uint32 i = 0; i < header.chunkCount; ++i)
|
||||
{
|
||||
srcChunks[i].SwapEndianness();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0, n = chunks.GetCount(); i < n; ++i)
|
||||
{
|
||||
IChunkFile::ChunkDesc& cd = chunks.Get(i);
|
||||
|
||||
cd.chunkType = (ChunkTypes)srcChunks[i].type;
|
||||
cd.chunkVersion = srcChunks[i].version & ~ChunkFile::ChunkTableEntry_0x746::kBigEndianVersionFlag;
|
||||
cd.chunkId = srcChunks[i].id;
|
||||
cd.size = srcChunks[i].size;
|
||||
cd.fileOffset = srcChunks[i].offsetInFile;
|
||||
cd.bSwapEndian = (srcChunks[i].version & ChunkFile::ChunkTableEntry_0x746::kBigEndianVersionFlag) ? SYSTEM_IS_LITTLE_ENDIAN : SYSTEM_IS_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template <class TListRef>
|
||||
static const char* StripChunkHeaders_0x744_0x745_Tpl(IReader* pReader, TListRef& chunks)
|
||||
{
|
||||
for (size_t i = 0, n = chunks.GetCount(); i < n; ++i)
|
||||
{
|
||||
IChunkFile::ChunkDesc& ct = chunks.Get(i);
|
||||
|
||||
if (ChunkFile::ChunkContainsHeader_0x744_0x745(ct.chunkType, ct.chunkVersion))
|
||||
{
|
||||
ChunkFile::ChunkHeader_0x744_0x745 ch;
|
||||
if (ct.size < sizeof(ch))
|
||||
{
|
||||
return "Damaged data: reported size of chunk data is less that size of the chunk header";
|
||||
}
|
||||
|
||||
// Validation
|
||||
{
|
||||
if (!pReader->SetPos(ct.fileOffset) ||
|
||||
!pReader->Read(&ch, sizeof(ch)))
|
||||
{
|
||||
return "Failed to read chunk header from file";
|
||||
}
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
ch.SwapEndianness();
|
||||
}
|
||||
|
||||
ch.version &= ~ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag;
|
||||
|
||||
if (ConvertChunkTypeTo0x746(ch.type) != ct.chunkType ||
|
||||
ch.version != ct.chunkVersion ||
|
||||
ch.id != ct.chunkId)
|
||||
{
|
||||
return "Data in a chunk header don't match data in the chunk table";
|
||||
}
|
||||
|
||||
// The following check is commented out because we have (on 2013/11/25)
|
||||
// big number of .cgf files in Crysis 3 that fail to pass the check.
|
||||
//if (ch.offsetInFile != ct.fileOffset)
|
||||
//{
|
||||
// return "File offset data in a chunk header don't match data in the chunk table";
|
||||
//}
|
||||
}
|
||||
|
||||
ct.fileOffset += sizeof(ch);
|
||||
ct.size -= sizeof(ch);
|
||||
|
||||
if (ct.data)
|
||||
{
|
||||
ct.data = ((char*)ct.data) + sizeof(ch);
|
||||
}
|
||||
}
|
||||
|
||||
if (ct.size < 0)
|
||||
{
|
||||
return "A negative-length chunk found in file";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char* GetChunkTableEntries_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc>& chunks)
|
||||
{
|
||||
ChunkListRef c(chunks);
|
||||
return GetChunkTableEntries_0x744_0x745_Tpl(pReader, c);
|
||||
}
|
||||
|
||||
const char* GetChunkTableEntries_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc*>& chunks)
|
||||
{
|
||||
ChunkPtrListRef c(chunks);
|
||||
return GetChunkTableEntries_0x744_0x745_Tpl(pReader, c);
|
||||
}
|
||||
|
||||
|
||||
const char* GetChunkTableEntries_0x746(IReader* pReader, std::vector<IChunkFile::ChunkDesc>& chunks)
|
||||
{
|
||||
ChunkListRef c(chunks);
|
||||
return GetChunkTableEntries_0x746_Tpl(pReader, c);
|
||||
}
|
||||
|
||||
const char* GetChunkTableEntries_0x746(IReader* pReader, std::vector<IChunkFile::ChunkDesc*>& chunks)
|
||||
{
|
||||
ChunkPtrListRef c(chunks);
|
||||
return GetChunkTableEntries_0x746_Tpl(pReader, c);
|
||||
}
|
||||
|
||||
|
||||
const char* StripChunkHeaders_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc>& chunks)
|
||||
{
|
||||
ChunkListRef c(chunks);
|
||||
return StripChunkHeaders_0x744_0x745_Tpl(pReader, c);
|
||||
}
|
||||
|
||||
const char* StripChunkHeaders_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc*>& chunks)
|
||||
{
|
||||
ChunkPtrListRef c(chunks);
|
||||
return StripChunkHeaders_0x744_0x745_Tpl(pReader, c);
|
||||
}
|
||||
} // namespace ChunkFile
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILEREADERS_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILEREADERS_H
|
||||
#pragma once
|
||||
|
||||
#include <CryFile.h> // for CCryFile
|
||||
#include "ChunkFileComponents.h"
|
||||
#include <CryFile.h>
|
||||
#include "IChunkFile.h"
|
||||
|
||||
namespace ChunkFile
|
||||
{
|
||||
struct IReader
|
||||
{
|
||||
virtual ~IReader()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Close() = 0;
|
||||
virtual int32 GetSize() = 0;
|
||||
virtual bool SetPos(int32 pos) = 0;
|
||||
virtual bool Read(void* buffer, size_t size) = 0;
|
||||
};
|
||||
|
||||
|
||||
class CryFileReader
|
||||
: public IReader
|
||||
{
|
||||
public:
|
||||
CryFileReader();
|
||||
virtual ~CryFileReader();
|
||||
|
||||
bool Open(const char* filename);
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IReader interface
|
||||
virtual void Close();
|
||||
virtual int32 GetSize();
|
||||
virtual bool SetPos(int32 pos);
|
||||
virtual bool Read(void* buffer, size_t size);
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
CCryFile m_f;
|
||||
int32 m_offset;
|
||||
};
|
||||
|
||||
|
||||
class MemoryReader
|
||||
: public IReader
|
||||
{
|
||||
public:
|
||||
MemoryReader();
|
||||
virtual ~MemoryReader();
|
||||
|
||||
bool Start(void* ptr, int32 size);
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IReader interface
|
||||
virtual void Close();
|
||||
virtual int32 GetSize();
|
||||
virtual bool SetPos(int32 pos);
|
||||
virtual bool Read(void* buffer, size_t size);
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
char* m_ptr;
|
||||
int32 m_size;
|
||||
int32 m_offset;
|
||||
};
|
||||
|
||||
|
||||
const char* GetChunkTableEntries_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc>& chunks);
|
||||
const char* GetChunkTableEntries_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc*>& chunks);
|
||||
|
||||
const char* GetChunkTableEntries_0x746(IReader* pReader, std::vector<IChunkFile::ChunkDesc>& chunks);
|
||||
const char* GetChunkTableEntries_0x746(IReader* pReader, std::vector<IChunkFile::ChunkDesc*>& chunks);
|
||||
|
||||
const char* StripChunkHeaders_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc>& chunks);
|
||||
const char* StripChunkHeaders_0x744_0x745(IReader* pReader, std::vector<IChunkFile::ChunkDesc*>& chunks);
|
||||
} // namespace ChunkFile
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILEREADERS_H
|
||||
@@ -1,643 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include <platform.h>
|
||||
#include "ChunkFileWriters.h"
|
||||
#include <AzFramework/Archive/IArchive.h>
|
||||
|
||||
static inline size_t ComputeSizeOfAlignment(size_t pos, size_t alignment)
|
||||
{
|
||||
if (alignment <= 1 || (alignment & (alignment - 1)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
const size_t mask = alignment - 1;
|
||||
return (alignment - (pos & mask)) & mask;
|
||||
}
|
||||
|
||||
|
||||
namespace ChunkFile
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool IWriter::WriteZeros(size_t size)
|
||||
{
|
||||
if (size <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
char bf[1024];
|
||||
memset(bf, 0, (sizeof(bf) < size ? sizeof(bf) : size));
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
const uint32 sz = (sizeof(bf) < size ? sizeof(bf) : size);
|
||||
size -= sz;
|
||||
if (!Write(bf, sz))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OsFileWriter::OsFileWriter()
|
||||
: m_f(0)
|
||||
{
|
||||
}
|
||||
|
||||
OsFileWriter::~OsFileWriter()
|
||||
{
|
||||
Erase();
|
||||
}
|
||||
|
||||
bool OsFileWriter::Create(const char* filename)
|
||||
{
|
||||
Erase();
|
||||
|
||||
if (filename == 0 || filename[0] == 0)
|
||||
{
|
||||
// RCLogError("Filename is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_filename = filename;
|
||||
|
||||
m_f = nullptr;
|
||||
azfopen(&m_f, filename, "wb");
|
||||
if (!m_f)
|
||||
{
|
||||
// RCLogError("Failed to create file %s.", m_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OsFileWriter::Erase()
|
||||
{
|
||||
if (m_f)
|
||||
{
|
||||
Close();
|
||||
::remove(m_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void OsFileWriter::Close()
|
||||
{
|
||||
if (m_f)
|
||||
{
|
||||
fclose(m_f);
|
||||
m_f = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int32 OsFileWriter::GetPos() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
bool OsFileWriter::Write(const void* buffer, size_t size)
|
||||
{
|
||||
if (!m_f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fwrite(buffer, size, 1, m_f) != 1)
|
||||
{
|
||||
// RCLogError("Failed to write %u byte(s) to file %s.", (uint)size, m_filename.c_str());
|
||||
Erase();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offset += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#if !defined(RESOURCE_COMPILER)
|
||||
|
||||
CryPakFileWriter::CryPakFileWriter()
|
||||
: m_pPak(0)
|
||||
, m_fileHandle(AZ::IO::InvalidHandle)
|
||||
{
|
||||
}
|
||||
|
||||
CryPakFileWriter::~CryPakFileWriter()
|
||||
{
|
||||
Erase();
|
||||
}
|
||||
|
||||
bool CryPakFileWriter::Create(AZ::IO::IArchive* pPak, const char* filename)
|
||||
{
|
||||
Erase();
|
||||
|
||||
if (pPak == 0 || filename == 0 || filename[0] == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pPak = pPak;
|
||||
m_filename = filename;
|
||||
|
||||
m_fileHandle = m_pPak->FOpen(m_filename.c_str(), "w+b");
|
||||
|
||||
if (m_fileHandle == AZ::IO::InvalidHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CryPakFileWriter::Erase()
|
||||
{
|
||||
if (m_fileHandle != AZ::IO::InvalidHandle)
|
||||
{
|
||||
Close();
|
||||
m_pPak->RemoveFile(m_filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void CryPakFileWriter::Close()
|
||||
{
|
||||
if (m_fileHandle != AZ::IO::InvalidHandle)
|
||||
{
|
||||
m_pPak->FClose(m_fileHandle);
|
||||
m_fileHandle = AZ::IO::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
int32 CryPakFileWriter::GetPos() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
bool CryPakFileWriter::Write(const void* buffer, size_t size)
|
||||
{
|
||||
if (m_fileHandle == AZ::IO::InvalidHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pPak->FWrite(buffer, 1, size, m_fileHandle) != size)
|
||||
{
|
||||
Erase();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_offset += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MemoryWriter::MemoryWriter()
|
||||
: m_ptr(0)
|
||||
, m_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
MemoryWriter::~MemoryWriter()
|
||||
{
|
||||
}
|
||||
|
||||
bool MemoryWriter::Start(void* ptr, int32 size)
|
||||
{
|
||||
Erase();
|
||||
|
||||
if (ptr == 0 || size <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ptr = (char*)ptr;
|
||||
m_size = size;
|
||||
m_offset = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryWriter::Erase()
|
||||
{
|
||||
m_ptr = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
void MemoryWriter::Close()
|
||||
{
|
||||
m_ptr = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
int32 MemoryWriter::GetPos() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
bool MemoryWriter::Write(const void* buffer, size_t size)
|
||||
{
|
||||
if (!m_ptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((size_t)m_offset + size > (size_t)m_size)
|
||||
{
|
||||
Erase();
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&m_ptr[m_offset], buffer, size);
|
||||
m_offset += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MemorylessChunkFileWriter::MemorylessChunkFileWriter(
|
||||
EChunkFileFormat eFormat,
|
||||
IWriter* pWriter)
|
||||
: m_eChunkFileFormat(eFormat)
|
||||
, m_pWriter(pWriter)
|
||||
, m_alignment(4)
|
||||
, m_chunkCount(0)
|
||||
, m_eState(eState_Init)
|
||||
{
|
||||
if (!m_pWriter)
|
||||
{
|
||||
m_eState = eState_Fail;
|
||||
}
|
||||
}
|
||||
|
||||
MemorylessChunkFileWriter::~MemorylessChunkFileWriter()
|
||||
{
|
||||
if (m_eState != eState_Success)
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::SetAlignment(size_t alignment)
|
||||
{
|
||||
m_alignment = (alignment < 1) ? 1 : alignment;
|
||||
}
|
||||
|
||||
bool MemorylessChunkFileWriter::StartPass()
|
||||
{
|
||||
switch (m_eState)
|
||||
{
|
||||
case eState_Init:
|
||||
m_eState = eState_CountingChunks;
|
||||
m_chunkIndex = -1;
|
||||
break;
|
||||
case eState_CountingChunks:
|
||||
WriteFileHeader(m_chunkIndex + 1, GetSizeOfHeader());
|
||||
m_eState = eState_WritingChunkTable;
|
||||
WriteChunkTableHeader(m_chunkIndex + 1);
|
||||
m_dataOffsetInFile = GetSizeOfHeader() + GetSizeOfChunkTable(m_chunkIndex + 1);
|
||||
m_chunkIndex = -1;
|
||||
break;
|
||||
case eState_WritingChunkTable:
|
||||
if (m_chunkIndex >= 0)
|
||||
{
|
||||
WriteChunkEntry();
|
||||
}
|
||||
m_eState = eState_WritingData;
|
||||
m_dataOffsetInFile = GetSizeOfHeader() + GetSizeOfChunkTable(m_chunkIndex + 1);
|
||||
m_chunkIndex = -1;
|
||||
break;
|
||||
case eState_WritingData:
|
||||
m_eState = eState_Success;
|
||||
m_pWriter->Close();
|
||||
return false;
|
||||
case eState_Fail:
|
||||
return false;
|
||||
default:
|
||||
assert(0);
|
||||
Fail();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::StartChunk(EEndianness eEndianness, uint32 type, uint32 version, uint32 id)
|
||||
{
|
||||
if (type != 0)
|
||||
{
|
||||
type = ConvertChunkTypeTo0x746(type);
|
||||
if (type == 0)
|
||||
{
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (version >= ChunkFile::ChunkTableEntry_0x746::kBigEndianVersionFlag)
|
||||
{
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_eState)
|
||||
{
|
||||
case eState_CountingChunks:
|
||||
++m_chunkIndex;
|
||||
break;
|
||||
case eState_WritingChunkTable:
|
||||
if (m_chunkIndex >= 0)
|
||||
{
|
||||
WriteChunkEntry();
|
||||
}
|
||||
/* fall through */
|
||||
case eState_WritingData:
|
||||
{
|
||||
size_t size = ComputeSizeOfAlignment(m_dataOffsetInFile, m_alignment);
|
||||
|
||||
// Make sure that zero-length chunks have distinct positions in file
|
||||
if (size == 0 && m_chunkIndex > 0 && m_chunkSize == 0)
|
||||
{
|
||||
size = m_alignment;
|
||||
}
|
||||
|
||||
m_dataOffsetInFile += size;
|
||||
m_chunkOffsetInFile = m_dataOffsetInFile;
|
||||
if (m_eState == eState_WritingData && !m_pWriter->WriteZeros(size))
|
||||
{
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
++m_chunkIndex;
|
||||
m_chunkEndianness = eEndianness;
|
||||
m_chunkType = type;
|
||||
m_chunkVersion = version;
|
||||
m_chunkId = id;
|
||||
m_chunkSize = 0;
|
||||
|
||||
if (m_eChunkFileFormat == eChunkFileFormat_0x745 &&
|
||||
ChunkContainsHeader_0x744_0x745(m_chunkType, m_chunkVersion))
|
||||
{
|
||||
ChunkHeader_0x744_0x745 c;
|
||||
|
||||
c.type = ConvertChunkTypeTo0x745(m_chunkType);
|
||||
c.version = m_chunkVersion | (m_chunkEndianness == eEndianness_Big ? ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag : 0);
|
||||
c.id = m_chunkId;
|
||||
c.offsetInFile = m_chunkOffsetInFile;
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
c.SwapEndianness();
|
||||
}
|
||||
|
||||
AddChunkData(&c, sizeof(c));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Fail();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::AddChunkData(void* ptr, size_t size)
|
||||
{
|
||||
if (m_chunkIndex < 0)
|
||||
{
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_eState)
|
||||
{
|
||||
case eState_CountingChunks:
|
||||
break;
|
||||
case eState_WritingChunkTable:
|
||||
case eState_WritingData:
|
||||
m_chunkSize += size;
|
||||
m_dataOffsetInFile += size;
|
||||
if (m_eState == eState_WritingData && !m_pWriter->Write(ptr, size))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Fail();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::AddChunkDataZeros(size_t size)
|
||||
{
|
||||
if (m_chunkIndex < 0)
|
||||
{
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_eState)
|
||||
{
|
||||
case eState_CountingChunks:
|
||||
break;
|
||||
case eState_WritingChunkTable:
|
||||
case eState_WritingData:
|
||||
m_chunkSize += size;
|
||||
m_dataOffsetInFile += size;
|
||||
if (m_eState == eState_WritingData && !m_pWriter->WriteZeros(size))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Fail();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::AddChunkDataAlignment(size_t alignment)
|
||||
{
|
||||
const size_t size = ComputeSizeOfAlignment(m_chunkSize, alignment);
|
||||
return AddChunkDataZeros(size);
|
||||
}
|
||||
|
||||
bool MemorylessChunkFileWriter::HasWrittenSuccessfully() const
|
||||
{
|
||||
return m_eState == eState_Success;
|
||||
}
|
||||
|
||||
IWriter* MemorylessChunkFileWriter::GetWriter() const
|
||||
{
|
||||
return m_pWriter;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MemorylessChunkFileWriter::Fail()
|
||||
{
|
||||
m_eState = eState_Fail;
|
||||
if (m_pWriter)
|
||||
{
|
||||
m_pWriter->Erase();
|
||||
}
|
||||
}
|
||||
|
||||
size_t MemorylessChunkFileWriter::GetSizeOfHeader() const
|
||||
{
|
||||
return (m_eChunkFileFormat == eChunkFileFormat_0x745)
|
||||
? sizeof(FileHeader_0x744_0x745)
|
||||
: sizeof(FileHeader_0x746);
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::WriteFileHeader(int32 chunkCount, uint32 chunkTableOffsetInFile)
|
||||
{
|
||||
if (m_eChunkFileFormat == eChunkFileFormat_0x745)
|
||||
{
|
||||
FileHeader_0x744_0x745 h;
|
||||
h.Set(chunkTableOffsetInFile);
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
h.SwapEndianness();
|
||||
}
|
||||
|
||||
if (!m_pWriter->Write(&h, sizeof(h)))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FileHeader_0x746 h;
|
||||
h.Set(chunkCount, chunkTableOffsetInFile);
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
h.SwapEndianness();
|
||||
}
|
||||
|
||||
if (!m_pWriter->Write(&h, sizeof(h)))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t MemorylessChunkFileWriter::GetSizeOfChunkTable(int32 chunkCount) const
|
||||
{
|
||||
if (m_eChunkFileFormat == eChunkFileFormat_0x745)
|
||||
{
|
||||
return sizeof(uint32) + chunkCount * sizeof(ChunkTableEntry_0x745);
|
||||
}
|
||||
else
|
||||
{
|
||||
return chunkCount * sizeof(ChunkTableEntry_0x746);
|
||||
}
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::WriteChunkTableHeader(int32 chunkCount)
|
||||
{
|
||||
if (m_eChunkFileFormat == eChunkFileFormat_0x745)
|
||||
{
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
SwapEndianBase(&chunkCount, 1);
|
||||
}
|
||||
|
||||
if (!m_pWriter->Write(&chunkCount, sizeof(chunkCount)))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemorylessChunkFileWriter::WriteChunkEntry()
|
||||
{
|
||||
if (m_chunkIndex < 0)
|
||||
{
|
||||
assert(0);
|
||||
Fail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_eChunkFileFormat == eChunkFileFormat_0x745)
|
||||
{
|
||||
ChunkTableEntry_0x745 c;
|
||||
|
||||
c.type = ConvertChunkTypeTo0x745(m_chunkType);
|
||||
c.version = m_chunkVersion | (m_chunkEndianness == eEndianness_Big ? ChunkFile::ChunkHeader_0x744_0x745::kBigEndianVersionFlag : 0);
|
||||
c.id = m_chunkId;
|
||||
c.size = m_chunkSize;
|
||||
c.offsetInFile = m_chunkOffsetInFile;
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
c.SwapEndianness();
|
||||
}
|
||||
|
||||
if (!m_pWriter->Write(&c, sizeof(c)))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ChunkTableEntry_0x746 c;
|
||||
|
||||
c.type = m_chunkType;
|
||||
c.version = m_chunkVersion | (m_chunkEndianness == eEndianness_Big ? ChunkFile::ChunkTableEntry_0x746::kBigEndianVersionFlag : 0);
|
||||
c.id = m_chunkId;
|
||||
c.size = m_chunkSize;
|
||||
c.offsetInFile = m_chunkOffsetInFile;
|
||||
|
||||
if (SYSTEM_IS_BIG_ENDIAN)
|
||||
{
|
||||
c.SwapEndianness();
|
||||
}
|
||||
|
||||
if (!m_pWriter->Write(&c, sizeof(c)))
|
||||
{
|
||||
Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
} // namespace ChunkFile
|
||||
@@ -1,341 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILEWRITERS_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILEWRITERS_H
|
||||
#pragma once
|
||||
|
||||
#include "ChunkFileComponents.h"
|
||||
|
||||
// RESOURCE_COMPIELR is defined by max plugin, too, and the max plugin MAY NOT include any of azcore
|
||||
// or anything else which uses modern C++
|
||||
#if !defined(RESOURCE_COMPILER)
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#endif
|
||||
|
||||
namespace AZ::IO
|
||||
{
|
||||
struct IArchive;
|
||||
}
|
||||
namespace ChunkFile
|
||||
{
|
||||
struct IWriter
|
||||
{
|
||||
virtual ~IWriter()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Erase() = 0;
|
||||
virtual void Close() = 0; // if Close() is not called then the file should be deleted in destructor
|
||||
|
||||
virtual int32 GetPos() const = 0;
|
||||
|
||||
virtual bool Write(const void* buffer, size_t size) = 0;
|
||||
|
||||
// non-virtual helper function
|
||||
bool WriteZeros(size_t size);
|
||||
};
|
||||
|
||||
|
||||
class OsFileWriter
|
||||
: public IWriter
|
||||
{
|
||||
public:
|
||||
OsFileWriter();
|
||||
virtual ~OsFileWriter();
|
||||
|
||||
bool Create(const char* filename);
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IWriter interface
|
||||
virtual void Erase();
|
||||
virtual void Close();
|
||||
|
||||
virtual int32 GetPos() const;
|
||||
|
||||
virtual bool Write(const void* buffer, size_t size);
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
string m_filename;
|
||||
FILE* m_f;
|
||||
int32 m_offset;
|
||||
};
|
||||
|
||||
|
||||
#if !defined(RESOURCE_COMPILER)
|
||||
class CryPakFileWriter
|
||||
: public IWriter
|
||||
{
|
||||
public:
|
||||
CryPakFileWriter();
|
||||
virtual ~CryPakFileWriter();
|
||||
|
||||
bool Create(AZ::IO::IArchive* pPak, const char* filename);
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IWriter interface
|
||||
virtual void Erase();
|
||||
virtual void Close();
|
||||
|
||||
virtual int32 GetPos() const;
|
||||
|
||||
virtual bool Write(const void* buffer, size_t size);
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
string m_filename;
|
||||
AZ::IO::IArchive* m_pPak;
|
||||
AZ::IO::HandleType m_fileHandle;
|
||||
int32 m_offset;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// Doesn't write any data, just computes the size
|
||||
class SizeWriter
|
||||
: public IWriter
|
||||
{
|
||||
public:
|
||||
SizeWriter()
|
||||
{
|
||||
}
|
||||
virtual ~SizeWriter()
|
||||
{
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
m_offset = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IWriter interface
|
||||
virtual void Erase()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Close()
|
||||
{
|
||||
}
|
||||
|
||||
virtual int32 GetPos() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
virtual bool Write([[maybe_unused]] const void* buffer, size_t size)
|
||||
{
|
||||
m_offset += size;
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
int32 m_offset;
|
||||
};
|
||||
|
||||
|
||||
class MemoryWriter
|
||||
: public IWriter
|
||||
{
|
||||
public:
|
||||
MemoryWriter();
|
||||
virtual ~MemoryWriter();
|
||||
|
||||
bool Start(void* ptr, int32 size);
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IWriter interface
|
||||
virtual void Erase();
|
||||
virtual void Close();
|
||||
|
||||
virtual int32 GetPos() const;
|
||||
|
||||
virtual bool Write(const void* buffer, size_t size);
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
char* m_ptr;
|
||||
int32 m_size;
|
||||
int32 m_offset;
|
||||
};
|
||||
|
||||
|
||||
// Memoryless chunk file writer
|
||||
//
|
||||
// Usage example:
|
||||
//
|
||||
// OsFileWriter writer;
|
||||
// if (!writer.Create(filename))
|
||||
// {
|
||||
// showAnErrorMessage();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MemorylessChunkFileWriter wr(eChunFileFormat, writer);
|
||||
// while (wr.StartPass())
|
||||
// {
|
||||
// // default alignment of chunk data in file is 4, but you may change it by calling wr.SetAlignment(xxx)
|
||||
//
|
||||
// wr.StartChunk(eEndianness_Native, chunkA_type, chunkA_version, chunkA_id);
|
||||
// wr.AddChunkData(data_ptr0, data_size0); // make sure that data have endianness specified by bLittleEdndian
|
||||
// wr.AddChunkData(data_ptr1, data_size1);
|
||||
// ...
|
||||
// wr.StartChunk(eEndianness_Native, chunkB_type, chunkB_version, chunkB_id);
|
||||
// wr.AddChunkData(data_ptrN, data_sizeN);
|
||||
// ...
|
||||
// }
|
||||
// if (!wr.HasWrittenSuccessfully())
|
||||
// {
|
||||
// showAnErrorMessage();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Usage example (interface way): see
|
||||
//
|
||||
// OsFileWriter writer;
|
||||
// if (!writer.Create(filename))
|
||||
// {
|
||||
// showAnErrorMessage();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// MemorylessChunkFileWriter wr(eChunFileFormat, writer);
|
||||
// while (wr.StartPass())
|
||||
// {
|
||||
// // default alignment of chunk data in file is 4, but you may change it by calling wr.SetAlignment(xxx)
|
||||
//
|
||||
// wr.StartChunk(eEndianness_Native, chunkA_type, chunkA_version, chunkA_id);
|
||||
// wr.AddChunkData(data_ptr0, data_size0); // make sure that data have endianness specified by bLittleEdndian
|
||||
// wr.AddChunkData(data_ptr1, data_size1);
|
||||
// ...
|
||||
// wr.StartChunk(eEndianness_Native, chunkB_type, chunkB_version, chunkB_id);
|
||||
// wr.AddChunkData(data_ptrN, data_sizeN);
|
||||
// ...
|
||||
// }
|
||||
// if (!wr.HasWrittenSuccessfully())
|
||||
// {
|
||||
// showAnErrorMessage();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
struct IChunkFileWriter
|
||||
{
|
||||
virtual ~IChunkFileWriter()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Sets alignment for *beginning* of chunk data.
|
||||
// Allowed to be called at any time, influences all future
|
||||
// StartChunk() calls (until a new SetAlignment() call).
|
||||
virtual void SetAlignment(size_t alignment) = 0;
|
||||
|
||||
// Returns false when there is no more passes left.
|
||||
virtual bool StartPass() = 0;
|
||||
|
||||
// eEndianness specifies endianness of the data user is
|
||||
// going to provide via AddChunkData*(). The data will be
|
||||
// sent to the low-level writer as is, without any re-coding.
|
||||
virtual void StartChunk(EEndianness eEndianness, uint32 type, uint32 version, uint32 id) = 0;
|
||||
virtual void AddChunkData(void* ptr, size_t size) = 0;
|
||||
virtual void AddChunkDataZeros(size_t size) = 0;
|
||||
virtual void AddChunkDataAlignment(size_t alignment) = 0;
|
||||
|
||||
virtual bool HasWrittenSuccessfully() const = 0;
|
||||
|
||||
virtual IWriter* GetWriter() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class MemorylessChunkFileWriter
|
||||
: public IChunkFileWriter
|
||||
{
|
||||
public:
|
||||
enum EChunkFileFormat
|
||||
{
|
||||
eChunkFileFormat_0x745,
|
||||
eChunkFileFormat_0x746,
|
||||
};
|
||||
|
||||
MemorylessChunkFileWriter(EChunkFileFormat eFormat, IWriter* pWriter);
|
||||
|
||||
//-------------------------------------------------------
|
||||
// IChunkFileWriter interface
|
||||
virtual ~MemorylessChunkFileWriter();
|
||||
|
||||
virtual void SetAlignment(size_t alignment);
|
||||
|
||||
virtual bool StartPass();
|
||||
|
||||
virtual void StartChunk(EEndianness eEndianness, uint32 type, uint32 version, uint32 id);
|
||||
virtual void AddChunkData(void* ptr, size_t size);
|
||||
virtual void AddChunkDataZeros(size_t size);
|
||||
virtual void AddChunkDataAlignment(size_t alignment);
|
||||
|
||||
virtual bool HasWrittenSuccessfully() const;
|
||||
|
||||
virtual IWriter* GetWriter() const;
|
||||
//-------------------------------------------------------
|
||||
|
||||
private:
|
||||
void Fail();
|
||||
|
||||
static size_t ComputeSizeOfAlignmentArea(size_t pos, size_t alignment);
|
||||
|
||||
size_t GetSizeOfHeader() const;
|
||||
void WriteFileHeader(int32 chunkCount, uint32 chunkTableOffsetInFile);
|
||||
|
||||
size_t GetSizeOfChunkTable(int32 chunkCount) const;
|
||||
void WriteChunkTableHeader(int32 chunkCount);
|
||||
void WriteChunkEntry();
|
||||
|
||||
private:
|
||||
IWriter* const m_pWriter;
|
||||
|
||||
EChunkFileFormat m_eChunkFileFormat;
|
||||
|
||||
size_t m_alignment;
|
||||
|
||||
int32 m_chunkCount;
|
||||
|
||||
int32 m_chunkIndex;
|
||||
uint16 m_chunkType;
|
||||
uint16 m_chunkVersion;
|
||||
uint32 m_chunkId;
|
||||
uint32 m_chunkSize;
|
||||
uint32 m_chunkOffsetInFile;
|
||||
EEndianness m_chunkEndianness;
|
||||
|
||||
uint32 m_dataOffsetInFile;
|
||||
|
||||
enum EState
|
||||
{
|
||||
eState_Init,
|
||||
|
||||
eState_CountingChunks,
|
||||
eState_WritingChunkTable,
|
||||
eState_WritingData,
|
||||
|
||||
eState_Success,
|
||||
eState_Fail,
|
||||
};
|
||||
EState m_eState;
|
||||
};
|
||||
} // namespace ChunkFile
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_CHUNKFILEWRITERS_H
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include <platform.h>
|
||||
#include "ReadOnlyChunkFile.h"
|
||||
#include "ChunkFileComponents.h"
|
||||
#include "ChunkFileReaders.h"
|
||||
#include <AzCore/Casting/numeric_cast.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
|
||||
#define MAX_CHUNKS_NUM 10000000
|
||||
|
||||
#if !defined(FUNCTION_PROFILER_3DENGINE)
|
||||
# define FUNCTION_PROFILER_3DENGINE
|
||||
#endif
|
||||
|
||||
#if !defined(LOADING_TIME_PROFILE_SECTION)
|
||||
# define LOADING_TIME_PROFILE_SECTION
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadOnlyChunkFile::CReadOnlyChunkFile(bool bCopyFileData, bool bNoWarningMode)
|
||||
{
|
||||
m_pFileBuffer = 0;
|
||||
m_nBufferSize = 0;
|
||||
|
||||
m_bNoWarningMode = bNoWarningMode;
|
||||
|
||||
m_bOwnFileBuffer = false;
|
||||
m_bLoaded = false;
|
||||
m_bCopyFileData = bCopyFileData;
|
||||
}
|
||||
|
||||
CReadOnlyChunkFile::~CReadOnlyChunkFile()
|
||||
{
|
||||
FreeBuffer();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CReadOnlyChunkFile::FreeBuffer()
|
||||
{
|
||||
if (m_pFileBuffer && m_bOwnFileBuffer)
|
||||
{
|
||||
delete [] m_pFileBuffer;
|
||||
}
|
||||
m_pFileBuffer = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_bOwnFileBuffer = false;
|
||||
m_bLoaded = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadOnlyChunkFile::ChunkDesc* CReadOnlyChunkFile::GetChunk(int nIndex)
|
||||
{
|
||||
assert(size_t(nIndex) < m_chunks.size());
|
||||
return &m_chunks[nIndex];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const CReadOnlyChunkFile::ChunkDesc* CReadOnlyChunkFile::GetChunk(int nIndex) const
|
||||
{
|
||||
assert(size_t(nIndex) < m_chunks.size());
|
||||
return &m_chunks[nIndex];
|
||||
}
|
||||
|
||||
// number of chunks
|
||||
int CReadOnlyChunkFile::NumChunks() const
|
||||
{
|
||||
return (int)m_chunks.size();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadOnlyChunkFile::ChunkDesc* CReadOnlyChunkFile::FindChunkByType(ChunkTypes nChunkType)
|
||||
{
|
||||
for (size_t i = 0, count = m_chunks.size(); i < count; ++i)
|
||||
{
|
||||
if (m_chunks[i].chunkType == nChunkType)
|
||||
{
|
||||
return &m_chunks[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadOnlyChunkFile::ChunkDesc* CReadOnlyChunkFile::FindChunkById(int id)
|
||||
{
|
||||
ChunkDesc chunkToFind;
|
||||
chunkToFind.chunkId = id;
|
||||
|
||||
std::vector<ChunkDesc>::iterator it = std::lower_bound(m_chunks.begin(), m_chunks.end(), chunkToFind, IChunkFile::ChunkDesc::LessId);
|
||||
if (it != m_chunks.end() && id == (*it).chunkId)
|
||||
{
|
||||
return &(*it);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CReadOnlyChunkFile::ReadChunkTableFromBuffer()
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
if (m_pFileBuffer == 0)
|
||||
{
|
||||
m_LastError.Format("Unexpected empty buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
ChunkFile::MemoryReader f;
|
||||
|
||||
if (!f.Start(m_pFileBuffer, m_nBufferSize))
|
||||
{
|
||||
m_LastError.Format("Empty memory chunk file");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bStripHeaders = false;
|
||||
const char* err = 0;
|
||||
|
||||
err = ChunkFile::GetChunkTableEntries_0x746(&f, m_chunks);
|
||||
if (err)
|
||||
{
|
||||
err = ChunkFile::GetChunkTableEntries_0x744_0x745(&f, m_chunks);
|
||||
bStripHeaders = true;
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
for (size_t i = 0; i < m_chunks.size(); ++i)
|
||||
{
|
||||
ChunkDesc& cd = m_chunks[i];
|
||||
cd.data = m_pFileBuffer + cd.fileOffset;
|
||||
}
|
||||
if (bStripHeaders)
|
||||
{
|
||||
err = ChunkFile::StripChunkHeaders_0x744_0x745(&f, m_chunks);
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
m_LastError = err;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort chunks by Id, for faster queries later (see FindChunkById()).
|
||||
std::sort(m_chunks.begin(), m_chunks.end(), IChunkFile::ChunkDesc::LessId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CReadOnlyChunkFile::Read(const char* filename)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
FreeBuffer();
|
||||
|
||||
if (!AZ::IO::FileIOBase::GetInstance())
|
||||
{
|
||||
m_LastError = "File system not ready yet.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Exists(filename))
|
||||
{
|
||||
m_LastError.Format("File '%s' not found", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::u64 fileSize;
|
||||
if (!AZ::IO::FileIOBase::GetInstance()->Size(filename, fileSize))
|
||||
{
|
||||
m_LastError.Format("Failed to retrieve file size for '%s'", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pFileBuffer = new char[fileSize];
|
||||
m_bOwnFileBuffer = true;
|
||||
|
||||
AZ::IO::FileIOStream stream(filename, AZ::IO::OpenMode::ModeRead);
|
||||
if (stream.Read(fileSize, m_pFileBuffer) != fileSize)
|
||||
{
|
||||
m_LastError.Format("Failed to read %u bytes from file '%s'", fileSize, filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_nBufferSize = aznumeric_caster(fileSize);
|
||||
|
||||
if (!ReadChunkTableFromBuffer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_bLoaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CReadOnlyChunkFile::ReadFromMemory(const void* pData, int nDataSize)
|
||||
{
|
||||
LOADING_TIME_PROFILE_SECTION;
|
||||
|
||||
FreeBuffer();
|
||||
|
||||
m_pFileBuffer = (char*)pData;
|
||||
m_bOwnFileBuffer = false;
|
||||
m_nBufferSize = nDataSize;
|
||||
|
||||
if (!ReadChunkTableFromBuffer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_bLoaded = true;
|
||||
return true;
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CGF_READONLYCHUNKFILE_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CGF_READONLYCHUNKFILE_H
|
||||
#pragma once
|
||||
|
||||
#include <CrySizer.h>
|
||||
#include <CryHeaders.h>
|
||||
#include <smartptr.h>
|
||||
#include <IChunkFile.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Chunk file reader.
|
||||
// Accesses a chunked file structure through file mapping object.
|
||||
// Opens a chunk file and checks for its validity.
|
||||
// If it's invalid, closes it as if there was no open operation.
|
||||
// Error handling is performed through the return value of Read: it must
|
||||
// be true for successfully open files
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CReadOnlyChunkFile
|
||||
: public IChunkFile
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CReadOnlyChunkFile(bool bCopyFileData, bool bNoWarningMode = false);
|
||||
virtual ~CReadOnlyChunkFile();
|
||||
|
||||
// interface IChunkFile --------------------------------------------------
|
||||
|
||||
virtual void Release() { delete this; }
|
||||
|
||||
virtual bool IsReadOnly() const { return true; }
|
||||
virtual bool IsLoaded() const { return m_bLoaded; }
|
||||
|
||||
virtual bool Read(const char* filename);
|
||||
virtual bool ReadFromMemory(const void* pData, int nDataSize);
|
||||
|
||||
virtual bool Write([[maybe_unused]] const char* filename) { return false; }
|
||||
virtual bool WriteToMemoryBuffer([[maybe_unused]] void** pData, [[maybe_unused]] int* nSize) { return false; }
|
||||
virtual void ReleaseMemoryBuffer() {}
|
||||
|
||||
virtual int AddChunk([[maybe_unused]] ChunkTypes chunkType, [[maybe_unused]] int chunkVersion, [[maybe_unused]] EEndianness eEndianness, [[maybe_unused]] const void* chunkData, [[maybe_unused]] int chunkSize) { return -1; }
|
||||
virtual void DeleteChunkById([[maybe_unused]] int nChunkId) {}
|
||||
virtual void DeleteChunksByType([[maybe_unused]] ChunkTypes nChunkType) {}
|
||||
|
||||
virtual ChunkDesc* FindChunkByType(ChunkTypes nChunkType);
|
||||
virtual ChunkDesc* FindChunkById(int nChunkId);
|
||||
|
||||
virtual int NumChunks() const;
|
||||
|
||||
virtual ChunkDesc* GetChunk(int nIndex);
|
||||
virtual const ChunkDesc* GetChunk(int nIndex) const;
|
||||
|
||||
virtual const char* GetLastError() const { return m_LastError; }
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
virtual void GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
pSizer->AddObject(m_LastError);
|
||||
pSizer->AddObject(m_chunks);
|
||||
}
|
||||
private:
|
||||
bool ReadChunkTableFromBuffer();
|
||||
void FreeBuffer();
|
||||
|
||||
private:
|
||||
// this variable contains the last error occurred in this class
|
||||
string m_LastError;
|
||||
|
||||
std::vector<ChunkDesc> m_chunks;
|
||||
|
||||
char* m_pFileBuffer;
|
||||
int m_nBufferSize;
|
||||
bool m_bOwnFileBuffer;
|
||||
bool m_bNoWarningMode;
|
||||
bool m_bLoaded;
|
||||
bool m_bCopyFileData;
|
||||
};
|
||||
|
||||
TYPEDEF_AUTOPTR(CReadOnlyChunkFile);
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CGF_READONLYCHUNKFILE_H
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_SWAPENDIANNESS_H
|
||||
#define CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_SWAPENDIANNESS_H
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
inline void SwapEndians_(void* pData, size_t nCount, size_t nSizeCheck)
|
||||
{
|
||||
// Primitive type.
|
||||
switch (nSizeCheck)
|
||||
{
|
||||
case 1:
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
while (nCount--)
|
||||
{
|
||||
uint16& i = *((uint16*&)pData)++;
|
||||
i = ((i >> 8) + (i << 8)) & 0xFFFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
while (nCount--)
|
||||
{
|
||||
uint32& i = *((uint32*&)pData)++;
|
||||
i = (i >> 24) + ((i >> 8) & 0xFF00) + ((i & 0xFF00) << 8) + (i << 24);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
while (nCount--)
|
||||
{
|
||||
uint64& i = *((uint64*&)pData)++;
|
||||
i = (i >> 56) + ((i >> 40) & 0xFF00) + ((i >> 24) & 0xFF0000) + ((i >> 8) & 0xFF000000)
|
||||
+ ((i & 0xFF000000) << 8) + ((i & 0xFF0000) << 24) + ((i & 0xFF00) << 40) + (i << 56);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void SwapEndianness(T* t, std::size_t count)
|
||||
{
|
||||
SwapEndians_(t, count, sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void SwapEndianness(T& t)
|
||||
{
|
||||
SwapEndianness(&t, 1);
|
||||
}
|
||||
|
||||
|
||||
#endif // CRYINCLUDE_TOOLS_RC_RESOURCECOMPILER_SWAPENDIANNESS_H
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
set(FILES
|
||||
CGFLoader.cpp
|
||||
CGFSaver.cpp
|
||||
ChunkFile.cpp
|
||||
ReadOnlyChunkFile.cpp
|
||||
CGFLoader.h
|
||||
CGFSaver.h
|
||||
ChunkData.h
|
||||
ChunkFile.h
|
||||
ReadOnlyChunkFile.h
|
||||
ChunkFileReaders.cpp
|
||||
ChunkFileReaders.h
|
||||
ChunkFileWriters.cpp
|
||||
ChunkFileWriters.h
|
||||
SwapEndianness.h
|
||||
)
|
||||
@@ -1,80 +0,0 @@
|
||||
#
|
||||
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
# its licensors.
|
||||
#
|
||||
# For complete copyright and license terms please see the LICENSE at the root of this
|
||||
# distribution (the "License"). All use of this software is governed by the License,
|
||||
# or, if provided, by the license below or the license accompanying this file. Do not
|
||||
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
#
|
||||
|
||||
add_subdirectory(CGF)
|
||||
add_subdirectory(MeshCompiler)
|
||||
|
||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
|
||||
ly_get_pal_tool_dirs(pal_tool_dirs ${CMAKE_CURRENT_LIST_DIR}/Platform)
|
||||
|
||||
ly_add_target(
|
||||
NAME Cry3DEngine.Static STATIC
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
cry3dengine_files.cmake
|
||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
|
||||
PLATFORM_INCLUDE_FILES
|
||||
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
.
|
||||
${pal_dir}
|
||||
PRIVATE
|
||||
${pal_tool_dirs}
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::mikkelsen
|
||||
Legacy::CryCommon
|
||||
Legacy::CryRender.Headers
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME Cry3DEngine ${PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE}
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
cry3dengine_shared_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PUBLIC
|
||||
.
|
||||
..
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
Legacy::Cry3DEngine.Static
|
||||
Legacy::Cry3DEngine.MeshCompiler.Static
|
||||
Legacy::Cry3DEngine.CGF.Static
|
||||
Legacy::CryCommon
|
||||
)
|
||||
|
||||
################################################################################
|
||||
# Tests
|
||||
################################################################################
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
|
||||
ly_add_target(
|
||||
NAME Cry3DEngine.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE Legacy
|
||||
FILES_CMAKE
|
||||
cry3dengine_test_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
.
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
Legacy::CryCommon
|
||||
Legacy::Cry3DEngine.Static
|
||||
Legacy::Cry3DEngine.MeshCompiler.Static
|
||||
Legacy::Cry3DEngine.CGF.Static
|
||||
)
|
||||
ly_add_googletest(
|
||||
NAME Legacy::Cry3DEngine.Tests
|
||||
)
|
||||
endif()
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Occlusion buffer
|
||||
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
#include "CZBufferCuller.h"
|
||||
|
||||
SHWOccZBuffer HWZBuffer;
|
||||
|
||||
void CZBufferCuller::BeginFrame(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
if (!GetCVars()->e_CoverageBuffer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const CCamera& rCam = passInfo.GetCamera();
|
||||
m_AccurateTest = GetCVars()->e_CoverageBufferAccurateOBBTest;
|
||||
|
||||
m_Treshold = GetCVars()->e_CoverageBufferTolerance;
|
||||
|
||||
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
if (GetCVars()->e_CoverageBufferDebugFreeze || GetCVars()->e_CameraFreeze)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_ObjectsTested =
|
||||
m_ObjectsTestedAndRejected = 0;
|
||||
//to enable statistics
|
||||
m_Camera = rCam;
|
||||
m_Position = rCam.GetPosition();
|
||||
uint32 oldSizeX = m_SizeX;
|
||||
|
||||
const uint32 sizeX = min(max(1, GetCVars()->e_CoverageBufferResolution), 1024);
|
||||
const uint32 sizeY = sizeX;
|
||||
|
||||
m_SizeX = sizeX;
|
||||
m_SizeY = sizeY;
|
||||
m_fSizeX = static_cast<f32>(sizeX);
|
||||
m_fSizeY = static_cast<f32>(sizeY);
|
||||
m_fSizeZ = static_cast<f32>(TZB_MAXDEPTH);
|
||||
|
||||
|
||||
if (oldSizeX != sizeX)
|
||||
{
|
||||
CryModuleMemalignFree(m_ZBuffer);
|
||||
//64-byte buffer to avoid memory page issues when vector loading
|
||||
m_ZBuffer = (TZBZexel*)CryModuleMemalign((sizeof(TZBZexel) * sizeX * sizeY) + 64, 128);
|
||||
}
|
||||
|
||||
m_MatViewProj.Transpose();
|
||||
|
||||
m_RotationSafe = GetCVars()->e_CoverageBufferRotationSafeCheck;
|
||||
|
||||
m_DebugFreez = GetCVars()->e_CoverageBufferDebugFreeze != 0;
|
||||
}
|
||||
|
||||
void CZBufferCuller::ReloadBuffer(const uint32 BufferID)
|
||||
{
|
||||
if (m_DebugFreez)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_Bias = BufferID == 0 ? static_cast<int32>(GetCVars()->e_CoverageBufferBias) : 0;
|
||||
}
|
||||
|
||||
|
||||
CZBufferCuller::CZBufferCuller()
|
||||
: m_OutdoorVisible(1)
|
||||
, m_MatViewProj(IDENTITY)
|
||||
{
|
||||
m_SizeX =
|
||||
m_SizeY = min(max(1, GetCVars()->e_CoverageBufferResolution), 1024);
|
||||
m_ZBuffer = (TZBZexel*)CryModuleMemalign((sizeof(TZBZexel) * m_SizeX * m_SizeY) + 64, 128);
|
||||
|
||||
m_ObjectsTested =
|
||||
m_ObjectsTestedAndRejected = 0;
|
||||
}
|
||||
|
||||
bool CZBufferCuller::IsBoxVisible(const AABB& objBox, [[maybe_unused]] uint32* const __restrict pResDest)
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
m_ObjectsTested++;
|
||||
Vec4 Verts[8] =
|
||||
{
|
||||
m_MatViewProj* Vec4(objBox.min.x, objBox.min.y, objBox.min.z, 1.f),//0
|
||||
m_MatViewProj * Vec4(objBox.min.x, objBox.max.y, objBox.min.z, 1.f),//1
|
||||
m_MatViewProj * Vec4(objBox.max.x, objBox.min.y, objBox.min.z, 1.f),//2
|
||||
m_MatViewProj * Vec4(objBox.max.x, objBox.max.y, objBox.min.z, 1.f),//3
|
||||
m_MatViewProj * Vec4(objBox.min.x, objBox.min.y, objBox.max.z, 1.f),//4
|
||||
m_MatViewProj * Vec4(objBox.min.x, objBox.max.y, objBox.max.z, 1.f),//5
|
||||
m_MatViewProj * Vec4(objBox.max.x, objBox.min.y, objBox.max.z, 1.f),//6
|
||||
m_MatViewProj * Vec4(objBox.max.x, objBox.max.y, objBox.max.z, 1.f)//7
|
||||
};
|
||||
bool CutNearPlane = Verts[0].w <= 0.f;
|
||||
CutNearPlane |= Verts[1].w <= 0.f;
|
||||
CutNearPlane |= Verts[2].w <= 0.f;
|
||||
CutNearPlane |= Verts[3].w <= 0.f;
|
||||
CutNearPlane |= Verts[4].w <= 0.f;
|
||||
CutNearPlane |= Verts[5].w <= 0.f;
|
||||
CutNearPlane |= Verts[6].w <= 0.f;
|
||||
CutNearPlane |= Verts[7].w <= 0.f;
|
||||
if (CutNearPlane)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IF (m_RotationSafe == 1, 0)
|
||||
{
|
||||
return Rasterize<1>(Verts, 8);
|
||||
}
|
||||
IF (m_RotationSafe == 2, 1)
|
||||
{
|
||||
return Rasterize<2>(Verts, 8);
|
||||
}
|
||||
return Rasterize<0>(Verts, 8);
|
||||
}
|
||||
|
||||
static int sh = 8;
|
||||
void CZBufferCuller::DrawDebug(int32 nStep)
|
||||
{ // project buffer to the screen
|
||||
nStep %= 32;
|
||||
if (!nStep)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const CCamera& rCam = GetCamera();
|
||||
float farPlane = rCam.GetFarPlane();
|
||||
float nearPlane = rCam.GetNearPlane();
|
||||
|
||||
float a = farPlane / (farPlane - nearPlane);
|
||||
float b = farPlane * nearPlane / (nearPlane - farPlane);
|
||||
|
||||
const float scale = 10.0f;
|
||||
|
||||
TransformationMatrices backupSceneMatrices;
|
||||
|
||||
m_pRenderer->Set2DMode(m_SizeX, m_SizeY, backupSceneMatrices);
|
||||
SAuxGeomRenderFlags Flags = e_Def3DPublicRenderflags;
|
||||
Flags.SetDepthWriteFlag(e_DepthWriteOff);
|
||||
Flags.SetAlphaBlendMode(e_AlphaBlended);
|
||||
m_pRenderer->GetIRenderAuxGeom()->SetRenderFlags(Flags);
|
||||
Vec3 vSize(.4f, .4f, .4f);
|
||||
if (nStep == 1)
|
||||
{
|
||||
vSize = Vec3(.5f, .5f, .5f);
|
||||
}
|
||||
for (uint32 y = 0; y < m_SizeY; y += nStep)
|
||||
{
|
||||
for (uint32 x = 0; x < m_SizeX; x += nStep)
|
||||
{
|
||||
Vec3 vPos((float)x, (float)(m_SizeY - y - 1), 0);
|
||||
vPos += Vec3(0.5f, -0.5f, 0);
|
||||
const uint32 Value = m_ZBuffer[x + y * m_SizeX];
|
||||
//Value>>=sh;
|
||||
|
||||
float w = Value / (65535.0f);
|
||||
|
||||
float z = b / (w - a);
|
||||
|
||||
uint32 ValueC = 255u - min(255u, (uint32)(z * scale));
|
||||
ColorB col;
|
||||
|
||||
col = ColorB(ValueC, ValueC, ValueC, 200);
|
||||
|
||||
|
||||
if (Value != 0xffff)
|
||||
{
|
||||
//ColorB col((Value&31)<<3,((Value>>5)&31)<<3,((Value>>10)&63)<<2,200);
|
||||
GetRenderer()->GetIRenderAuxGeom()->DrawAABB(AABB(vPos - vSize, vPos + vSize), nStep <= 2, col, eBBD_Faceted);
|
||||
}
|
||||
}
|
||||
}
|
||||
//m_pRenderer->GetIRenderAuxGeom()->Flush();
|
||||
m_pRenderer->Unset2DMode(backupSceneMatrices);
|
||||
}
|
||||
|
||||
void CZBufferCuller::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
SIZER_COMPONENT_NAME(pSizer, "CoverageBuffer");
|
||||
pSizer->AddObject(m_ZBuffer, sizeof(TZBZexel) * m_SizeX * m_SizeY);
|
||||
}
|
||||
@@ -1,273 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
// Description : Occlusion Culler using hardware generated ZBuffer
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_CRY3DENGINE_CZBUFFERCULLER_H
|
||||
#define CRYINCLUDE_CRY3DENGINE_CZBUFFERCULLER_H
|
||||
#pragma once
|
||||
|
||||
#include <Cry_Math.h>
|
||||
struct IRenderMesh;
|
||||
|
||||
typedef uint16 TZBZexel;
|
||||
const uint64 TZB_MAXDEPTH = (1 << (sizeof(TZBZexel) * 8)) - 1;
|
||||
|
||||
class CZBufferCuller
|
||||
: public Cry3DEngineBase
|
||||
{
|
||||
protected:
|
||||
bool m_DebugFreez;
|
||||
uint32 m_SizeX;
|
||||
uint32 m_SizeY;
|
||||
f32 m_fSizeX;
|
||||
f32 m_fSizeY;
|
||||
f32 m_fSizeZ;
|
||||
TZBZexel* m_ZBuffer;
|
||||
|
||||
Matrix44 m_MatProj;
|
||||
Matrix44 m_MatView;
|
||||
Matrix44 m_MatViewProj;
|
||||
Matrix44A m_MatViewProjT;
|
||||
Vec3 m_Position;
|
||||
|
||||
int32 m_Bias;
|
||||
uint32 m_RotationSafe;
|
||||
uint32 m_AccurateTest;
|
||||
uint32 m_Treshold;
|
||||
|
||||
f32 m_FixedZFar;
|
||||
uint32 m_ObjectsTested;
|
||||
uint32 m_ObjectsTestedAndRejected;
|
||||
CCamera m_Camera;
|
||||
int m_OutdoorVisible;
|
||||
|
||||
template<uint32 ROTATE, class T>
|
||||
bool Rasterize(const T rVertices, const uint32 VCount)
|
||||
{
|
||||
int64 MinX = m_SizeX;
|
||||
int64 MaxX = 0;
|
||||
int64 MinY = m_SizeY;
|
||||
int64 MaxY = 0;
|
||||
int64 MinZ = TZB_MAXDEPTH;
|
||||
for (uint32 a = 0; a < VCount; a++)
|
||||
{
|
||||
Vec4 V = rVertices[a];
|
||||
const f32 InvW = 1.f / V.w;
|
||||
int64 X = static_cast<int64>((V.x * InvW * 0.5f + 0.5f) * m_fSizeX + 0.5f);
|
||||
int64 Y = static_cast<int64>((V.y * InvW * 0.5f + 0.5f) * m_fSizeY + 0.5f);
|
||||
int64 Z = static_cast<int64>(V.z * InvW * m_fSizeZ);
|
||||
if (X < MinX)
|
||||
{
|
||||
MinX = X;
|
||||
}
|
||||
else
|
||||
if (X > MaxX)
|
||||
{
|
||||
MaxX = X;
|
||||
}
|
||||
if (Y < MinY)
|
||||
{
|
||||
MinY = Y;
|
||||
}
|
||||
else
|
||||
if (Y > MaxY)
|
||||
{
|
||||
MaxY = Y;
|
||||
}
|
||||
if (Z < MinZ)
|
||||
{
|
||||
MinZ = Z;
|
||||
}
|
||||
}
|
||||
if (MinX < 0)
|
||||
{
|
||||
if constexpr (ROTATE == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MinX = 0;
|
||||
}
|
||||
}
|
||||
if (MaxX > m_SizeX)
|
||||
{
|
||||
if constexpr (ROTATE == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxX = m_SizeX;
|
||||
}
|
||||
}
|
||||
if (MinY < 0)
|
||||
{
|
||||
if constexpr (ROTATE == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MinY = 0;
|
||||
}
|
||||
}
|
||||
if (MaxY > m_SizeY)
|
||||
{
|
||||
if constexpr (ROTATE == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxY = m_SizeY;
|
||||
}
|
||||
}
|
||||
if constexpr (ROTATE == 2)
|
||||
{
|
||||
if (MinX >= m_SizeX || MinY >= m_SizeY || MaxX < 0 || MaxX < 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int64 y = MinY; y < MaxY; y++)
|
||||
{
|
||||
for (int64 x = MinX; x < MaxX; x++)
|
||||
{
|
||||
if (static_cast<int64>(m_ZBuffer[static_cast<int32>(x) + static_cast<int32>(y) * m_SizeX]) > MinZ)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool IsBoxVisible_OCCLUDER(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_OCEAN(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_OCCELL(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_OCCELL_OCCLUDER(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_OBJECT(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_OBJECT_TO_LIGHT(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_TERRAIN_NODE(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible_PORTAL(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
bool IsBoxVisible(const AABB& objBox, uint32* const __restrict pResDest = NULL);
|
||||
|
||||
|
||||
public:
|
||||
CZBufferCuller();
|
||||
~CZBufferCuller(){CryModuleMemalignFree(m_ZBuffer); }
|
||||
|
||||
// start new frame
|
||||
void BeginFrame(const SRenderingPassInfo& passInfo);
|
||||
void ReloadBuffer(const uint32 BufferID);
|
||||
|
||||
// render into buffer
|
||||
ILINE void AddRenderMesh([[maybe_unused]] IRenderMesh* pRM, [[maybe_unused]] Matrix34A* pTranRotMatrix, _smart_ptr<IMaterial> pMaterial, [[maybe_unused]] bool bOutdoorOnly, [[maybe_unused]] bool bCompletelyInFrustum, [[maybe_unused]] bool bNoCull){}
|
||||
|
||||
|
||||
ILINE bool IsObjectVisible(const AABB& objBox, EOcclusionObjectType eOcclusionObjectType, [[maybe_unused]] float fDistance, uint32* pRetVal = NULL)
|
||||
{
|
||||
switch (eOcclusionObjectType)
|
||||
{
|
||||
case eoot_OCCLUDER:
|
||||
return IsBoxVisible_OCCLUDER(objBox, pRetVal);
|
||||
case eoot_OCEAN:
|
||||
return IsBoxVisible_OCEAN(objBox, pRetVal);
|
||||
case eoot_OCCELL:
|
||||
return IsBoxVisible_OCCELL(objBox, pRetVal);
|
||||
case eoot_OCCELL_OCCLUDER:
|
||||
return IsBoxVisible_OCCELL_OCCLUDER(objBox, pRetVal);
|
||||
case eoot_OBJECT:
|
||||
return IsBoxVisible_OBJECT(objBox, pRetVal);
|
||||
case eoot_OBJECT_TO_LIGHT:
|
||||
return IsBoxVisible_OBJECT_TO_LIGHT(objBox, pRetVal);
|
||||
case eoot_TERRAIN_NODE:
|
||||
return IsBoxVisible_TERRAIN_NODE(objBox, pRetVal);
|
||||
case eoot_PORTAL:
|
||||
return IsBoxVisible_PORTAL(objBox, pRetVal);
|
||||
}
|
||||
assert(!"Undefined occluder type");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// draw content to the screen for debug
|
||||
void DrawDebug(int32 nStep);
|
||||
|
||||
// return current camera
|
||||
const CCamera& GetCamera() const {return m_Camera; }
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
bool IsOutdooVisible(){return m_OutdoorVisible == 1; }
|
||||
int32 TrisWritten() const{return 0; }
|
||||
int32 ObjectsWritten() const{return 0; }
|
||||
int32 TrisTested() const{return 0; }
|
||||
int32 ObjectsTested() const{return m_ObjectsTested; }
|
||||
int32 ObjectsTestedAndRejected() const{return m_ObjectsTestedAndRejected; }
|
||||
int32 SelRes() const{return m_SizeX; }
|
||||
float FixedZFar() const{return m_FixedZFar; }
|
||||
float GetZNearInMeters() const{return 0.f; }
|
||||
float GetZFarInMeters() const{return 1024; }
|
||||
} _ALIGN(128);
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_TERRAIN_NODE(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_OCCELL_OCCLUDER(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_OCCLUDER(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_OCEAN(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_OCCELL(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
if (GetCVars()->e_CoverageBufferDebugFreeze)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_OBJECT(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_OBJECT_TO_LIGHT(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
ILINE bool CZBufferCuller::IsBoxVisible_PORTAL(const AABB& objBox, uint32* const __restrict pResDest)
|
||||
{
|
||||
return IsBoxVisible(objBox, pResDest);
|
||||
}
|
||||
|
||||
#endif // CRYINCLUDE_CRY3DENGINE_CZBUFFERCULLER_H
|
||||
@@ -1,113 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
|
||||
#include "ClipVolume.h"
|
||||
|
||||
CClipVolume::CClipVolume()
|
||||
: m_nStencilRef(0)
|
||||
, m_WorldTM(IDENTITY)
|
||||
, m_InverseWorldTM(IDENTITY)
|
||||
, m_BBoxWS(AABB::RESET)
|
||||
, m_BBoxLS(AABB::RESET)
|
||||
, m_pBspTree(NULL)
|
||||
{
|
||||
memset(m_sName, 0x0, sizeof(m_sName));
|
||||
}
|
||||
|
||||
CClipVolume::~CClipVolume()
|
||||
{
|
||||
m_pRenderMesh = NULL;
|
||||
|
||||
for (size_t i = 0; i < m_lstRenderNodes.size(); ++i)
|
||||
{
|
||||
if (m_lstRenderNodes[i]->m_pRNTmpData)
|
||||
{
|
||||
m_lstRenderNodes[i]->m_pRNTmpData->userData.m_pClipVolume = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CClipVolume::SetName(const char* szName)
|
||||
{
|
||||
cry_strcpy(m_sName, szName);
|
||||
}
|
||||
|
||||
void CClipVolume::GetClipVolumeMesh(_smart_ptr<IRenderMesh>& renderMesh, Matrix34& worldTM) const
|
||||
{
|
||||
renderMesh = m_pRenderMesh;
|
||||
worldTM = m_WorldTM;
|
||||
}
|
||||
|
||||
AABB CClipVolume::GetClipVolumeBBox() const
|
||||
{
|
||||
return m_BBoxWS;
|
||||
}
|
||||
|
||||
void CClipVolume::Update(_smart_ptr<IRenderMesh> pRenderMesh, IBSPTree3D* pBspTree, const Matrix34& worldTM, uint32 flags)
|
||||
{
|
||||
const bool bMeshUpdated = m_pRenderMesh != pRenderMesh;
|
||||
|
||||
m_pRenderMesh = pRenderMesh;
|
||||
m_pBspTree = pBspTree;
|
||||
m_WorldTM = worldTM;
|
||||
m_InverseWorldTM = worldTM.GetInverted();
|
||||
m_BBoxWS.Reset();
|
||||
m_BBoxLS.Reset();
|
||||
m_nFlags = flags;
|
||||
|
||||
if (m_pRenderMesh)
|
||||
{
|
||||
pRenderMesh->GetBBox(m_BBoxLS.min, m_BBoxLS.max);
|
||||
m_BBoxWS.SetTransformedAABB(worldTM, m_BBoxLS);
|
||||
}
|
||||
}
|
||||
|
||||
bool CClipVolume::IsPointInsideClipVolume(const Vec3& point) const
|
||||
{
|
||||
FUNCTION_PROFILER_3DENGINE;
|
||||
|
||||
if (!m_pRenderMesh || !m_pBspTree || !m_BBoxWS.IsContainPoint(point))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vec3 pt = m_InverseWorldTM.TransformPoint(point);
|
||||
return m_BBoxLS.IsContainPoint(pt) && m_pBspTree->IsInside(pt);
|
||||
}
|
||||
|
||||
void CClipVolume::RegisterRenderNode(IRenderNode* pRenderNode)
|
||||
{
|
||||
if (m_lstRenderNodes.Find(pRenderNode) < 0)
|
||||
{
|
||||
m_lstRenderNodes.Add(pRenderNode);
|
||||
|
||||
if (pRenderNode->m_pRNTmpData)
|
||||
{
|
||||
pRenderNode->m_pRNTmpData->userData.m_pClipVolume = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
void CClipVolume::UnregisterRenderNode(IRenderNode* pRenderNode)
|
||||
{
|
||||
if (m_lstRenderNodes.Delete(pRenderNode) && pRenderNode->m_pRNTmpData)
|
||||
{
|
||||
pRenderNode->m_pRNTmpData->userData.m_pClipVolume = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void CClipVolume::GetMemoryUsage(class ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(*this));
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef __INCLUDE_CRY3DENGINE_CLIPVOLUME_H
|
||||
#define __INCLUDE_CRY3DENGINE_CLIPVOLUME_H
|
||||
|
||||
struct IBSPTree3D;
|
||||
|
||||
class CClipVolume
|
||||
: public IClipVolume
|
||||
{
|
||||
public:
|
||||
CClipVolume();
|
||||
virtual ~CClipVolume();
|
||||
|
||||
////////////// IClipVolume implementation //////////////
|
||||
virtual void GetClipVolumeMesh(_smart_ptr<IRenderMesh>& renderMesh, Matrix34& worldTM) const;
|
||||
virtual AABB GetClipVolumeBBox() const;
|
||||
|
||||
virtual uint8 GetStencilRef() const { return m_nStencilRef; }
|
||||
virtual uint GetClipVolumeFlags() const { return m_nFlags; }
|
||||
virtual bool IsPointInsideClipVolume(const Vec3& vPos) const;
|
||||
////////////////////////////
|
||||
|
||||
void SetName(const char* szName);
|
||||
void SetStencilRef(int nStencilRef) { m_nStencilRef = nStencilRef; }
|
||||
|
||||
void Update(_smart_ptr<IRenderMesh> pRenderMesh, IBSPTree3D* pBspTree, const Matrix34& worldTM, uint32 flags);
|
||||
|
||||
void RegisterRenderNode(IRenderNode* pRenderNode);
|
||||
void UnregisterRenderNode(IRenderNode* pRenderNode);
|
||||
|
||||
void GetMemoryUsage(class ICrySizer* pSizer) const;
|
||||
|
||||
private:
|
||||
uint8 m_nStencilRef;
|
||||
uint32 m_nFlags;
|
||||
Matrix34 m_WorldTM;
|
||||
Matrix34 m_InverseWorldTM;
|
||||
AABB m_BBoxWS;
|
||||
AABB m_BBoxLS;
|
||||
|
||||
_smart_ptr<IRenderMesh> m_pRenderMesh;
|
||||
IBSPTree3D* m_pBspTree;
|
||||
|
||||
PodArray<IRenderNode*> m_lstRenderNodes;
|
||||
char m_sName[64];
|
||||
};
|
||||
|
||||
#endif //__INCLUDE_CRY3DENGINE_CLIPVOLUME_H
|
||||
@@ -1,176 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#include "Cry3DEngine_precompiled.h"
|
||||
|
||||
#include "ClipVolume.h"
|
||||
#include "ClipVolumeManager.h"
|
||||
#include "LightEntity.h"
|
||||
#include "FogVolumeRenderNode.h"
|
||||
#include "ObjMan.h"
|
||||
|
||||
CClipVolumeManager::~CClipVolumeManager()
|
||||
{
|
||||
assert(m_ClipVolumes.empty());
|
||||
}
|
||||
|
||||
IClipVolume* CClipVolumeManager::CreateClipVolume()
|
||||
{
|
||||
SClipVolumeInfo volumeInfo(new CClipVolume());
|
||||
m_ClipVolumes.push_back(volumeInfo);
|
||||
|
||||
return m_ClipVolumes.back().m_pVolume;
|
||||
}
|
||||
|
||||
bool CClipVolumeManager::DeleteClipVolume(IClipVolume* pClipVolume)
|
||||
{
|
||||
if (m_ClipVolumes.Delete(static_cast<CClipVolume*>(pClipVolume)))
|
||||
{
|
||||
delete pClipVolume;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CClipVolumeManager::UpdateClipVolume(IClipVolume* pClipVolume, _smart_ptr<IRenderMesh> pRenderMesh, IBSPTree3D* pBspTree, const Matrix34& worldTM, bool bActive, uint32 flags, const char* szName)
|
||||
{
|
||||
int nVolumeIndex = m_ClipVolumes.Find((CClipVolume*)pClipVolume);
|
||||
if (nVolumeIndex >= 0)
|
||||
{
|
||||
SClipVolumeInfo& volumeInfo = m_ClipVolumes[nVolumeIndex];
|
||||
volumeInfo.m_pVolume->Update(pRenderMesh, pBspTree, worldTM, flags);
|
||||
volumeInfo.m_pVolume->SetName(szName);
|
||||
volumeInfo.m_bActive = bActive;
|
||||
|
||||
AABB volumeBBox = pClipVolume->GetClipVolumeBBox();
|
||||
Get3DEngine()->GetObjManager()->ReregisterEntitiesInArea(volumeBBox.min, volumeBBox.max);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CClipVolumeManager::PrepareVolumesForRendering(const SRenderingPassInfo& passInfo)
|
||||
{
|
||||
for (size_t i = 0; i < m_ClipVolumes.size(); ++i)
|
||||
{
|
||||
SClipVolumeInfo& volInfo = m_ClipVolumes[i];
|
||||
volInfo.m_pVolume->SetStencilRef(InactiveVolumeStencilRef);
|
||||
|
||||
if (volInfo.m_bActive && passInfo.GetCamera().IsAABBVisible_F(volInfo.m_pVolume->GetClipVolumeBBox()))
|
||||
{
|
||||
uint8 nStencilRef = GetRenderer()->EF_AddDeferredClipVolume(volInfo.m_pVolume);
|
||||
volInfo.m_pVolume->SetStencilRef(nStencilRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CClipVolumeManager::UpdateEntityClipVolume(const Vec3& pos, IRenderNode* pRenderNode)
|
||||
{
|
||||
FRAME_PROFILER("CClipVolumeManager::UpdateEntityClipVolume", GetSystem(), PROFILE_3DENGINE);
|
||||
|
||||
if (!pRenderNode || !pRenderNode->m_pRNTmpData)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IClipVolume* pPreviousVolume = pRenderNode->m_pRNTmpData->userData.m_pClipVolume;
|
||||
UnregisterRenderNode(pRenderNode);
|
||||
|
||||
// user assigned clip volume
|
||||
CLightEntity* pLight = static_cast<CLightEntity*>(pRenderNode);
|
||||
if (pRenderNode->GetRenderNodeType() == eERType_Light && (pLight->m_light.m_Flags & DLF_HAS_CLIP_VOLUME) != 0)
|
||||
{
|
||||
for (int i = 1; i >= 0; --i)
|
||||
{
|
||||
if (CClipVolume* pVolume = static_cast<CClipVolume*>(pLight->m_light.m_pClipVolumes[i]))
|
||||
{
|
||||
pVolume->RegisterRenderNode(pRenderNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // assign by position
|
||||
{
|
||||
// Check if entity is in same clip volume as before
|
||||
if (pPreviousVolume && (pPreviousVolume->GetClipVolumeFlags() & IClipVolume::eClipVolumeIsVisArea) == 0)
|
||||
{
|
||||
CClipVolume* pVolume = static_cast<CClipVolume*>(pPreviousVolume);
|
||||
if (pVolume->IsPointInsideClipVolume(pos))
|
||||
{
|
||||
pVolume->RegisterRenderNode(pRenderNode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (CClipVolume* pVolume = GetClipVolumeByPos(pos, pPreviousVolume))
|
||||
{
|
||||
pVolume->RegisterRenderNode(pRenderNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CClipVolumeManager::UnregisterRenderNode(IRenderNode* pRenderNode)
|
||||
{
|
||||
if (!pRenderNode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_ClipVolumes.size(); ++i)
|
||||
{
|
||||
m_ClipVolumes[i].m_pVolume->UnregisterRenderNode(pRenderNode);
|
||||
}
|
||||
|
||||
if (pRenderNode->m_pRNTmpData)
|
||||
{
|
||||
pRenderNode->m_pRNTmpData->userData.m_pClipVolume = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CClipVolumeManager::IsClipVolumeRequired(IRenderNode* pRenderNode) const
|
||||
{
|
||||
const uint32 NoClipVolumeLights = DLF_SUN | DLF_ATTACH_TO_SUN;
|
||||
|
||||
const bool bForwardObject = (pRenderNode->m_nInternalFlags & IRenderNode::REQUIRES_FORWARD_RENDERING) != 0;
|
||||
const EERType ertype = pRenderNode->GetRenderNodeType();
|
||||
const bool bIsValidLight = ertype == eERType_Light &&
|
||||
(static_cast<CLightEntity*>(pRenderNode)->m_light.m_Flags & NoClipVolumeLights) == 0;
|
||||
const bool bIsValidFogVolume = (ertype == eERType_FogVolume) &&
|
||||
static_cast<CFogVolumeRenderNode*>(pRenderNode)->IsAffectsThisAreaOnly();
|
||||
|
||||
return bIsValidLight || bForwardObject || bIsValidFogVolume;
|
||||
}
|
||||
|
||||
CClipVolume* CClipVolumeManager::GetClipVolumeByPos(const Vec3& pos, const IClipVolume* pIgnoreVolume) const
|
||||
{
|
||||
for (size_t i = 0; i < m_ClipVolumes.size(); ++i)
|
||||
{
|
||||
const SClipVolumeInfo& volInfo = m_ClipVolumes[i];
|
||||
|
||||
if (volInfo.m_bActive && volInfo.m_pVolume != pIgnoreVolume && volInfo.m_pVolume->IsPointInsideClipVolume(pos))
|
||||
{
|
||||
return m_ClipVolumes[i].m_pVolume;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CClipVolumeManager::GetMemoryUsage(class ICrySizer* pSizer) const
|
||||
{
|
||||
pSizer->AddObject(this, sizeof(this));
|
||||
for (size_t i = 0; i < m_ClipVolumes.size(); ++i)
|
||||
{
|
||||
pSizer->AddObject(m_ClipVolumes[i].m_pVolume);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
||||
* its licensors.
|
||||
*
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this
|
||||
* distribution (the "License"). All use of this software is governed by the License,
|
||||
* or, if provided, by the license below or the license accompanying this file. Do not
|
||||
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
*/
|
||||
// Original file Copyright Crytek GMBH or its affiliates, used under license.
|
||||
|
||||
#ifndef __INCLUDE_CRY3DENGINE_CLIPVOLUMEMANAGER_H
|
||||
#define __INCLUDE_CRY3DENGINE_CLIPVOLUMEMANAGER_H
|
||||
|
||||
class CClipVolume;
|
||||
|
||||
class CClipVolumeManager
|
||||
: public Cry3DEngineBase
|
||||
{
|
||||
struct SClipVolumeInfo
|
||||
{
|
||||
CClipVolume* m_pVolume;
|
||||
bool m_bActive;
|
||||
|
||||
SClipVolumeInfo()
|
||||
: m_bActive(false) {}
|
||||
SClipVolumeInfo(CClipVolume* pVolume)
|
||||
: m_pVolume(pVolume)
|
||||
, m_bActive(false)
|
||||
{}
|
||||
|
||||
bool operator==(const SClipVolumeInfo& other) const { return m_pVolume == other.m_pVolume; }
|
||||
};
|
||||
|
||||
public:
|
||||
static const uint8 InactiveVolumeStencilRef = 0xFD;
|
||||
static const uint8 AffectsEverythingStencilRef = 0xFE;
|
||||
|
||||
virtual ~CClipVolumeManager();
|
||||
|
||||
virtual IClipVolume* CreateClipVolume();
|
||||
virtual bool DeleteClipVolume(IClipVolume* pClipVolume);
|
||||
virtual bool UpdateClipVolume(IClipVolume* pClipVolume, _smart_ptr<IRenderMesh> pRenderMesh, IBSPTree3D* pBspTree, const Matrix34& worldTM, bool bActive, uint32 flags, const char* szName);
|
||||
|
||||
void PrepareVolumesForRendering(const SRenderingPassInfo& passInfo);
|
||||
|
||||
void UpdateEntityClipVolume(const Vec3& pos, IRenderNode* pRenderNode);
|
||||
void UnregisterRenderNode(IRenderNode* pRenderNode);
|
||||
|
||||
bool IsClipVolumeRequired(IRenderNode* pRenderNode) const;
|
||||
CClipVolume* GetClipVolumeByPos(const Vec3& pos, const IClipVolume* pIgnoreVolume = NULL) const;
|
||||
|
||||
void GetMemoryUsage(class ICrySizer* pSizer) const;
|
||||
size_t GetClipVolumeCount() const { return m_ClipVolumes.size(); }
|
||||
|
||||
private:
|
||||
PodArray<SClipVolumeInfo> m_ClipVolumes;
|
||||
};
|
||||
|
||||
|
||||
#endif //__INCLUDE_CRY3DENGINE_CLIPVOLUMEMANAGER_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user