merging from main

This commit is contained in:
greerdv
2021-05-05 19:07:04 +01:00
2729 changed files with 34176 additions and 597749 deletions
-1
View File
@@ -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
)
+117 -51
View File
@@ -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)
@@ -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
@@ -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,
)
@@ -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}')
@@ -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 = [
@@ -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 = [
@@ -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 = [
@@ -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
@@ -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)
@@ -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
View File
@@ -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()
-3
View File
@@ -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);
}
}
-286
View File
@@ -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"
-23
View File
@@ -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;
}
-143
View File
@@ -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
-818
View File
@@ -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
-128
View File
@@ -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
-166
View File
@@ -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
-110
View File
@@ -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
)
-80
View File
@@ -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);
}
-273
View File
@@ -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
-113
View File
@@ -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));
}
-60
View File
@@ -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