merge from main

This commit is contained in:
pereslav
2021-05-05 00:09:25 +01:00
2235 changed files with 30410 additions and 560731 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
)
+16 -27
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
@@ -196,7 +187,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
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
TIMEOUT 1500
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
@@ -212,7 +203,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
@@ -228,7 +219,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
TEST_SUITE periodic
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "SUITE_periodic"
TIMEOUT 3600
TIMEOUT 1500
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
@@ -244,7 +235,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
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
TIMEOUT 1500
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
@@ -259,7 +250,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
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 +265,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 +283,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 +304,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,
)
@@ -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)
@@ -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
@@ -305,11 +269,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 +279,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 +328,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 +357,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 +378,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 +398,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 +445,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":
+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
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
@@ -1,280 +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 "CloudRenderNode.h"
#include "CloudsManager.h"
#include "VisAreas.h"
#include "ObjMan.h"
#include "Environment/OceanEnvironmentBus.h"
//////////////////////////////////////////////////////////////////////////
CCloudRenderNode::CCloudRenderNode()
{
m_bounds.min = Vec3(-1, -1, -1);
m_bounds.max = Vec3(1, 1, 1);
m_fScale = 1.0f;
m_offsetedMatrix.SetIdentity();
m_matrix.SetIdentity();
m_vOffset.Set(0, 0, 0);
m_alpha = 1.f;
m_pCloudRenderElement = (CREBaseCloud*)GetRenderer()->EF_CreateRE(eDATA_Cloud);
m_pREImposter = (CREImposter*) GetRenderer()->EF_CreateRE(eDATA_Imposter);
GetCloudsManager()->AddCloudRenderNode(this);
m_origin = Vec3(0, 0, 0);
m_moveProps.m_autoMove = false;
m_moveProps.m_speed = Vec3(0, 0, 0);
m_moveProps.m_spaceLoopBox = Vec3(2000.0f, 2000.0f, 2000.0f);
m_moveProps.m_fadeDistance = 0;
}
//////////////////////////////////////////////////////////////////////////
CCloudRenderNode::~CCloudRenderNode()
{
GetCloudsManager()->RemoveCloudRenderNode(this);
m_pCloudRenderElement->Release(false);
m_pREImposter->Release(false);
Get3DEngine()->FreeRenderNodeState(this);
}
//////////////////////////////////////////////////////////////////////////
bool CCloudRenderNode::LoadCloudFromXml(XmlNodeRef root)
{
m_pCloudDesc = new SCloudDescription;
GetCloudsManager()->ParseCloudFromXml(root, m_pCloudDesc);
SetCloudDesc(m_pCloudDesc);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CCloudRenderNode::LoadCloud(const char* sCloudFilename)
{
m_bounds.min = Vec3(-1, -1, -1);
m_bounds.max = Vec3(1, 1, 1);
SetCloudDesc(GetCloudsManager()->LoadCloud(sCloudFilename));
return m_pCloudDesc != 0;
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetMovementProperties(const SCloudMovementProperties& properties)
{
m_moveProps = properties;
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetCloudDesc(SCloudDescription* pCloud)
{
m_pCloudDesc = pCloud;
if (m_pCloudDesc != NULL && m_pCloudDesc->m_particles.size() > 0)
{
m_vOffset = m_pCloudDesc->m_offset;
m_bounds.min = m_pCloudDesc->m_bounds.min - m_pCloudDesc->m_offset;
m_bounds.max = m_pCloudDesc->m_bounds.max - m_pCloudDesc->m_offset;
if (m_pCloudDesc->m_pMaterial)
{
m_pMaterial = m_pCloudDesc->m_pMaterial;
}
m_pCloudRenderElement->SetParticles(&m_pCloudDesc->m_particles[0], m_pCloudDesc->m_particles.size());
m_WSBBox.SetTransformedAABB(m_matrix, m_bounds);
m_fScale = m_matrix.GetColumn(0).GetLength();
// Offset matrix by the cloud bounds offset.
m_offsetedMatrix = m_matrix * Matrix34::CreateTranslationMat(-m_vOffset);
}
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetMatrix(const Matrix34& mat)
{
SetMatrixInternal(mat, true);
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::SetMatrixInternal(const Matrix34& mat, bool updateOrigin)
{
m_dwRndFlags |= ERF_OUTDOORONLY;
if (updateOrigin)
{
m_origin = mat.GetTranslation();
}
m_matrix = mat;
m_pos = mat.GetTranslation();
// m_WSBBox.SetTransformedAABB( m_matrix,m_bounds );
m_fScale = mat.GetColumn(0).GetLength();
m_WSBBox.SetTransformedAABB(Matrix34::CreateTranslationMat(m_pos), AABB(m_bounds.min * m_fScale, m_bounds.max * m_fScale));
// Offset matrix by the cloud bounds offset.
// m_offsetedMatrix = m_matrix * Matrix34::CreateTranslationMat(-m_vOffset);
m_offsetedMatrix = Matrix34::CreateTranslationMat(m_pos - m_vOffset * m_fScale);
m_offsetedMatrix.ScaleColumn(Vec3(m_fScale, m_fScale, m_fScale));
Get3DEngine()->RegisterEntity(this);
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::MoveCloud()
{
FUNCTION_PROFILER_3DENGINE;
Vec3 pos(m_matrix.GetTranslation());
ITimer* pTimer(gEnv->pTimer);
if (m_moveProps.m_autoMove)
{
// update position
float deltaTime = pTimer->GetFrameTime();
assert(deltaTime >= 0);
pos += deltaTime * m_moveProps.m_speed;
// constrain movement to specified loop box
Vec3 loopBoxMin(m_origin - m_moveProps.m_spaceLoopBox);
Vec3 loopBoxMax(m_origin + m_moveProps.m_spaceLoopBox);
if (pos.x < loopBoxMin.x)
{
pos.x = loopBoxMax.x;
}
if (pos.y < loopBoxMin.y)
{
pos.y = loopBoxMax.y;
}
if (pos.z < loopBoxMin.z)
{
pos.z = loopBoxMax.z;
}
if (pos.x > loopBoxMax.x)
{
pos.x = loopBoxMin.x;
}
if (pos.y > loopBoxMax.y)
{
pos.y = loopBoxMin.y;
}
if (pos.z > loopBoxMax.z)
{
pos.z = loopBoxMin.z;
}
// set new position
Matrix34 mat(m_matrix);
mat.SetTranslation(pos);
SetMatrixInternal(mat, false);
// fade out clouds at the borders of the loop box
if (m_moveProps.m_fadeDistance > 0)
{
Vec3 fade(max(m_moveProps.m_spaceLoopBox.x, m_moveProps.m_fadeDistance),
max(m_moveProps.m_spaceLoopBox.y, m_moveProps.m_fadeDistance),
max(m_moveProps.m_spaceLoopBox.z, m_moveProps.m_fadeDistance));
fade -= Vec3(fabs(pos.x - m_origin.x), fabs(pos.y - m_origin.y), fabs(pos.z - m_origin.z));
m_alpha = clamp_tpl(min(min(fade.x, fade.y), fade.z) / m_moveProps.m_fadeDistance, 0.0f, 1.0f);
}
}
else
{
if ((m_origin - pos).GetLengthSquared() > 1e-4f)
{
Matrix34 mat(m_matrix);
mat.SetTranslation(m_origin);
SetMatrixInternal(mat, false);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CCloudRenderNode::Render(const SRendParams& rParams, const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE;
if (!m_pMaterial || !passInfo.RenderClouds())
{
return;
}
IRenderer* pRenderer(GetRenderer());
// get render objects
CRenderObject* pRO = pRenderer->EF_GetObject_Temp(passInfo.ThreadID());
if (!pRO)
{
return;
}
SShaderItem& shaderItem = (rParams.pMaterial) ? rParams.pMaterial->GetShaderItem(0) : m_pMaterial->GetShaderItem(0);
pRO->m_II.m_Matrix = m_offsetedMatrix;
SRenderObjData* pOD = pRenderer->EF_GetObjData(pRO, true, passInfo.ThreadID());
pOD->m_fTempVars[0] = m_fScale;
pRO->m_fSort = 0;
pRO->m_fDistance = rParams.fDistance;
int nAfterWater = GetObjManager()->IsAfterWater(m_offsetedMatrix.GetTranslation(), passInfo) ? 1 : 0;
pRO->m_II.m_AmbColor = rParams.AmbientColor;
pRO->m_fAlpha = rParams.fAlpha * m_alpha;
float mvd(GetMaxViewDist());
float d((passInfo.GetCamera().GetPosition() - m_offsetedMatrix.GetTranslation()).GetLength());
if (d > 0.9f * mvd)
{
float s(clamp_tpl(1.0f - (d - 0.9f * mvd) / (0.1f * mvd), 0.0f, 1.0f));
pRO->m_fAlpha *= s;
}
pRenderer->EF_AddEf(m_pCloudRenderElement, shaderItem, pRO, passInfo, EFSLIST_TRANSP, nAfterWater, SRendItemSorter(rParams.rendItemSorter));
}
//////////////////////////////////////////////////////////////////////////
bool CCloudRenderNode::CheckIntersection(const Vec3& p1, const Vec3& p2)
{
if (p1 == p2)
{
return false;
}
if (m_pCloudDesc && m_pCloudDesc->m_pCloudTree)
{
Vec3 outp;
if (Intersect::Lineseg_AABB(Lineseg(p1, p2), m_WSBBox, outp))
{
Matrix34 pInv = m_offsetedMatrix.GetInverted();
return m_pCloudDesc->m_pCloudTree->CheckIntersection(pInv * p1, pInv * p2);
}
}
return false;
}
void CCloudRenderNode::OffsetPosition(const Vec3& delta)
{
if (m_pRNTmpData)
{
m_pRNTmpData->OffsetPosition(delta);
}
m_pos += delta;
m_origin += delta;
m_matrix.SetTranslation(m_matrix.GetTranslation() + delta);
m_offsetedMatrix.SetTranslation(m_offsetedMatrix.GetTranslation() + delta);
m_WSBBox.Move(delta);
}
@@ -1,91 +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_CLOUDRENDERNODE_H
#define CRYINCLUDE_CRY3DENGINE_CLOUDRENDERNODE_H
#pragma once
struct SCloudDescription;
//////////////////////////////////////////////////////////////////////////
// RenderNode for rendering single cloud object.
//////////////////////////////////////////////////////////////////////////
class CCloudRenderNode
: public ICloudRenderNode
, public Cry3DEngineBase
{
public:
CCloudRenderNode();
//////////////////////////////////////////////////////////////////////////
// Implements ICloudRenderNode
//////////////////////////////////////////////////////////////////////////
virtual bool LoadCloud(const char* sCloudFilename);
virtual bool LoadCloudFromXml(XmlNodeRef cloudNode);
virtual void SetMovementProperties(const SCloudMovementProperties& properties);
//////////////////////////////////////////////////////////////////////////
// Implements IRenderNode
//////////////////////////////////////////////////////////////////////////
virtual void GetLocalBounds(AABB& bbox) { bbox = m_bounds; };
virtual void SetMatrix(const Matrix34& mat);
virtual EERType GetRenderNodeType();
virtual const char* GetEntityClassName() const { return "Cloud"; }
virtual const char* GetName() const { return "Cloud"; }
virtual Vec3 GetPos(bool bWorldOnly = true) const;
virtual void Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo);
void SetMaterial(_smart_ptr<IMaterial> pMat) override { m_pMaterial = pMat; }
virtual _smart_ptr<IMaterial> GetMaterial(Vec3* pHitPos = NULL);
virtual _smart_ptr<IMaterial> GetMaterialOverride() { return m_pMaterial; }
virtual float GetMaxViewDist();
virtual const AABB GetBBox() const { return m_WSBBox; }
virtual void SetBBox(const AABB& WSBBox) { m_WSBBox = WSBBox; }
virtual void FillBBox(AABB& aabb);
virtual void OffsetPosition(const Vec3& delta);
//////////////////////////////////////////////////////////////////////////
bool CheckIntersection(const Vec3& p1, const Vec3& p2);
void MoveCloud();
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
private:
void SetCloudDesc(SCloudDescription* pCloud);
~CCloudRenderNode();
virtual void SetMatrixInternal(const Matrix34& mat, bool updateOrigin);
private:
Vec3 m_pos;
float m_fScale;
_smart_ptr<IMaterial> m_pMaterial;
_smart_ptr<SCloudDescription> m_pCloudDesc;
Matrix34 m_matrix;
Matrix34 m_offsetedMatrix;
Vec3 m_vOffset;
AABB m_bounds;
CREBaseCloud* m_pCloudRenderElement;
CREImposter* m_pREImposter;
float m_alpha;
Vec3 m_origin;
SCloudMovementProperties m_moveProps;
AABB m_WSBBox;
};
#endif // CRYINCLUDE_CRY3DENGINE_CLOUDRENDERNODE_H
@@ -1,335 +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 "CloudRenderNode.h"
#include "CloudsManager.h"
#include <CryPath.h>
#include "MatMan.h"
//////////////////////////////////////////////////////////////////////////
SCloudDescription::~SCloudDescription()
{
delete m_pCloudTree;
m_pCloudTree = 0;
// Unregister itself from clouds manager.
if (!filename.empty())
{
Get3DEngine()->GetCloudsManager()->Unregister(this);
}
}
//////////////////////////////////////////////////////////////////////////
SCloudDescription* CCloudsManager::LoadCloud(const char* sFilename)
{
string filename = PathUtil::ToUnixPath(sFilename);
SCloudDescription* pCloud = stl::find_in_map(m_cloudsMap, filename, NULL);
if (!pCloud)
{
XmlNodeRef root = GetISystem()->LoadXmlFromFile(filename);
if (root)
{
pCloud = new SCloudDescription;
pCloud->filename = filename;
ParseCloudFromXml(root, pCloud);
CloudParticles particles;
particles.resize(pCloud->m_particles.size());
for (uint32 i = 0; i < particles.size(); i++)
{
particles[i] = &pCloud->m_particles[i];
}
pCloud->m_pCloudTree = new SCloudQuadTree();
pCloud->m_pCloudTree->Init(pCloud->m_bounds, particles);
Register(pCloud);
}
}
return pCloud;
}
//////////////////////////////////////////////////////////////////////////
void CCloudsManager::ParseCloudFromXml(XmlNodeRef root, SCloudDescription* pCloud)
{
assert(pCloud);
pCloud->m_bounds.min = Vec3(0, 0, 0);
pCloud->m_bounds.max = Vec3(0, 0, 0);
pCloud->m_pMaterial = 0;
const char* sMtlName = root->getAttr("Material");
if (sMtlName && sMtlName[0] != '\0')
{
pCloud->m_pMaterial = GetMatMan()->LoadMaterial(sMtlName);
if (!pCloud->m_pMaterial)
{
CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR, "Error: Failed to load cloud material" /*,sMtlName*/);
}
}
int numRows = 1;
int numCols = 1;
root->getAttr("TextureNumRows", numRows);
root->getAttr("TextureNumCols", numCols);
if (numRows < 1)
{
numRows = 1;
}
if (numCols < 1)
{
numCols = 1;
}
pCloud->m_textureRows = numRows;
pCloud->m_textureCols = numCols;
pCloud->m_numSprites = root->getChildCount();
pCloud->m_particles.reserve(pCloud->m_numSprites);
pCloud->m_particles.clear();
float xTextureStep = 1.0f / numCols;
float yTextureStep = 1.0f / numRows;
Vec3 pos(0, 0, 0);
int texID = 0;
float angle = 0;
float radius = 0;
Vec2 uv[2];
if (pCloud->m_numSprites > 0)
{
pCloud->m_bounds.Reset();
}
for (int i = 0; i < root->getChildCount(); i++)
{
XmlNodeRef child = root->getChild(i);
child->getAttr("Pos", pos);
child->getAttr("texID", texID);
child->getAttr("Radius", radius);
if (!child->getAttr("Angle", angle))
{
angle = 0;
}
int x = texID % numCols;
int y = texID / numCols;
uv[0].x = x * xTextureStep;
uv[0].y = y * yTextureStep;
uv[1].x = (x + 1) * xTextureStep;
uv[1].y = (y + 1) * yTextureStep;
SCloudParticle sprite(pos, radius, radius, 0, 0, uv);
pCloud->m_particles.push_back(sprite);
pCloud->m_bounds.Add(pos - Vec3(radius, radius, radius));
pCloud->m_bounds.Add(pos + Vec3(radius, radius, radius));
}
// Offset particles so that bounding box is centered at origin.
pCloud->m_offset = -pCloud->m_bounds.GetCenter();
pCloud->m_bounds.min += pCloud->m_offset;
pCloud->m_bounds.max += pCloud->m_offset;
for (uint32 i = 0; i < pCloud->m_particles.size(); i++)
{
pCloud->m_particles[i].SetPosition(pCloud->m_particles[i].GetPosition() + pCloud->m_offset);
}
}
//////////////////////////////////////////////////////////////////////////
void CCloudsManager::Register(SCloudDescription* desc)
{
assert(desc);
m_cloudsMap[desc->filename] = desc;
}
//////////////////////////////////////////////////////////////////////////
void CCloudsManager::Unregister(SCloudDescription* desc)
{
assert(desc);
m_cloudsMap.erase(desc->filename);
}
//////////////////////////////////////////////////////////////////////////
void CCloudsManager::AddCloudRenderNode(CCloudRenderNode* pNode)
{
m_cloudNodes.push_back(pNode);
}
//////////////////////////////////////////////////////////////////////////
void CCloudsManager::RemoveCloudRenderNode(CCloudRenderNode* pNode)
{
int size = m_cloudNodes.size();
for (int i = 0; i < size; i++)
{
if (m_cloudNodes[i] == pNode)
{
if (i < size - 1)
{
m_cloudNodes[i] = m_cloudNodes[size - 1];
}
m_cloudNodes.resize(size - 1);
break;
}
}
}
//!!! WARNING
//bool Sp_IsDraw = false;
//Matrix34 Sp_Mat;
//Vec3 Sp_Pos;
//float Sp_Rad;
//////////////////////////////////////////////////////////////////////////
bool CCloudsManager::CheckIntersectClouds(const Vec3& p1, const Vec3& p2)
{
for (std::vector<CCloudRenderNode*>::iterator it = m_cloudNodes.begin(); it != m_cloudNodes.end(); ++it)
{
//Sp_IsDraw = false;
if ((*it)->CheckIntersection(p1, p2))
{
//Sp_Mat = (*it)->m_offsetedMatrix;
//Sp_IsDraw = true;
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void CCloudsManager::MoveClouds()
{
FUNCTION_PROFILER_3DENGINE;
std::vector<CCloudRenderNode*>::iterator it(m_cloudNodes.begin());
std::vector<CCloudRenderNode*>::iterator itEnd(m_cloudNodes.end());
for (; it != itEnd; ++it)
{
(*it)->MoveCloud();
}
}
//////////////////////////////////////////////////////////////////////////
void SCloudQuadTree::Init(const AABB& bounds, const CloudParticles& particles, int maxlevel)
{
m_bounds = bounds;
if (m_level >= maxlevel)
{
m_particles.resize(particles.size());
memcpy(&m_particles[0], &particles[0], particles.size() * sizeof(SCloudParticle*));
return;
}
CloudParticles parts;
for (int k = 0; k < 4; k++)
{
AABB bnds;
parts.resize(0);
Vec3 centr = (bounds.min + bounds.max) / 2;
if (k == 0)
{
bnds = AABB(bounds.min, Vec3(centr.x, centr.y, bounds.max.z));
}
else if (k == 1)
{
bnds = AABB(Vec3(bounds.min.x, centr.y, bounds.min.z), Vec3(centr.x, bounds.max.y, bounds.max.z));
}
else if (k == 2)
{
bnds = AABB(Vec3(centr.x, bounds.min.y, bounds.min.z), Vec3(bounds.max.x, centr.y, bounds.max.z));
}
else if (k == 3)
{
bnds = AABB(Vec3(centr.x, centr.y, bounds.min.z), bounds.max);
}
for (uint32 i = 0; i < particles.size(); i++)
{
SCloudParticle* pPtcl = particles[i];
if (bnds.IsOverlapSphereBounds(pPtcl->GetPosition(), pPtcl->GetRadiusX()) ||
bnds.IsContainSphere(pPtcl->GetPosition(), pPtcl->GetRadiusX()))
{
parts.push_back(pPtcl);
}
}
if (!parts.empty())
{
m_pQuads[k] = new SCloudQuadTree(m_level + 1);
m_pQuads[k]->Init(bnds, parts, maxlevel);
}
}
}
//////////////////////////////////////////////////////////////////////////
bool SCloudQuadTree::CheckIntersection(const Vec3& p1, const Vec3& p2)
{
Vec3 outp, outp2;
if (Intersect::Lineseg_AABB(Lineseg(p1, p2), m_bounds, outp))
{
if (m_pQuads[0] && m_pQuads[0]->CheckIntersection(p1, p2))
{
return true;
}
if (m_pQuads[1] && m_pQuads[1]->CheckIntersection(p1, p2))
{
return true;
}
if (m_pQuads[2] && m_pQuads[2]->CheckIntersection(p1, p2))
{
return true;
}
if (m_pQuads[3] && m_pQuads[3]->CheckIntersection(p1, p2))
{
return true;
}
if (!m_particles.empty())
{
for (uint32 i = 0; i < m_particles.size(); i++)
{
//if(Intersect::Lineseg_Sphere(Lineseg(p1, p2), Sphere (m_particles[i]->GetPosition(), m_particles[i]->GetRadiusX()*(2.0f/3)), outp, outp2))
if (Intersect::Lineseg_Sphere(Lineseg(p1, p2), Sphere (m_particles[i]->GetPosition(), m_particles[i]->GetRadiusX()), outp, outp2))
{
//Sp_Pos = m_particles[i]->GetPosition();
//Sp_Rad = m_particles[i]->GetRadiusX()/2;
return true;
}
}
}
}
return false;
}
/*
//!!! WARNING
extern bool Sp_IsDraw;
extern Matrix34 Sp_Mat;
extern Vec3 Sp_Pos;
extern float Sp_Rad;
void C3DEngine::Hack_GetSprite(bool & IsDraw, Matrix34 & Mat, Vec3 & Pos, float & Rad)
{
IsDraw = Sp_IsDraw;
Mat = Sp_Mat;
Pos = Sp_Pos;
Rad = Sp_Rad;
}
*/
-116
View File
@@ -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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRY3DENGINE_CLOUDSMANAGER_H
#define CRYINCLUDE_CRY3DENGINE_CLOUDSMANAGER_H
#pragma once
class CCloudRenderNode;
typedef std::vector<SCloudParticle*> CloudParticles;
struct SCloudQuadTree
{
CloudParticles m_particles;
AABB m_bounds;
SCloudQuadTree* m_pQuads[4];
int m_level;
SCloudQuadTree(int level = 0)
{
m_pQuads[0] = 0;
m_pQuads[1] = 0;
m_pQuads[2] = 0;
m_pQuads[3] = 0;
m_level = level;
}
~SCloudQuadTree()
{
delete m_pQuads[0];
delete m_pQuads[1];
delete m_pQuads[2];
delete m_pQuads[3];
m_pQuads[0] = m_pQuads[1] = m_pQuads[2] = m_pQuads[3] = 0;
}
void Init(const AABB& bounds, const CloudParticles& particles, int maxlevel = 2);
bool CheckIntersection(const Vec3& p1, const Vec3& p2);
};
//////////////////////////////////////////////////////////////////////////
// SCloudDescription contains cached representation of the cloud description file.
//////////////////////////////////////////////////////////////////////////
struct SCloudDescription
: public _reference_target_t
, public Cry3DEngineBase
{
string filename;
int m_textureRows;
int m_textureCols;
int m_numSprites;
AABB m_bounds;
Vec3 m_offset;
_smart_ptr<IMaterial> m_pMaterial;
std::vector<SCloudParticle> m_particles;
SCloudQuadTree* m_pCloudTree;
SCloudDescription()
{
m_textureRows = 0;
m_textureCols = 0;
m_numSprites = 0;
m_pCloudTree = 0;
};
~SCloudDescription();
};
//////////////////////////////////////////////////////////////////////////
// CloudsManager is used to manage cloud descriptions loaded from the files.
// When cloud file is once loaded it caches its content and next time the same
// cloud file is request, Clients will get the cached content.
//////////////////////////////////////////////////////////////////////////
class CCloudsManager
: public Cry3DEngineBase
{
public:
CCloudsManager() {};
~CCloudsManager() {};
// Loads cloud file and returns cloud description.
// If cloud was already loaded cached instance is returned.
// Reference count of the cloud description is incremented,Client must call Release on returned pointer to free cloud description.
SCloudDescription* LoadCloud(const char* sFilename);
// Used to parse xml node and create a cloud description from it.
void ParseCloudFromXml(XmlNodeRef node, SCloudDescription* pCloud);
void AddCloudRenderNode(CCloudRenderNode* pNode);
void RemoveCloudRenderNode(CCloudRenderNode* pNode);
bool CheckIntersectClouds(const Vec3& p1, const Vec3& p2);
void MoveClouds();
private:
friend struct SCloudDescription;
void Register(SCloudDescription* desc);
void Unregister(SCloudDescription* desc);
private:
typedef std::map<string, SCloudDescription*, stl::less_stricmp<string> > CloudsMaps;
CloudsMaps m_cloudsMap;
std::vector<CCloudRenderNode*> m_cloudNodes;
};
#endif // CRYINCLUDE_CRY3DENGINE_CLOUDSMANAGER_H
-176
View File
@@ -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.
// Description : Defines the DLL entry point, implements access to other modules
#include "Cry3DEngine_precompiled.h"
#include "MatMan.h"
#include <IEngineModule.h>
#include <CryExtension/Impl/ClassWeaver.h>
#include "I3DEngine_info.h"
//////////////////////////////////////////////////////////////////////
struct CSystemEventListner_3DEngine
: public ISystemEventListener
{
public:
virtual void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
{
switch (event)
{
case ESYSTEM_EVENT_LEVEL_PRECACHE_START:
if (Cry3DEngineBase::Get3DEngine())
{
Cry3DEngineBase::Get3DEngine()->ClearPrecacheInfo();
}
break;
case ESYSTEM_EVENT_RANDOM_SEED:
cry_random_seed(gEnv->bNoRandomSeed ? 0 : (uint32)wparam);
break;
case ESYSTEM_EVENT_LEVEL_POST_UNLOAD:
{
STLALLOCATOR_CLEANUP;
if (Cry3DEngineBase::Get3DEngine())
{
Cry3DEngineBase::Get3DEngine()->ClearDebugFPSInfo(true);
}
break;
}
case ESYSTEM_EVENT_LEVEL_LOAD_END:
{
if (Cry3DEngineBase::Get3DEngine())
{
Cry3DEngineBase::Get3DEngine()->ClearDebugFPSInfo();
}
if (Cry3DEngineBase::GetObjManager())
{
Cry3DEngineBase::GetObjManager()->FreeNotUsedCGFs();
}
Cry3DEngineBase::m_bLevelLoadingInProgress = false;
break;
}
case ESYSTEM_EVENT_LEVEL_LOAD_START:
{
Cry3DEngineBase::m_bLevelLoadingInProgress = true;
break;
}
case ESYSTEM_EVENT_LEVEL_UNLOAD:
{
Cry3DEngineBase::m_bLevelLoadingInProgress = true;
break;
}
case ESYSTEM_EVENT_3D_POST_RENDERING_START:
{
Cry3DEngineBase::GetMatMan()->DoLoadSurfaceTypesInInit(false);
break;
}
case ESYSTEM_EVENT_3D_POST_RENDERING_END:
{
if (Cry3DEngineBase::Get3DEngine()->GetObjectTree())
{
delete Cry3DEngineBase::Get3DEngine()->GetObjectTree();
Cry3DEngineBase::Get3DEngine()->SetObjectTree(nullptr);
}
if (IObjManager* pObjManager = Cry3DEngineBase::GetObjManager())
{
pObjManager->UnloadObjects(true);
}
if (Cry3DEngineBase::GetMatMan())
{
Cry3DEngineBase::GetMatMan()->ShutDown();
Cry3DEngineBase::GetMatMan()->DoLoadSurfaceTypesInInit(true);
}
break;
}
}
}
};
static CSystemEventListner_3DEngine g_system_event_listener_engine;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class CEngineModule_Cry3DEngine
: public IEngineModule
{
CRYINTERFACE_SIMPLE(IEngineModule)
CRYGENERATE_SINGLETONCLASS(CEngineModule_Cry3DEngine, "EngineModule_Cry3DEngine", 0x2d38f12a521d43cf, 0xba18fd1fa7ea5020)
//////////////////////////////////////////////////////////////////////////
virtual const char* GetName() const {
return "Cry3DEngine";
};
virtual const char* GetCategory() const { return "CryEngine"; };
//////////////////////////////////////////////////////////////////////////
virtual bool Initialize(SSystemGlobalEnvironment& env, [[maybe_unused]] const SSystemInitParams& initParams)
{
ISystem* pSystem = env.pSystem;
ModuleInitISystem(pSystem, "Cry3DEngine");
pSystem->GetISystemEventDispatcher()->RegisterListener(&g_system_event_listener_engine);
C3DEngine* p3DEngine = CryAlignedNew<C3DEngine>(pSystem);
env.p3DEngine = p3DEngine;
return true;
}
};
CRYREGISTER_SINGLETON_CLASS(CEngineModule_Cry3DEngine)
CEngineModule_Cry3DEngine::CEngineModule_Cry3DEngine()
{
};
CEngineModule_Cry3DEngine::~CEngineModule_Cry3DEngine()
{
};
#if !defined(AZ_MONOLITHIC_BUILD)
#include <CrtDebugStats.h>
#endif
#include "TypeInfo_impl.h"
// 3DEngine types
#include "SkyLightNishita_info.h"
STRUCT_INFO_BEGIN(SImageSubInfo)
VAR_INFO(nDummy)
VAR_INFO(nDim)
VAR_INFO(fTilingIn)
VAR_INFO(fTiling)
VAR_INFO(fSpecularAmount)
VAR_INFO(nSortOrder)
STRUCT_INFO_END(SImageSubInfo)
STRUCT_INFO_BEGIN(SImageInfo)
VAR_INFO(baseInfo)
VAR_INFO(detailInfo)
VAR_INFO(szDetMatName)
VAR_INFO(arrTextureId)
VAR_INFO(nPhysSurfaceType)
VAR_INFO(szBaseTexName)
VAR_INFO(fUseRemeshing)
VAR_INFO(layerFilterColor)
VAR_INFO(nLayerId)
VAR_INFO(fBr)
STRUCT_INFO_END(SImageInfo)
-111
View File
@@ -1,111 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Russian resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
#ifdef _WIN32
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Russian resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// German (Germany) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
#ifdef _WIN32
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000904b0"
BEGIN
VALUE "CompanyName", "Amazon.com, Inc."
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "LegalCopyright", "Portions of this file Copyright (c) Amazon.com, Inc. or its affiliates. All Rights Reserved. Original file Copyright (c) Crytek GMBH. Used under license by Amazon.com, Inc. and its affiliates."
VALUE "ProductName", "Lumberyard"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x9, 1200
END
END
#endif // German (Germany) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
@@ -1,237 +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 <Cry3DEngineBase.h>
#define MAX_ERROR_STRING MAX_WARNING_LENGTH
//////////////////////////////////////////////////////////////////////////
void Cry3DEngineBase::PrintComment(const char* szText, ...)
{
if (!szText)
{
return;
}
va_list args;
va_start(args, szText);
GetLog()->LogV(IMiniLog::eComment, szText, args);
va_end(args);
}
void Cry3DEngineBase::PrintMessage(const char* szText, ...)
{
if (!szText)
{
return;
}
va_list args;
va_start(args, szText);
GetLog()->LogV(GetCVars()->e_3dEngineLogAlways ? IMiniLog::eAlways : IMiniLog::eMessage, szText, args);
va_end(args);
GetLog()->UpdateLoadingScreen(0);
}
void Cry3DEngineBase::PrintMessagePlus(const char* szText, ...)
{
if (!szText)
{
return;
}
va_list arglist;
char buf[MAX_ERROR_STRING];
va_start(arglist, szText);
int count = azvsnprintf(buf, sizeof(buf), szText, arglist);
if (count == -1 || count >= sizeof(buf))
{
buf[sizeof(buf) - 1] = '\0';
}
va_end(arglist);
GetLog()->LogPlus(buf);
GetLog()->UpdateLoadingScreen(0);
}
float Cry3DEngineBase::GetCurTimeSec()
{
return (gEnv->pTimer->GetCurrTime());
}
float Cry3DEngineBase::GetCurAsyncTimeSec()
{
return (gEnv->pTimer->GetAsyncTime().GetSeconds());
}
//////////////////////////////////////////////////////////////////////////
void Cry3DEngineBase::Warning(const char* format, ...)
{
if (!format)
{
return;
}
va_list args;
va_start(args, format);
// Call to validating warning of system.
m_pSystem->WarningV(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, 0, 0, format, args);
va_end(args);
GetLog()->UpdateLoadingScreen(0);
}
//////////////////////////////////////////////////////////////////////////
void Cry3DEngineBase::Error(const char* format, ...)
{
// assert(!"Cry3DEngineBase::Error");
if (format)
{
va_list args;
va_start(args, format);
// Call to validating warning of system.
m_pSystem->WarningV(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR, 0, 0, format, args);
va_end(args);
}
GetLog()->UpdateLoadingScreen(0);
}
//////////////////////////////////////////////////////////////////////////
void Cry3DEngineBase::FileWarning(int flags, const char* file, const char* format, ...)
{
if (format)
{
va_list args;
va_start(args, format);
// Call to validating warning of system.
m_pSystem->WarningV(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, flags | VALIDATOR_FLAG_FILE, file, format, args);
va_end(args);
}
GetLog()->UpdateLoadingScreen(0);
}
_smart_ptr<IMaterial> Cry3DEngineBase::MakeSystemMaterialFromShader(const char* sShaderName, SInputShaderResources* Res)
{
_smart_ptr<IMaterial> pMat = Get3DEngine()->GetMaterialManager()->CreateMaterial(sShaderName);
//pMat->AddRef();
SShaderItem si;
si = GetRenderer()->EF_LoadShaderItem(sShaderName, true, 0, Res);
pMat->AssignShaderItem(si);
return pMat;
}
//////////////////////////////////////////////////////////////////////////
bool Cry3DEngineBase::IsValidFile(const char* sFilename)
{
LOADING_TIME_PROFILE_SECTION;
return gEnv->pCryPak->IsFileExist(sFilename);
}
//////////////////////////////////////////////////////////////////////////
bool Cry3DEngineBase::IsResourceLocked(const char* sFilename)
{
auto pResList = GetPak()->GetResourceList(AZ::IO::IArchive::RFOM_NextLevel);
if (pResList)
{
return pResList->IsExist(sFilename);
}
return false;
}
void Cry3DEngineBase::DrawBBoxLabeled(const AABB& aabb, const Matrix34& m34, const ColorB& col, const char* format, ...)
{
va_list args;
va_start(args, format);
char szText[256];
vsnprintf_s(szText, sizeof(szText), sizeof(szText) - 1, format, args);
float fColor[4] = { col[0] / 255.f, col[1] / 255.f, col[2] / 255.f, col[3] / 255.f };
GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(SAuxGeomRenderFlags());
GetRenderer()->DrawLabelEx(m34.TransformPoint(aabb.GetCenter()), 1.3f, fColor, true, true, szText);
GetRenderer()->GetIRenderAuxGeom()->DrawAABB(aabb, m34, false, col, eBBD_Faceted);
va_end(args);
}
//////////////////////////////////////////////////////////////////////////
void Cry3DEngineBase::DrawBBox(const Vec3& vMin, const Vec3& vMax, ColorB col)
{
GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(SAuxGeomRenderFlags());
GetRenderer()->GetIRenderAuxGeom()->DrawAABB(AABB(vMin, vMax), false, col, eBBD_Faceted);
}
void Cry3DEngineBase::DrawBBox(const AABB& box, ColorB col)
{
GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(SAuxGeomRenderFlags());
GetRenderer()->GetIRenderAuxGeom()->DrawAABB(box, false, col, eBBD_Faceted);
}
void Cry3DEngineBase::DrawLine(const Vec3& vMin, const Vec3& vMax, ColorB col)
{
GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(SAuxGeomRenderFlags());
GetRenderer()->GetIRenderAuxGeom()->DrawLine(vMin, col, vMax, col);
}
void Cry3DEngineBase::DrawSphere(const Vec3& vPos, float fRadius, ColorB color)
{
GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(SAuxGeomRenderFlags());
GetRenderer()->GetIRenderAuxGeom()->DrawSphere(vPos, fRadius, color);
}
void Cry3DEngineBase::DrawQuad(const Vec3& v0, const Vec3& v1, const Vec3& v2, const Vec3& v3, ColorB color)
{
GetRenderer()->GetIRenderAuxGeom()->SetRenderFlags(SAuxGeomRenderFlags());
GetRenderer()->GetIRenderAuxGeom()->DrawTriangle(v0, color, v2, color, v3, color);
GetRenderer()->GetIRenderAuxGeom()->DrawTriangle(v0, color, v1, color, v2, color);
}
// Check if preloading is enabled.
bool Cry3DEngineBase::IsPreloadEnabled()
{
bool bPreload = false;
ICVar* pSysPreload = GetConsole()->GetCVar("sys_preload");
if (pSysPreload && pSysPreload->GetIVal() != 0)
{
bPreload = true;
}
return bPreload;
}
//////////////////////////////////////////////////////////////////////////
bool Cry3DEngineBase::CheckMinSpec(uint32 nMinSpec)
{
if ((int)nMinSpec != 0 && GetCVars()->e_ObjQuality != 0 && (int)nMinSpec > GetCVars()->e_ObjQuality)
{
return false;
}
return true;
}
bool Cry3DEngineBase::IsEscapePressed()
{
#ifdef WIN32
if (Cry3DEngineBase::m_bEditor && (CryGetAsyncKeyState(0x03) & 1)) // Ctrl+Break
{
Get3DEngine()->PrintMessage("*** Ctrl-Break was pressed - operation aborted ***");
return true;
}
#endif
return false;
}
@@ -1,202 +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 : Access to external stuff used by 3d engine. Most 3d engine classes
// are derived from this base class to access other interfaces
#ifndef CRYINCLUDE_CRY3DENGINE_CRY3DENGINEBASE_H
#define CRYINCLUDE_CRY3DENGINE_CRY3DENGINEBASE_H
#pragma once
#include "3DEngineMemory.h"
struct ISystem;
struct IRenderer;
struct ILog;
struct ITimer;
struct IConsole;
struct I3DEngine;
struct IObjManager;
struct CVars;
struct CVisAreaManager;
class COcean;
class C3DEngine;
class CParticleManager;
class CDecalManager;
class CRainManager;
class CCloudsManager;
class CSkyLightManager;
class CRenderMeshMerger;
class CMergedMeshesManager;
class CGeomCacheManager;
class CBreezeGenerator;
class CMatMan;
class CClipVolumeManager;
namespace AZ::IO
{
struct IArchive;
}
#define DISTANCE_TO_THE_SUN 1000000
#if !defined(_RELEASE)
#define OBJMAN_STREAM_STATS
#endif
struct Cry3DEngineBase
{
static ISystem* m_pSystem;
static IRenderer* m_pRenderer;
static ITimer* m_pTimer;
static ILog* m_pLog;
static ::IConsole* m_pConsole;
static C3DEngine* m_p3DEngine;
static CVars* m_pCVars;
static AZ::IO::IArchive* m_pCryPak;
static CObjManager* m_pObjManager;
static COcean* m_pOcean;
static IOpticsManager* m_pOpticsManager;
static CDecalManager* m_pDecalManager;
static CCloudsManager* m_pCloudsManager;
static CVisAreaManager* m_pVisAreaManager;
static CClipVolumeManager* m_pClipVolumeManager;
static CMatMan* m_pMatMan;
static CSkyLightManager* m_pSkyLightManager;
static CRenderMeshMerger* m_pRenderMeshMerger;
static IStreamedObjectListener* m_pStreamListener;
#if defined(USE_GEOM_CACHES)
static CGeomCacheManager* m_pGeomCacheManager;
#endif
static float m_fInvDissolveDistBand;
static threadID m_nMainThreadId;
static bool m_bLevelLoadingInProgress;
static bool m_bIsInRenderScene;
static bool m_bAsyncOctreeUpdates;
static bool m_bRenderTypeEnabled[eERType_TypesNum];
static int m_CpuFlags;
static ESystemConfigSpec m_LightConfigSpec;
#if defined(CONSOLE)
static const bool m_bEditor = false;
#else
static bool m_bEditor;
#endif
static int m_arrInstancesCounter[eERType_TypesNum];
// components access
ILINE static ISystem* GetSystem() { return m_pSystem; }
ILINE static IRenderer* GetRenderer() { return m_pRenderer; }
ILINE static ITimer* GetTimer() { return m_pTimer; }
ILINE static ILog* GetLog() { return m_pLog; }
inline static ::IConsole* GetConsole() { return m_pConsole; }
inline static C3DEngine* Get3DEngine() { return m_p3DEngine; }
inline static CObjManager* GetObjManager() { return m_pObjManager; };
inline static COcean* GetOcean() { return m_pOcean; };
inline static CVars* GetCVars() { return m_pCVars; }
inline static CVisAreaManager* GetVisAreaManager() { return m_pVisAreaManager; }
inline static AZ::IO::IArchive* GetPak() { return m_pCryPak; }
inline static CMatMan* GetMatMan() { return m_pMatMan; }
inline static CCloudsManager* GetCloudsManager() { return m_pCloudsManager; }
inline static CRenderMeshMerger* GetSharedRenderMeshMerger() { return m_pRenderMeshMerger; };
inline static CTemporaryPool* GetTemporaryPool() { return CTemporaryPool::Get(); };
#if defined(USE_GEOM_CACHES)
inline static CGeomCacheManager* GetGeomCacheManager() { return m_pGeomCacheManager; };
#endif
ILINE static bool IsRenderNodeTypeEnabled(EERType rnType) { return m_bRenderTypeEnabled[(int)rnType]; }
ILINE static void SetRenderNodeTypeEnabled(EERType rnType, bool bEnabled) {m_bRenderTypeEnabled[(int)rnType] = bEnabled; }
inline static int GetDefSID() { return DEFAULT_SID; };
float GetCurTimeSec();
float GetCurAsyncTimeSec();
static void PrintMessage(const char* szText, ...) PRINTF_PARAMS(1, 2);
static void PrintMessagePlus(const char* szText, ...) PRINTF_PARAMS(1, 2);
static void PrintComment(const char* szText, ...) PRINTF_PARAMS(1, 2);
// Validator warning.
static void Warning(const char* format, ...) PRINTF_PARAMS(1, 2);
static void Error(const char* format, ...) PRINTF_PARAMS(1, 2);
static void FileWarning(int flags, const char* file, const char* format, ...)
PRINTF_PARAMS(3, 4);
CRenderObject* GetIdentityCRenderObject(int nThreadID)
{
CRenderObject* pCRenderObject = GetRenderer()->EF_GetObject_Temp(nThreadID);
if (!pCRenderObject)
{
return NULL;
}
pCRenderObject->m_II.m_Matrix.SetIdentity();
return pCRenderObject;
}
static bool IsValidFile(const char* sFilename);
static bool IsResourceLocked(const char* sFilename);
static bool IsPreloadEnabled();
_smart_ptr<IMaterial> MakeSystemMaterialFromShader(const char* sShaderName, SInputShaderResources* Res = NULL);
void DrawBBoxLabeled(const AABB& aabb, const Matrix34& m34, const ColorB& col, const char* format, ...) PRINTF_PARAMS(5, 6);
void DrawBBox(const Vec3& vMin, const Vec3& vMax, ColorB col = Col_White);
void DrawBBox(const AABB& box, ColorB col = Col_White);
void DrawLine(const Vec3& vMin, const Vec3& vMax, ColorB col = Col_White);
void DrawSphere(const Vec3& vPos, float fRadius, ColorB color = ColorB(255, 255, 255, 255));
void DrawQuad(const Vec3& v0, const Vec3& v1, const Vec3& v2, const Vec3& v3, ColorB color);
int& GetInstCount(EERType eType) { return m_arrInstancesCounter[eType]; }
uint32 GetMinSpecFromRenderNodeFlags(uint32 dwRndFlags) const { return (dwRndFlags & ERF_SPEC_BITS_MASK) >> ERF_SPEC_BITS_SHIFT; }
static bool CheckMinSpec(uint32 nMinSpec);
static bool IsEscapePressed();
size_t fread(
void* buffer,
size_t elementSize,
size_t count,
FILE* stream)
{
size_t res = ::fread(buffer, elementSize, count, stream);
if (res != count)
{
Error("fread() failed");
}
return res;
}
int fseek (
FILE* stream,
long offset,
int whence
)
{
int res = ::fseek(stream, offset, whence);
if (res != 0)
{
Error("fseek() failed");
}
return res;
}
};
#endif // CRYINCLUDE_CRY3DENGINE_CRY3DENGINEBASE_H
@@ -1,35 +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
#include "ProjectDefines.h"
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(Cry3DEngineTraits_h)
#else
#if defined(WIN32) || defined(WIN64)
#define AZ_LEGACY_3DENGINE_TRAIT_DEFINE_MM_MULLO_EPI32_EMU 1
#endif
#if defined(WIN32) || defined(WIN64)
#define AZ_LEGACY_3DENGINE_TRAIT_DO_EXTRA_GEOMCACHE_PROCESSING 1 // probably needs a better name
#endif
#define AZ_LEGACY_3DENGINE_TRAIT_HAS_MM_CVTEPI16_EPI32 0
#define AZ_LEGACY_3DENGINE_TRAIT_HAS_MM_MULLO_EPI32 0
#define AZ_LEGACY_3DENGINE_TRAIT_HAS_MM_PACKUS_EPI32 0
#if defined(WIN32) || defined(WIN64) || defined(LINUX) || defined(MAC)
#define AZ_LEGACY_3DENGINE_TRAIT_HAS_SSE 1
#endif
#define AZ_LEGACY_3DENGINE_TRAIT_UNROLL_GEOMETRY_BACKING_LOOPS 1
#if defined(APPLE) || defined(LINUX)
#define AZ_LEGACY_3DENGINE_TRAIT_DISABLE_MMRM_SSE_INSTRUCTIONS 1
#endif
#endif
@@ -1,14 +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"
@@ -1,186 +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.
#pragma once
const int nThreadsNum = 3;
#include <platform.h>
#include <vector>
//#define DEFINE_MODULE_NAME "Cry3DEngine"
//#define FORCE_STANDARD_ASSERT // fix edit and continue
#if defined(WIN64)
#define CRY_INTEGRATE_DX12
#endif
//////////////////////////////////////////////////////////////////////////////////////////////
// Highlevel defines
// deferred cull queue handling - currently disabled
// #define USE_CULL_QUEUE
// Compilation (Export to Engine) not needed on consoles
#if defined(CONSOLE)
# define ENGINE_ENABLE_COMPILATION 0
#else
# define ENGINE_ENABLE_COMPILATION 1
#endif
#include <stdio.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/Casting/lossy_cast.h>
#define MAX_PATH_LENGTH 512
#include <ITimer.h>
#include <IProcess.h>
#include <Cry_Math.h>
#include <Cry_Camera.h>
#include <Cry_XOptimise.h>
#include <Cry_Geo.h>
#include <ILog.h>
#include <ISystem.h>
#include <IConsole.h>
#include <IPhysics.h>
#include <IRenderer.h>
#include <IRenderAuxGeom.h>
#include <IEntityRenderState.h>
#include <StackContainer.h>
#include <I3DEngine.h>
#include <CryFile.h>
#include <smartptr.h>
#include <CryArray.h>
#include <CryHeaders.h>
#include "Cry3DEngineBase.h"
#include <float.h>
#include "CryArray.h"
#include "cvars.h"
#include <CrySizer.h>
#include <StlUtils.h>
#include <CryArray2d.h>
#include "Material.h"
#include "3dEngine.h"
#include "ObjMan.h"
#include <ISerialize.h>
#include "BasicArea.h"
#include "Environment/OceanEnvironmentBus.h"
#include "ObjectsTree.h"
inline int snprintf(char* buf, int size, const char* format, ...)
{
va_list arglist;
va_start(arglist, format);
int res = azvsnprintf(buf, size, format, arglist);
va_end(arglist);
return res;
}
template <class T>
void AddToPtr(byte*& pPtr, T& rObj, EEndian eEndian)
{
PREFAST_SUPPRESS_WARNING(6326) COMPILE_TIME_ASSERT(((sizeof(T) % 4) == 0));
assert(!((INT_PTR)pPtr & 3));
memcpy(pPtr, &rObj, sizeof(rObj));
SwapEndian(*(T*)pPtr, eEndian);
pPtr += sizeof(rObj);
assert(!((INT_PTR)pPtr & 3));
}
template <class T>
void AddToPtr(byte*& pPtr, int& nDataSize, T& rObj, EEndian eEndian)
{
PREFAST_SUPPRESS_WARNING(6326) COMPILE_TIME_ASSERT(((sizeof(T) % 4) == 0));
assert(!((INT_PTR)pPtr & 3));
memcpy(pPtr, &rObj, sizeof(rObj));
SwapEndian(*(T*)pPtr, eEndian);
pPtr += sizeof(rObj);
nDataSize -= sizeof(rObj);
assert(nDataSize >= 0);
assert(!((INT_PTR)pPtr & 3));
}
inline void FixAlignment(byte*& pPtr, int& nDataSize)
{
while ((UINT_PTR)pPtr & 3)
{
*pPtr = 222;
pPtr++;
nDataSize--;
}
}
inline void FixAlignment(byte*& pPtr)
{
while ((UINT_PTR)pPtr & 3)
{
*pPtr = 222;
pPtr++;
}
}
template <class T>
void AddToPtr(byte*& pPtr, int& nDataSize, const T* pArray, int nElemNum, EEndian eEndian, bool bFixAlignment = false)
{
assert(!((INT_PTR)pPtr & 3));
memcpy(pPtr, pArray, nElemNum * sizeof(T));
SwapEndian((T*)pPtr, nElemNum, eEndian);
pPtr += nElemNum * sizeof(T);
nDataSize -= nElemNum * sizeof(T);
assert(nDataSize >= 0);
if (bFixAlignment)
{
FixAlignment(pPtr, nDataSize);
}
else
{
assert(!((INT_PTR)pPtr & 3));
}
}
template <class T>
void AddToPtr(byte*& pPtr, const T* pArray, int nElemNum, EEndian eEndian, bool bFixAlignment = false)
{
assert(!((INT_PTR)pPtr & 3));
memcpy(pPtr, pArray, nElemNum * sizeof(T));
SwapEndian((T*)pPtr, nElemNum, eEndian);
pPtr += nElemNum * sizeof(T);
if (bFixAlignment)
{
FixAlignment(pPtr);
}
else
{
assert(!((INT_PTR)pPtr & 3));
}
}
struct TriangleIndex
{
TriangleIndex() { ZeroStruct(*this); }
uint16& operator [] (const int& n) { assert(n >= 0 && n < 3); return idx[n]; }
const uint16& operator [] (const int& n) const { assert(n >= 0 && n < 3); return idx[n]; }
uint16 idx[3];
uint16 nCull;
};
#define FUNCTION_PROFILER_3DENGINE FUNCTION_PROFILER(gEnv->pSystem, PROFILE_3DENGINE)
#define FUNCTION_PROFILER_3DENGINE_LEGACYONLY FUNCTION_PROFILER_LEGACYONLY(gEnv->pSystem, PROFILE_3DENGINE)
@@ -1,990 +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/Cry_LegacyPhysUtils.h>
namespace LegacyCryPhysicsUtils
{
namespace qhull_IMPL
{
static int __qhullcalled = 0;
int qhull(strided_pointer<Vec3> _pts, int npts, index_t*& pTris, qhullmalloc qmalloc)
{
#if defined(PLATFORM_64BIT)
static ptitem ptbuf[4096];
static qhtritem trbuf[4096];
static qhtritem* tmparr_ptr_buf[2048];
static int tmparr_idx_buf[2048];
#else
static ptitem ptbuf[1024];
static qhtritem trbuf[1024];
static qhtritem* tmparr_ptr_buf[512];
static int tmparr_idx_buf[512];
#endif
static volatile int g_lockQhull;
int iter = 0, maxiter = 0;
__qhullcalled++;
strided_pointer<Vec3mem> pts = strided_pointer<Vec3mem>((Vec3mem*)_pts.data, _pts.iStride);
ptitem* pt, * ptmax, * ptdeleted, * ptlist = npts > sizeof(ptbuf) / sizeof(ptbuf[0]) ? new ptitem[npts] : ptbuf;
qhtritem* tr, * trnext, * trend, * trnew, * trdata = trbuf, * trstart = 0, * trlast, * trbest = nullptr;
int i, j, k, ti, trdatasz = sizeof(trbuf) / sizeof(trbuf[0]), bidx[6], n, next_iter, delbuds;
qhtritem** tmparr_ptr = tmparr_ptr_buf;
int* tmparr_idx = tmparr_idx_buf, tmparr_sz = 512;
float dist, maxdist /*,e*/;
Vec3 pmin(VMAX), pmax(VMIN);
WriteLock lock(g_lockQhull);
// select points for initial tetrahedron
// first, find 6 points corresponding to min and max coordinates
for (i = 1; i < npts; i++)
{
if (pts[i].x > pmax.x)
{
pmax.x = pts[i].x;
bidx[0] = i;
}
if (pts[i].x < pmin.x)
{
pmin.x = pts[i].x;
bidx[1] = i;
}
if (pts[i].y > pmax.y)
{
pmax.y = pts[i].y;
bidx[2] = i;
}
if (pts[i].y < pmin.y)
{
pmin.y = pts[i].y;
bidx[3] = i;
}
if (pts[i].z > pmax.z)
{
pmax.z = pts[i].z;
bidx[4] = i;
}
if (pts[i].z < pmin.z)
{
pmin.z = pts[i].z;
bidx[5] = i;
}
}
// e = max(max(pmax.x-pmin.x,pmax.y-pmin.y),pmax.z-pmin.z)*0.01f;
for (bidx[0] = 0, i = 1; i < npts; i++)
{
bidx[0] += i - bidx[0] & -isneg(pts[i].x - pts[bidx[0]].x);
}
for (bidx[1] = 0, i = 1; i < npts; i++)
{
bidx[1] += i - bidx[1] & -isneg((pts[bidx[1]] - pts[bidx[0]]).len2() - (pts[i] - pts[bidx[0]]).len2());
}
Vec3 norm = pts[bidx[1]] - pts[bidx[0]];
for (bidx[2] = 0, i = 1; i < npts; i++)
{
bidx[2] += i - bidx[2] & -isneg((norm ^ pts[bidx[2]] - pts[bidx[0]]).len2() - (norm ^ pts[i] - pts[bidx[0]]).len2());
}
norm = pts[bidx[1]] - pts[bidx[0]] ^ pts[bidx[2]] - pts[bidx[0]];
for (bidx[3] = 0, i = 1; i < npts; i++)
{
bidx[3] += i - bidx[3] & -isneg(fabs_tpl((pts[bidx[3]] - pts[bidx[0]]) * norm) - fabs_tpl((pts[i] - pts[bidx[0]]) * norm));
}
if ((pts[bidx[3]] - pts[bidx[0]]) * norm > 0)
{
i = bidx[1];
bidx[1] = bidx[2];
bidx[2] = i;
}
// build a double linked list from all points
for (i = 0; i < npts; i++)
{
ptlist[i].prev = ptlist + i - 1;
ptlist[i].next = ptlist + i + 1;
}
ptlist[0].prev = ptlist + npts - 1;
ptlist[npts - 1].next = ptlist;
// remove selected points from the list
for (i = 0; i < 4; i++)
{
delete_item_from_list(ptlist + bidx[i]);
}
// assign 3 points to each of 4 initial triangles
for (i = 0; i < 4; i++)
{
for (j = k = 0; j < 4; j++)
{
if (j != i)
{
trbuf[i].idx[k++] = bidx[j]; // skip i.th point in i.th triangle
}
}
trbuf[i].n = pts[trbuf[i].idx[1]] - pts[trbuf[i].idx[0]] ^ pts[trbuf[i].idx[2]] - pts[trbuf[i].idx[0]];
trbuf[i].pt0 = pts[trbuf[i].idx[0]];
if (e_cansee(pts[bidx[i]] - trbuf[i].pt0, trbuf[i].n, 0)) // flip the orientation so that ccw normal points outwards
{
ti = trbuf[i].idx[0];
trbuf[i].idx[0] = trbuf[i].idx[2];
trbuf[i].idx[2] = ti;
trbuf[i].n = -trbuf[i].n;
}
trbuf[i].ptassoc = 0;
trbuf[i].deleted = 0;
add_item_to_list(trstart, trbuf + i);
}
// fill buddy links for each triangle
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if (j != i)
{
for (k = 0; k < 3; k++)
{
for (ti = 0; ti < 3; ti++)
{
if (trbuf[i].idx[k] == trbuf[j].idx[ti] && trbuf[i].idx[k == 2 ? 0 : k + 1] == trbuf[j].idx[ti == 0 ? 2 : ti - 1])
{
trbuf[i].buddy[k] = trbuf + j;
break;
}
}
}
}
}
}
trend = trstart + 4;
for (i = 0; i < 4; i++)
{
if (trbuf[i].n.len2() < 1E-6f)
{
#ifdef _DEBUG
//OutputDebugString("WARNING: convex hull not computed because of degenerate initial triangles\n");
#endif
n = 0;
goto endqhull; // some degenerate case, don't party with it
}
}
// associate points with one of the initial triangles
for (i = 0; i < npts; i++)
{
if (ptlist[i].next)
{
break;
}
}
associate_ptlist_with_trilist(ptlist + i, trstart, ptlist, pts);
#define DELETE_TRI(ptri) { \
merge_lists(ptdeleted, (ptri)->ptassoc); \
if ((ptri) == trstart) {trstart = (ptri)->next; } \
if ((ptri) == trnext) {trnext = (ptri)->next; } \
delete_item_from_list(ptri); (ptri)->deleted = 1; }
// main loop
iter = 0;
maxiter = npts * npts * 2;
ptmax = trstart->ptassoc;
tr = trstart;
do
{
trnext = tr->next;
pt = tr->ptassoc;
if (pt)
{
// find the fartherst of the associated with the triangle points
maxdist = -1E37f;
do
{
if ((dist = pts[(int)(pt - ptlist)] * tr->n) > maxdist)
{
maxdist = dist;
ptmax = pt;
}
pt = pt->next;
} while (pt != tr->ptassoc);
ptdeleted = 0;
if (tr->ptassoc == ptmax)
{
tr->ptassoc = ptmax->next;
}
delete_item_from_list(ptmax);
if (tr->ptassoc == ptmax)
{
tr->ptassoc = 0;
}
// find the triangle that the point can see "most confidently"
tr = trstart;
trlast = tr->prev;
ti = static_cast<int>(ptmax - ptlist);
maxdist = -1E37f;
do
{
trnext = tr->next;
if ((pts[ti] - tr->pt0) * tr->n > maxdist)
{
maxdist = (pts[ti] - tr->pt0) * tr->n;
trbest = tr;
}
if (tr == trlast)
{
break;
}
tr = trnext;
} while (true);
// "flood fill" triangles that the point can see around that one
DELETE_TRI(trbest)
tr = trbest->next = trbest->prev = trbest;
do
{
if (tr->buddy[0] && !tr->buddy[0]->deleted && e_cansee(pts[ti] - tr->buddy[0]->pt0, tr->buddy[0]->n, 0))
{
DELETE_TRI(tr->buddy[0])
add_item_to_list(tr, tr->buddy[0]);
}
if (tr->buddy[1] && !tr->buddy[1]->deleted && e_cansee(pts[ti] - tr->buddy[1]->pt0, tr->buddy[1]->n, 0))
{
DELETE_TRI(tr->buddy[1])
add_item_to_list(tr, tr->buddy[1]);
}
if (tr->buddy[2] && !tr->buddy[2]->deleted && e_cansee(pts[ti] - tr->buddy[2]->pt0, tr->buddy[2]->n, 0))
{
DELETE_TRI(tr->buddy[2])
add_item_to_list(tr, tr->buddy[2]);
}
tr = tr->next;
} while (tr != trbest);
// delete near-visible triangles around deleted area edges to preserve hole convexity
// do as many iterations as needed
do
{
tr = trstart;
trlast = tr->prev;
next_iter = 0;
do
{
trnext = tr->next;
if (e_cansee(pts[ti] - tr->pt0, tr->n, -0.001f))
{
delbuds = tr->buddy[0]->deleted + tr->buddy[1]->deleted + tr->buddy[2]->deleted;
if (delbuds >= 2) // delete triangles that have 2+ buddies deleted
{
if (tr == trlast)
{
trlast = tr->next;
}
DELETE_TRI(tr);
next_iter = 1;
}
else if (delbuds == 1) // follow triangle fan around both shared edge ends
{
int bi, bi0, bi1, nfantris, fandir;
qhtritem* fantris[64], * tr1;
for (bi0 = 0; bi0 < 3 && !tr->buddy[bi0]->deleted; bi0++)
{
; // bi0 - deleted buddy index
}
for (fandir = -1; fandir <= 1; fandir += 2) // follow fans in 2 possible directions
{
tr1 = tr;
bi1 = bi0;
nfantris = 0;
do
{
if (nfantris == 64)
{
break;
}
bi = bi1 + fandir;
if (bi > 2)
{
bi -= 3;
}
if (bi < 0)
{
bi += 3;
}
for (bi1 = 0; bi1 < 3 && tr1->buddy[bi]->buddy[bi1] != tr1; bi1++)
{
;
}
fantris[nfantris++] = tr1; // store this triangle in a temporary fan list
tr1 = tr1->buddy[bi];
bi = bi1; // go to the next fan triangle
if (!e_cansee(pts[ti] - tr1->pt0, tr1->n, -0.002f))
{
break; // discard this fan
}
if (tr1->deleted)
{
if (tr1 != tr->buddy[bi0])
{
// delete fan only if it ended on _another_ deleted triangle
for (--nfantris; nfantris >= 0; nfantris--)
{
if (fantris[nfantris] == trlast)
{
trlast = fantris[nfantris]->next;
}
DELETE_TRI(fantris[nfantris])
}
next_iter = 1;
}
break; // fan end
}
} while (true);
}
}
}
if (tr == trlast)
{
break;
}
tr = trnext;
} while (tr);
} while (next_iter && trstart);
if (!trstart || trstart->deleted)
{
n = 0;
goto endqhull;
}
// find triangles that shared an edge with deleted triangles
trnew = 0;
tr = trstart;
do
{
for (i = 0; i < 3; i++)
{
if (tr->buddy[i]->deleted)
{
// create a new triangle
if (trend >= trdata + trdatasz)
{
qhtritem* trdata_new = new qhtritem[trdatasz += 256];
memcpy(trdata_new, trdata, (trend - trdata) * sizeof(qhtritem));
intptr_t diff = (intptr_t)trdata_new - (intptr_t)trdata;
for (n = 0; n < trdatasz - 256; n++)
{
relocate_tritem(trdata_new + n, diff);
}
relocate_ptritem(trend, diff);
relocate_ptritem(trstart, diff);
relocate_ptritem(trnext, diff);
relocate_ptritem(tr, diff);
relocate_ptritem(trbest, diff);
relocate_ptritem(trnew, diff);
if (trdata != trbuf)
{
delete[] trdata;
}
trdata = trdata_new;
}
trend->idx[0] = static_cast<int>(ptmax - ptlist);
trend->idx[1] = tr->idx[i == 2 ? 0 : i + 1];
trend->idx[2] = tr->idx[i];
trend->ptassoc = 0;
trend->deleted = 0;
trend->n = pts[trend->idx[1]] - pts[trend->idx[0]] ^ pts[trend->idx[2]] - pts[trend->idx[0]];
trend->pt0 = pts[trend->idx[0]];
trend->buddy[1] = tr;
tr->buddy[i] = trend;
trend->buddy[0] = trend->buddy[2] = 0;
add_item_to_list(trnew, trend++);
}
}
tr = tr->next;
} while (tr != trstart);
// sort pointers to the new triangles by their 2nd vertex index
n = static_cast<int>(trend - trnew);
if (tmparr_sz < n)
{
if (tmparr_idx != tmparr_idx_buf)
{
delete[] tmparr_idx;
}
if (tmparr_ptr != tmparr_ptr_buf)
{
delete[] tmparr_ptr;
}
tmparr_idx = new int[n];
tmparr_ptr = new qhtritem * [n];
}
for (tr = trnew, i = 0; tr < trend; tr++, i++)
{
tmparr_idx[i] = tr->idx[2];
tmparr_ptr[i] = tr;
}
qsort(tmparr_idx, (void**)tmparr_ptr, 0, static_cast<int>(trend - trnew - 1));
// find 0th buddy for each new triangle (i.e. the triangle, which has its idx[2]==tr->idx[1]
for (tr = trnew; tr < trend; tr++)
{
i = bin_search(tmparr_idx, n, tr->idx[1]);
tr->buddy[0] = tmparr_ptr[i];
tmparr_ptr[i]->buddy[2] = tr;
}
for (tr = trnew; tr < trend; tr++)
{
if (!tr->buddy[0] || !tr->buddy[2])
{
goto endqh;
}
}
// assign all points from the deleted triangles to the new triangles
associate_ptlist_with_trilist(ptdeleted, trnew, ptlist, pts);
// add new triangles to the list
merge_lists(trnext, trnew);
}
else if (trnext == trstart)
{
break; // all triangles in queue have no associated vertices
}
tr = trnext;
} while (++iter < maxiter);
endqh:
// build the final triangle list
for (tr = trstart, n = 1; tr->next != trstart; tr = tr->next, n++)
{
;
}
if (!pTris)
{
pTris = !qmalloc ? new index_t[n * 3] : (index_t*)qmalloc(sizeof(index_t) * n * 3);
}
i = 0;
tr = trstart;
do
{
pTris[i] = tr->idx[0];
pTris[i + 1] = tr->idx[1];
pTris[i + 2] = tr->idx[2];
tr = tr->next;
i += 3;
} while (tr != trstart);
endqhull:
if (ptlist != ptbuf)
{
delete[] ptlist;
}
if (tmparr_idx != tmparr_idx_buf)
{
delete[] tmparr_idx;
}
if (tmparr_ptr != tmparr_ptr_buf)
{
delete[] tmparr_ptr;
}
if (trdata != trbuf)
{
delete[] trdata;
}
return n;
}
#undef DELETE_TRI
void associate_ptlist_with_trilist(ptitem* ptlist, qhtritem* trilist, ptitem* pt0, strided_pointer<Vec3mem> pvtx)
{
if (!ptlist)
{
return;
}
ptitem* pt = ptlist, * ptnext, * ptlast = ptlist->prev;
qhtritem* tr;
int i;
do
{
ptnext = pt->next;
delete_item_from_list(pt);
tr = trilist;
i = static_cast<int>(pt - pt0);
do
{
if (e_cansee(pvtx[i] - tr->pt0, tr->n))
{
add_item_to_list(tr->ptassoc, pt);
break;
}
tr = tr->next;
} while (tr != trilist);
if (pt == ptlast)
{
break;
}
pt = ptnext;
} while (true);
}
void qsort(int* v, void** p, int left, int right)
{
if (left >= right)
{
return;
}
int i, last;
swap(v, p, left, (left + right) >> 1);
for (last = left, i = left + 1; i <= right; i++)
{
if (v[i] < v[left])
{
swap(v, p, ++last, i);
}
}
swap(v, p, left, last);
qsort(v, p, left, last - 1);
qsort(v, p, last + 1, right);
}
int bin_search(int* v, int n, int idx)
{
int left = 0, right = n, m;
do
{
m = (left + right) >> 1;
if (v[m] == idx)
{
return m;
}
if (v[m] < idx)
{
left = m;
}
else
{
right = m;
}
} while (left < right - 1);
return left;
}
}
int qhull(strided_pointer<Vec3> _pts, int npts, index_t*& pTris, qhullmalloc qmalloc)
{
return qhull_IMPL::qhull(_pts, npts, pTris, qmalloc);
}
int TriangulatePoly(vector2df* pVtx, int nVtx, int* pTris, int szTriBuf)
{
return TriangulatePoly_IMPL::TriangulatePoly(pVtx, nVtx, pTris, szTriBuf);
}
namespace TriangulatePoly_IMPL
{
int TriangulatePolyBruteforce(vector2df* pVtx, int nVtx, int* pTris, int szTriBuf)
{
int i, nThunks, nNonEars, nTris = 0;
vtxthunk* ptr, * ptr0, bufThunks[32], * pThunks = nVtx <= 31 ? bufThunks : new vtxthunk[nVtx + 1];
ptr = ptr0 = pThunks;
for (i = nThunks = 0; i < nVtx; i++)
{
if (!is_unused(pVtx[i].x))
{
pThunks[nThunks].next[0] = pThunks + nThunks - 1;
pThunks[nThunks].next[1] = pThunks + nThunks + 1;
pThunks[nThunks].pt = pVtx + i;
ptr = pThunks + nThunks++;
}
}
if (nThunks < 3)
{
return 0;
}
ptr->next[1] = ptr0;
ptr0->next[0] = ptr;
for (i = 0; i < nThunks; i++)
{
pThunks[i].bProcessed = (*pThunks[i].next[1]->pt - *pThunks[i].pt ^ *pThunks[i].next[0]->pt - *pThunks[i].pt) > 0;
}
for (nNonEars = 0; nNonEars < nThunks && nTris < szTriBuf; ptr0 = ptr0->next[1])
{
if (nThunks == 3)
{
pTris[nTris * 3] = static_cast<int>(ptr0->pt - pVtx);
pTris[nTris * 3 + 1] = static_cast<int>(ptr0->next[1]->pt - pVtx);
pTris[nTris * 3 + 2] = static_cast<int>(ptr0->next[0]->pt - pVtx);
nTris++;
break;
}
for (i = 0; (*ptr0->next[1]->pt - *ptr0->pt ^ *ptr0->next[0]->pt - *ptr0->pt) < 0 && i < nThunks; ptr0 = ptr0->next[1], i++)
{
;
}
if (i == nThunks)
{
break;
}
for (ptr = ptr0->next[1]->next[1]; ptr != ptr0->next[0] && ptr->bProcessed; ptr = ptr->next[1])
{
; // find the 1st non-convex vertex after ptr0
}
for (; ptr != ptr0->next[0] && min(min(*ptr0->pt - *ptr0->next[0]->pt ^ *ptr->pt - *ptr0->next[0]->pt,
*ptr0->next[1]->pt - *ptr0->pt ^ *ptr->pt - *ptr0->pt),
*ptr0->next[0]->pt - *ptr0->next[1]->pt ^ *ptr->pt - *ptr0->next[1]->pt) < 0; ptr = ptr->next[1])
{
;
}
if (ptr == ptr0->next[0]) // vertex is an ear, output the corresponding triangle
{
pTris[nTris * 3] = static_cast<int>(ptr0->pt - pVtx);
pTris[nTris * 3 + 1] = static_cast<int>(ptr0->next[1]->pt - pVtx);
pTris[nTris * 3 + 2] = static_cast<int>(ptr0->next[0]->pt - pVtx);
nTris++;
ptr0->next[1]->next[0] = ptr0->next[0];
ptr0->next[0]->next[1] = ptr0->next[1];
nThunks--;
nNonEars = 0;
}
else
{
nNonEars++;
}
}
if (pThunks != bufThunks)
{
delete[] pThunks;
}
return nTris;
}
int TriangulatePoly(vector2df* pVtx, int nVtx, int* pTris, int szTriBuf)
{
if (nVtx < 3)
{
return 0;
}
vtxthunk* pThunks, * pPrevThunk, * pContStart, ** pSags, ** pBottoms, * pPinnacle = nullptr, * pBounds[2], * pPrevBounds[2], * ptr, * ptr_next;
vtxthunk bufThunks[32], * bufSags[16], * bufBottoms[16];
int i, nThunks, nBottoms = 0, nSags = 0, iBottom = 0, nConts = 0, j, isag, nThunks0, nTris = 0, nPrevSags, nTrisCnt, iter, nDegenTris = 0;
float ymax, ymin, e, area0 = 0, area1 = 0, cntarea, minCntArea;
isag = is_unused(pVtx[0].x);
ymin = ymax = pVtx[isag].y;
for (i = isag; i < nVtx; i++)
{
if (!is_unused(pVtx[i].x))
{
ymin = min(ymin, pVtx[i].y);
ymax = max(ymax, pVtx[i].y);
}
}
e = (ymax - ymin) * 0.0005f;
for (i = 1 + isag; i < nVtx; i++)
{
if (!is_unused(pVtx[i].x))
{
j = i < nVtx - 1 && !is_unused(pVtx[i + 1].x) ? i + 1 : isag;
if ((ymin = min(pVtx[j].y, pVtx[i - 1].y)) > pVtx[i].y - e)
{
if ((pVtx[j] - pVtx[i] ^ pVtx[i - 1] - pVtx[i]) > 0)
{
nBottoms++; // we have a bottom
}
else if (ymin > pVtx[i].y + 1E-8f)
{
nSags++; // we have a sag
}
}
}
else
{
nConts++;
isag = ++i;
}
}
nSags += nConts;
if ((nConts - 2) >> 31 & g_bBruteforceTriangulation)
{
return TriangulatePolyBruteforce(pVtx, nVtx, pTris, szTriBuf);
}
pThunks = nVtx + nSags * 2 <= sizeof(bufThunks) / sizeof(bufThunks[0]) ? bufThunks : new vtxthunk[nVtx + nSags * 2];
for (i = nThunks = 0, pContStart = pPrevThunk = pThunks; i < nVtx; i++)
{
if (!is_unused(pVtx[i].x))
{
pThunks[nThunks].next[1] = pThunks + nThunks;
pThunks[nThunks].next[1] = pPrevThunk->next[1];
pPrevThunk->next[1] = pThunks + nThunks;
pThunks[nThunks].next[0] = pPrevThunk;
pThunks[nThunks].jump = 0;
pPrevThunk = pThunks + nThunks;
pThunks[nThunks].bProcessed = 0;
pThunks[nThunks++].pt = &pVtx[i];
}
else
{
pPrevThunk->next[1] = pContStart;
pContStart->next[0] = pThunks + nThunks - 1;
pContStart = pPrevThunk = pThunks + nThunks;
}
}
for (i = j = 0, cntarea = 0, minCntArea = 1; i < nThunks; i++)
{
cntarea += *pThunks[i].pt ^ *pThunks[i].next[1]->pt;
j++;
if (pThunks[i].next[1] != pThunks + i + 1)
{
if (j >= 3)
{
area0 += cntarea;
minCntArea = min(cntarea, minCntArea);
}
cntarea = 0;
j = 0;
}
}
if (minCntArea > 0 && nConts > 1)
{
// if all contours are positive, triangulate them as separate (it's more safe)
for (i = 0; i < nThunks; i++)
{
if (pThunks[i].next[0] != pThunks + i - 1)
{
nTrisCnt = TriangulatePoly(pThunks[i].pt, static_cast<int>((pThunks[i].next[0]->pt - pThunks[i].pt) + 2), pTris + nTris * 3, szTriBuf - nTris * 3);
for (j = 0, isag = static_cast<int>(pThunks[i].pt - pVtx); j < nTrisCnt * 3; j++)
{
pTris[nTris * 3 + j] += isag;
}
i = static_cast<int>(pThunks[i].next[0] - pThunks);
nTris += nTrisCnt;
}
}
if (pThunks != bufThunks)
{
delete[] pThunks;
}
return nTris;
}
pSags = nSags <= sizeof(bufSags) / sizeof(bufSags[0]) ? bufSags : new vtxthunk * [nSags];
pBottoms = nSags + nBottoms <= sizeof(bufBottoms) / sizeof(bufBottoms[0]) ? bufBottoms : new vtxthunk * [nSags + nBottoms];
for (i = nSags = nBottoms = 0; i < nThunks; i++)
{
if ((ymin = min(pThunks[i].next[1]->pt->y, pThunks[i].next[0]->pt->y)) > pThunks[i].pt->y - e)
{
if ((*pThunks[i].next[1]->pt - *pThunks[i].pt ^ *pThunks[i].next[0]->pt - *pThunks[i].pt) >= 0)
{
pBottoms[nBottoms++] = pThunks + i; // we have a bottom
}
else if (ymin > pThunks[i].pt->y + e)
{
pSags[nSags++] = pThunks + i; // we have a sag
}
}
}
iBottom = -1;
pBounds[0] = pBounds[1] = pPrevBounds[0] = pPrevBounds[1] = 0;
nThunks0 = nThunks;
nPrevSags = nSags;
iter = nThunks * 4;
do
{
nextiter:
if (!pBounds[0]) // if bounds are empty, get the next available bottom
{
for (++iBottom; iBottom < nBottoms && !pBottoms[iBottom]->next[0]; iBottom++)
{
;
}
if (iBottom >= nBottoms)
{
break;
}
pBounds[0] = pBounds[1] = pPinnacle = pBottoms[iBottom];
}
pBounds[0]->bProcessed = pBounds[1]->bProcessed = 1;
if (pBounds[0] == pPrevBounds[0] && pBounds[1] == pPrevBounds[1] && nSags == nPrevSags || !pBounds[0]->next[0] || !pBounds[1]->next[0])
{
pBounds[0] = pBounds[1] = 0;
continue;
}
pPrevBounds[0] = pBounds[0];
pPrevBounds[1] = pBounds[1];
nPrevSags = nSags;
// check if left or right is a top
for (i = 0; i < 2; i++)
{
if (pBounds[i]->next[0]->pt->y < pBounds[i]->pt->y && pBounds[i]->next[1]->pt->y <= pBounds[i]->pt->y &&
(*pBounds[i]->next[0]->pt - *pBounds[i]->pt ^ *pBounds[i]->next[1]->pt - *pBounds[i]->pt) > 0)
{
if (pBounds[i]->jump)
{
do
{
ptr = pBounds[i]->jump;
pBounds[i]->jump = 0;
pBounds[i] = ptr;
} while (pBounds[i]->jump);
}
else
{
pBounds[i]->jump = pBounds[i ^ 1];
pBounds[0] = pBounds[1] = 0;
goto nextiter;
}
if (!pBounds[0]->next[0] || !pBounds[1]->next[0])
{
pBounds[0] = pBounds[1] = 0;
goto nextiter;
}
}
}
i = isneg(pBounds[1]->next[1]->pt->y - pBounds[0]->next[0]->pt->y);
ymax = pBounds[i ^ 1]->next[i ^ 1]->pt->y;
ymin = min(pBounds[0]->pt->y, pBounds[1]->pt->y);
for (j = 0, isag = -1; j < nSags; j++)
{
if (inrange(pSags[j]->pt->y, ymin, ymax) && // find a sag in next left-left-right-next right quad
pSags[j] != pBounds[0]->next[0] && pSags[j] != pBounds[1]->next[1] &&
(*pBounds[0]->pt - *pBounds[0]->next[0]->pt ^ *pSags[j]->pt - *pBounds[0]->next[0]->pt) >= 0 &&
(*pBounds[1]->pt - *pBounds[0]->pt ^ *pSags[j]->pt - *pBounds[0]->pt) >= 0 &&
(*pBounds[1]->next[1]->pt - *pBounds[1]->pt ^ *pSags[j]->pt - *pBounds[1]->pt) >= 0 &&
(*pBounds[0]->next[0]->pt - *pBounds[1]->next[1]->pt ^ *pSags[j]->pt - *pBounds[1]->next[1]->pt) >= 0)
{
ymax = pSags[j]->pt->y;
isag = j;
}
}
if (isag >= 0) // build a bridge between the sag and the highest active point
{
if (pSags[isag]->next[0])
{
pPinnacle->next[1]->next[0] = pThunks + nThunks;
pSags[isag]->next[0]->next[1] = pThunks + nThunks + 1;
pThunks[nThunks].next[0] = pThunks + nThunks + 1;
pThunks[nThunks].next[1] = pPinnacle->next[1];
pThunks[nThunks + 1].next[1] = pThunks + nThunks;
pThunks[nThunks + 1].next[0] = pSags[isag]->next[0];
pPinnacle->next[1] = pSags[isag];
pSags[isag]->next[0] = pPinnacle;
pThunks[nThunks].pt = pPinnacle->pt;
pThunks[nThunks + 1].pt = pSags[isag]->pt;
pThunks[nThunks].jump = pThunks[nThunks + 1].jump = 0;
pThunks[nThunks].bProcessed = pThunks[nThunks + 1].bProcessed = 0;
if (pBounds[1] == pPinnacle)
{
pBounds[1] = pThunks + nThunks;
}
for (ptr = pThunks + nThunks, j = 0; ptr != pBounds[1]->next[1] && j < nThunks; ptr = ptr->next[1], j++)
{
if (min(ptr->next[0]->pt->y, ptr->next[1]->pt->y) > ptr->pt->y) // ptr is a bottom
{
pBottoms[nBottoms++] = ptr;
break;
}
}
pBounds[1] = pPinnacle;
pPinnacle = pSags[isag];
nThunks += 2;
}
for (j = isag; j < nSags - 1; j++)
{
pSags[j] = pSags[j + 1];
}
--nSags;
continue;
}
// create triangles featuring the new vertex
for (ptr = pBounds[i]; ptr != pBounds[i ^ 1] && nTris < szTriBuf; ptr = ptr_next)
{
if ((*ptr->next[i ^ 1]->pt - *ptr->pt ^ *ptr->next[i]->pt - *ptr->pt) * (1 - i * 2) > 0 || pBounds[0]->next[0] == pBounds[1]->next[1])
{
// output the triangle
pTris[nTris * 3] = static_cast<int>(pBounds[i]->next[i]->pt - pVtx);
pTris[nTris * 3 + 1 + i] = static_cast<int>(ptr->pt - pVtx);
pTris[nTris * 3 + 2 - i] = static_cast<int>(ptr->next[i ^ 1]->pt - pVtx);
vector2df edge0 = pVtx[pTris[nTris * 3 + 1]] - pVtx[pTris[nTris * 3]], edge1 = pVtx[pTris[nTris * 3 + 2]] - pVtx[pTris[nTris * 3]];
float darea = edge0 ^ edge1;
area1 += darea;
nDegenTris += isneg(sqr(darea) - sqr(0.02f) * (edge0 * edge0) * (edge1 * edge1));
nTris++;
ptr->next[i ^ 1]->next[i] = ptr->next[i];
ptr->next[i]->next[i ^ 1] = ptr->next[i ^ 1];
pBounds[i] = ptr_next = ptr->next[i ^ 1];
if (pPinnacle == ptr)
{
pPinnacle = ptr->next[i];
}
ptr->next[0] = ptr->next[1] = 0;
ptr->bProcessed = 1;
}
else
{
break;
}
}
if ((pBounds[i] = pBounds[i]->next[i]) == pBounds[i ^ 1]->next[i ^ 1])
{
pBounds[0] = pBounds[1] = 0;
}
else if (pBounds[i]->pt->y > pPinnacle->pt->y)
{
pPinnacle = pBounds[i];
}
} while (nTris < szTriBuf && --iter);
if (pThunks != bufThunks)
{
delete[] pThunks;
}
if (pBottoms != bufBottoms)
{
delete[] pBottoms;
}
if (pSags != bufSags)
{
delete[] pSags;
}
int bProblem = nTris<nThunks0 - nConts * 2 || fabs_tpl(area0 - area1)>area0 * 0.003f || nTris >= szTriBuf;
if (bProblem || nDegenTris)
{
if (nConts == 1)
{
return TriangulatePolyBruteforce(pVtx, nVtx, pTris, szTriBuf);
}
else
{
g_nTriangulationErrors += bProblem;
}
}
return nTris;
}
}
}
-15
View File
@@ -1,15 +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"
-31
View File
@@ -1,31 +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 main include
#ifndef CRYINCLUDE_CRY3DENGINE_CULLBUFFER_H
#define CRYINCLUDE_CRY3DENGINE_CULLBUFFER_H
#pragma once
#include "ProjectDefines.h"
#include "ObjMan.h" // EOcclusionObjectType
#include "CZBufferCuller.h"
class CCullBuffer
: public CZBufferCuller
{
};
#endif // CRYINCLUDE_CRY3DENGINE_CULLBUFFER_H
-438
View File
@@ -1,438 +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 : draw, create decals on the world
#include "Cry3DEngine_precompiled.h"
#include "DecalManager.h"
#include "3dEngine.h"
#include "ObjMan.h"
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
IGeometry* CDecal::s_pSphere = 0;
void CDecal::ResetStaticData()
{
SAFE_RELEASE(s_pSphere);
}
int CDecal::Update(bool& active, const float fFrameTime)
{
// process life time and disable decal when needed
m_fLifeTime -= fFrameTime;
if (m_fLifeTime < 0)
{
active = 0;
FreeRenderData();
}
else if (m_ownerInfo.pRenderNode && m_ownerInfo.pRenderNode->m_nInternalFlags & IRenderNode::UPDATE_DECALS)
{
active = false;
return 1;
}
return 0;
}
Vec3 CDecal::GetWorldPosition()
{
Vec3 vPos = m_vPos;
if (m_ownerInfo.pRenderNode)
{
if (m_eDecalType == eDecalType_OS_SimpleQuad || m_eDecalType == eDecalType_OS_OwnersVerticesUsed)
{
assert(m_ownerInfo.pRenderNode);
if (m_ownerInfo.pRenderNode)
{
Matrix34A objMat;
if (IStatObj* pEntObject = m_ownerInfo.GetOwner(objMat))
{
vPos = objMat.TransformPoint(vPos);
}
}
}
}
return vPos;
}
void CDecal::Render(const float fCurTime, int nAfterWater, float fDistanceFading, float fDistance, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter)
{
FUNCTION_PROFILER_3DENGINE;
if (!m_pMaterial || !m_pMaterial->GetShaderItem().m_pShader || m_pMaterial->GetShaderItem().m_pShader->GetShaderType() != eST_General)
{
return; // shader not supported for decals
}
// Get decal alpha from life time
float fAlpha = m_fLifeTime * 2;
if (fAlpha > 1.f)
{
fAlpha = 1.f;
}
else if (fAlpha < 0)
{
return;
}
fAlpha *= fDistanceFading;
float fSizeK;
if (m_fGrowTime)
{
fSizeK = min(1.f, sqrt_tpl((fCurTime - m_fLifeBeginTime) / m_fGrowTime));
}
else
{
fSizeK = 1.f;
}
float fSizeAlphaK;
if (m_fGrowTimeAlpha)
{
fSizeAlphaK = min(1.f, sqrt_tpl((fCurTime - m_fLifeBeginTime) / m_fGrowTimeAlpha));
}
else
{
fSizeAlphaK = 1.f;
}
if (m_bDeferred)
{
SDeferredDecal newItem;
newItem.fAlpha = fAlpha;
newItem.pMaterial = m_pMaterial;
newItem.nSortOrder = m_sortPrio;
newItem.nFlags = 0;
Vec3 vRight, vUp, vNorm;
Matrix34A objMat;
if (IStatObj* pEntObject = m_ownerInfo.GetOwner(objMat))
{
vRight = objMat.TransformVector(m_vRight * m_fSize);
vUp = objMat.TransformVector(m_vUp * m_fSize);
vNorm = objMat.TransformVector((Vec3(m_vRight).Cross(m_vUp)) * m_fSize);
}
else
{
vRight = (m_vRight * m_fSize);
vUp = (m_vUp * m_fSize);
vNorm = ((Vec3(m_vRight).Cross(m_vUp)) * m_fSize);
}
Matrix33 matRotation;
matRotation.SetColumn(0, vRight);
matRotation.SetColumn(1, vUp);
matRotation.SetColumn(2, vNorm * GetFloatCVar(e_DecalsDefferedDynamicDepthScale));
newItem.projMatrix.SetRotation33(matRotation);
newItem.projMatrix.SetTranslation(m_vWSPos + vNorm * .1f * m_fWSSize);
if (m_fGrowTimeAlpha)
{
newItem.fGrowAlphaRef = max(.02f, 1.f - fSizeAlphaK);
}
else
{
newItem.fGrowAlphaRef = 0;
}
GetRenderer()->EF_AddDeferredDecal(newItem);
return;
}
switch (m_eDecalType)
{
case eDecalType_WS_Merged:
case eDecalType_OS_OwnersVerticesUsed:
{
// check if owner mesh was deleted
if (m_pRenderMesh && (m_pRenderMesh->GetVertexContainer() == m_pRenderMesh) && m_pRenderMesh->GetVerticesCount() < 3)
{
FreeRenderData();
}
if (!m_pRenderMesh)
{
break;
}
// setup transformation
CRenderObject* pObj = GetRenderer()->EF_GetObject_Temp(passInfo.ThreadID());
if (!pObj)
{
return;
}
pObj->m_fSort = 0;
pObj->m_RState = 0;
Matrix34A objMat;
if (m_ownerInfo.pRenderNode && !m_ownerInfo.GetOwner(objMat))
{
assert(0);
return;
}
else
if (!m_ownerInfo.pRenderNode)
{
objMat.SetIdentity();
if (m_eDecalType == eDecalType_WS_Merged)
{
objMat.SetTranslation(m_vPos);
}
}
pObj->m_II.m_Matrix = objMat;
pObj->m_nSort = m_sortPrio;
// somehow it's need's to be twice bigger to be same as simple decals
float fSize2 = m_fSize * fSizeK * 2.f; ///m_ownerInfo.pRenderNode->GetScale();
if (fSize2 < 0.0001f)
{
return;
}
// setup texgen
// S component
float correctScale(-1);
m_arrBigDecalRMCustomData[0] = correctScale * m_vUp.x / fSize2;
m_arrBigDecalRMCustomData[1] = correctScale * m_vUp.y / fSize2;
m_arrBigDecalRMCustomData[2] = correctScale * m_vUp.z / fSize2;
Vec3 vPosDecS = m_vPos;
if (m_eDecalType == eDecalType_WS_Merged)
{
vPosDecS.zero();
}
float D0 =
m_arrBigDecalRMCustomData[0] * vPosDecS.x +
m_arrBigDecalRMCustomData[1] * vPosDecS.y +
m_arrBigDecalRMCustomData[2] * vPosDecS.z;
m_arrBigDecalRMCustomData[3] = -D0 + 0.5f;
// T component
m_arrBigDecalRMCustomData[4] = m_vRight.x / fSize2;
m_arrBigDecalRMCustomData[5] = m_vRight.y / fSize2;
m_arrBigDecalRMCustomData[6] = m_vRight.z / fSize2;
float D1 =
m_arrBigDecalRMCustomData[4] * vPosDecS.x +
m_arrBigDecalRMCustomData[5] * vPosDecS.y +
m_arrBigDecalRMCustomData[6] * vPosDecS.z;
m_arrBigDecalRMCustomData[7] = -D1 + 0.5f;
// pass attenuation info
m_arrBigDecalRMCustomData[8] = vPosDecS.x;
m_arrBigDecalRMCustomData[9] = vPosDecS.y;
m_arrBigDecalRMCustomData[10] = vPosDecS.z;
m_arrBigDecalRMCustomData[11] = m_fSize;
// N component
Vec3 vNormal(Vec3(correctScale* m_vUp).Cross(m_vRight).GetNormalized());
m_arrBigDecalRMCustomData[12] = vNormal.x * (m_fSize / m_fWSSize);
m_arrBigDecalRMCustomData[13] = vNormal.y * (m_fSize / m_fWSSize);
m_arrBigDecalRMCustomData[14] = vNormal.z * (m_fSize / m_fWSSize);
m_arrBigDecalRMCustomData[15] = 0;
// draw complex decal using new indices and original object vertices
pObj->m_fAlpha = fAlpha;
pObj->m_ObjFlags |= FOB_DECAL | FOB_DECAL_TEXGEN_2D;
pObj->m_nTextureID = -1;
//pObj->m_nTextureID1 = -1;
pObj->m_II.m_AmbColor = m_vAmbient;
m_pRenderMesh->SetREUserData(m_arrBigDecalRMCustomData, 0, fAlpha);
m_pRenderMesh->AddRenderElements(m_pMaterial, pObj, passInfo, EFSLIST_GENERAL, nAfterWater);
}
break;
case eDecalType_OS_SimpleQuad:
{
assert(m_ownerInfo.pRenderNode);
if (!m_ownerInfo.pRenderNode)
{
break;
}
// transform decal in software from owner space into world space and render as quad
Matrix34A objMat;
IStatObj* pEntObject = m_ownerInfo.GetOwner(objMat);
if (!pEntObject)
{
break;
}
Vec3 vPos = objMat.TransformPoint(m_vPos);
Vec3 vRight = objMat.TransformVector(m_vRight * m_fSize);
Vec3 vUp = objMat.TransformVector(m_vUp * m_fSize);
UCol uCol;
uCol.dcolor = 0xffffffff;
uCol.bcolor[3] = fastround_positive(fAlpha * 255);
GetObjManager()->AddDecalToRenderer(fDistance, m_pMaterial, m_sortPrio, vRight * fSizeK, vUp * fSizeK, uCol,
OS_ALPHA_BLEND, m_vAmbient, vPos, nAfterWater, passInfo, rendItemSorter);
}
break;
case eDecalType_WS_SimpleQuad:
{ // draw small world space decal untransformed
UCol uCol;
uCol.dcolor = 0;
uCol.bcolor[3] = fastround_positive(fAlpha * 255);
GetObjManager()->AddDecalToRenderer(fDistance, m_pMaterial, m_sortPrio, m_vRight * m_fSize * fSizeK,
m_vUp * m_fSize * fSizeK, uCol, OS_ALPHA_BLEND, m_vAmbient, m_vPos, nAfterWater, passInfo,
rendItemSorter);
}
break;
case eDecalType_WS_OnTheGround:
{
RenderBigDecalOnTerrain(fAlpha, fSizeK, passInfo);
}
break;
}
}
void CDecal::FreeRenderData()
{
// delete render mesh
m_pRenderMesh = NULL;
m_ownerInfo.pRenderNode = 0;
}
void CDecal::RenderBigDecalOnTerrain(float fAlpha, float fScale, const SRenderingPassInfo& passInfo)
{
float fRadius = m_fSize * fScale;
// check terrain bounds
if (m_vPos.x < -fRadius || m_vPos.y < -fRadius)
{
return;
}
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
if (!terrain)
{
return;
}
const AZ::Aabb terrainAabb = terrain->GetTerrainAabb();
const float terrainSizeX = terrainAabb.GetXExtent();
const float terrainSizeY = terrainAabb.GetYExtent();
if (m_vPos.x >= terrainSizeX + fRadius || m_vPos.y >= terrainSizeY + fRadius)
{
return;
}
const AZ::Vector2 terrainGridResolution = terrain->GetTerrainGridResolution();
const int nUsintSize = static_cast<int>(AZ::GetMax(terrainGridResolution.GetX(), terrainGridResolution.GetY()));
fRadius += nUsintSize;
const float terrainHeight = terrain->GetHeightFromFloats(m_vPos.x, m_vPos.y, AzFramework::Terrain::TerrainDataRequests::Sampler::CLAMP);
if (fabs(m_vPos.z - terrainHeight) > fRadius)
{
return; // too far from ground surface
}
// setup texgen
float fSize = m_fSize * fScale;
if (fSize < 0.05f)
{
return;
}
// m_vUp and m_vRight are the scaled binormal and tangent
// The shader projects the vertex pass position onto these to calculate UVs
// However binormal and tangent are only half the height and width of the decal
// So we need to double them
Vec3 uvUp = m_vUp * 2.0f;
Vec3 uvRight = m_vRight * 2.0f;
// Let T denote the tangent, B the binormal and P the vertex position in decal space
// The shader calculates UVs by projecting vertex position onto the tangent and binormal:
// U = dot( T, P )
// V = dot( B, P )
// UVs should range 0...1, so normalize by the length of the tangent and binormal:
// U = dot( normalize(T), P / length(T) )
// V = dot( normalize(B), P / length(B) )
// This is equivalent to:
// U = dot( T, P ) / ( length(T) * length(T) )
// V = dot( B, P ) / ( length(B) * length(B) )
// The length squared can be folded into the tangent and binormal:
// U = dot( T / lengthSq(T), P )
// V = dot( B / lengthSq(B), P )
// Hence:
uvUp /= uvUp.GetLengthSquared();
uvRight /= uvRight.GetLengthSquared();
// S component
float correctScale(-1);
m_arrBigDecalRMCustomData[0] = correctScale * uvUp.x / fSize;
m_arrBigDecalRMCustomData[1] = correctScale * uvUp.y / fSize;
m_arrBigDecalRMCustomData[2] = correctScale * uvUp.z / fSize;
// T component
m_arrBigDecalRMCustomData[4] = uvRight.x / fSize;
m_arrBigDecalRMCustomData[5] = uvRight.y / fSize;
m_arrBigDecalRMCustomData[6] = uvRight.z / fSize;
// UV centering happens in the shader
// See shader function _TCModifyDecal
m_arrBigDecalRMCustomData[3] = 0.0f;
m_arrBigDecalRMCustomData[7] = 0.0f;
// pass attenuation info
m_arrBigDecalRMCustomData[8] = 0;
m_arrBigDecalRMCustomData[9] = 0;
m_arrBigDecalRMCustomData[10] = 0;
m_arrBigDecalRMCustomData[11] = fSize * 2.0f;
Vec3 vNormal(Vec3(correctScale* m_vUp).Cross(m_vRight).GetNormalized());
m_arrBigDecalRMCustomData[12] = vNormal.x;
m_arrBigDecalRMCustomData[13] = vNormal.y;
m_arrBigDecalRMCustomData[14] = vNormal.z;
m_arrBigDecalRMCustomData[15] = 0;
CRenderObject* pObj = GetIdentityCRenderObject(passInfo.ThreadID());
if (!pObj)
{
return;
}
pObj->m_II.m_Matrix.SetTranslation(m_vPos);
pObj->m_fAlpha = fAlpha;
pObj->m_ObjFlags |= FOB_DECAL | FOB_DECAL_TEXGEN_2D;
pObj->m_nTextureID = -1;
//pObj->m_nTextureID1 = -1;
pObj->m_II.m_AmbColor = m_vAmbient;
pObj->m_nSort = m_sortPrio;
Plane planes[4];
planes[0].SetPlane(m_vRight, m_vRight * m_fSize + m_vPos);
planes[1].SetPlane(-m_vRight, -m_vRight * m_fSize + m_vPos);
planes[2].SetPlane(m_vUp, m_vUp * m_fSize + m_vPos);
planes[3].SetPlane(-m_vUp, -m_vUp * m_fSize + m_vPos);
}
File diff suppressed because it is too large Load Diff
-159
View File
@@ -1,159 +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_DECALMANAGER_H
#define CRYINCLUDE_CRY3DENGINE_DECALMANAGER_H
#pragma once
#define DECAL_COUNT (512) // must be pow2
#define ENTITY_DECAL_DIST_FACTOR (200)
#define DIST_FADING_FACTOR (6.f)
class C3DEngine;
enum EDecal_Type
{
eDecalType_Undefined,
eDecalType_OS_OwnersVerticesUsed,
eDecalType_WS_Merged,
eDecalType_WS_OnTheGround,
eDecalType_WS_SimpleQuad,
eDecalType_OS_SimpleQuad
};
class CDecal
: public Cry3DEngineBase
{
public:
// cur state
Vec3 m_vPos;
Vec3 m_vRight, m_vUp, m_vFront;
float m_fSize;
Vec3 m_vWSPos; // Decal position (world coordinates) from DecalInfo.vPos
float m_fWSSize; // Decal size (world coordinates) from DecalInfo.fSize
// life style
float m_fLifeTime; // relative time left till decal should die
Vec3 m_vAmbient; // ambient color
SDecalOwnerInfo m_ownerInfo;
EDecal_Type m_eDecalType;
float m_fGrowTime, m_fGrowTimeAlpha; // e.g. growing blood pools
float m_fLifeBeginTime; //
uint8 m_iAssembleSize; // of how many decals has this decal be assembled, 0 if not to assemble
uint8 m_sortPrio;
uint8 m_bDeferred;
// render data
_smart_ptr<IRenderMesh> m_pRenderMesh; // only needed for terrain decals, 4 of them because they might cross borders
float m_arrBigDecalRMCustomData[16]; // only needed if one of m_arrBigDecalRMs[]!=0, most likely we can reduce to [12]
_smart_ptr< IMaterial > m_pMaterial;
uint32 m_nGroupId; // used for multi-component decals
#ifdef _DEBUG
char m_decalOwnerEntityClassName[256];
char m_decalOwnerName[256];
EERType m_decalOwnerType;
#endif
CDecal()
: m_vPos(0, 0, 0)
, m_vRight(0, 0, 0)
, m_vUp(0, 0, 0)
, m_vFront(0, 0, 0)
, m_fSize(0)
, m_vWSPos(0, 0, 0)
, m_fWSSize(0)
, m_fLifeTime(0)
, m_vAmbient(0, 0, 0)
, m_fGrowTime(0)
, m_fGrowTimeAlpha(0)
, m_fLifeBeginTime(0)
, m_sortPrio(0)
, m_pMaterial(0)
, m_nGroupId(0)
, m_iAssembleSize(0)
, m_bDeferred(0)
{
m_eDecalType = eDecalType_Undefined;
m_pRenderMesh = NULL;
memset(&m_arrBigDecalRMCustomData[0], 0, sizeof(m_arrBigDecalRMCustomData));
#ifdef _DEBUG
m_decalOwnerEntityClassName[0] = '\0';
m_decalOwnerName[0] = '\0';
m_decalOwnerType = eERType_NotRenderNode;
#endif
}
~CDecal()
{
FreeRenderData();
}
void Render(const float fFrameTime, int nAfterWater, float fDistanceFading, float fDiatance, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter);
int Update(bool& active, const float fFrameTime);
void RenderBigDecalOnTerrain(float fAlpha, float fScale, const SRenderingPassInfo& passInfo);
void FreeRenderData();
static void ResetStaticData();
bool IsBigDecalUsed() const { return m_pRenderMesh != 0; }
Vec3 GetWorldPosition();
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
private:
static IGeometry* s_pSphere;
};
class CDecalManager
: public Cry3DEngineBase
{
CDecal m_arrDecals[DECAL_COUNT];
bool m_arrbActiveDecals[DECAL_COUNT];
int m_nCurDecal;
PodArray<IRenderNode*> m_arrTempUpdatedOwners;
public: // ---------------------------------------------------------------
CDecalManager();
~CDecalManager();
bool Spawn(CryEngineDecalInfo Decal, CDecal* pCallerManagedDecal = 0);
// once per frame
void Update(const float fFrameTime);
// maybe multiple times per frame
void Render(const SRenderingPassInfo& passInfo);
void OnEntityDeleted(IRenderNode* pEnt);
void OnRenderMeshDeleted(IRenderMesh* pRenderMesh);
// complex decals
void FillBigDecalIndices(IRenderMesh* pRenderMesh, Vec3 vPos, float fRadius, Vec3 vProjDir, PodArray<vtx_idx>* plstIndices, _smart_ptr<IMaterial> pMat, AABB& meshBBox, float& texelAreaDensity);
_smart_ptr<IRenderMesh> MakeBigDecalRenderMesh(IRenderMesh* pSourceRenderMesh, Vec3 vPos, float fRadius, Vec3 vProjDir, _smart_ptr<IMaterial> pDecalMat, _smart_ptr<IMaterial> pSrcMat);
void MoveToEdge(IRenderMesh* pRM, const float fRadius, Vec3& vPos, Vec3& vOutNorm, const Vec3& vTri0, const Vec3& vTri1, const Vec3& vTri2);
void GetMemoryUsage(ICrySizer* pSizer) const;
void Reset() { memset(m_arrbActiveDecals, 0, sizeof(m_arrbActiveDecals)); m_nCurDecal = 0; }
void DeleteDecalsInRange(AABB* pAreaBox, IRenderNode* pEntity);
bool AdjustDecalPosition(CryEngineDecalInfo& DecalInfo, bool bMakeFatTest);
static bool RayRenderMeshIntersection(IRenderMesh* pRenderMesh, const Vec3& vInPos, const Vec3& vInDir, Vec3& vOutPos, Vec3& vOutNormal, bool bFastTest, float fMaxHitDistance, _smart_ptr<IMaterial> pMat);
void Serialize(TSerialize ser);
bool SpawnHierarchical(const CryEngineDecalInfo& rootDecalInfo, CDecal* pCallerManagedDecal);
private:
_smart_ptr<IMaterial> GetMaterialForDecalTexture(const char* pTextureName);
};
#endif // CRYINCLUDE_CRY3DENGINE_DECALMANAGER_H
@@ -1,469 +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 "DecalRenderNode.h"
#include "VisAreas.h"
#include "ObjMan.h"
#include "MatMan.h"
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
#include "Environment/OceanEnvironmentBus.h"
int CDecalRenderNode::m_nFillBigDecalIndicesCounter = 0;
CDecalRenderNode::CDecalRenderNode()
: m_pos(0, 0, 0)
, m_localBounds(Vec3(-1, -1, -1), Vec3(1, 1, 1))
, m_pMaterial(NULL)
, m_updateRequested(false)
, m_decalProperties()
, m_decal(nullptr)
, m_nLastRenderedFrameId(0)
, m_nLayerId(0)
{
m_Matrix.SetIdentity();
}
CDecalRenderNode::~CDecalRenderNode()
{
DeleteDecal();
GetISystem()->GetI3DEngine()->FreeRenderNodeState(this);
}
const SDecalProperties* CDecalRenderNode::GetDecalProperties() const
{
return &m_decalProperties;
}
void CDecalRenderNode::DeleteDecal()
{
if (m_decal)
{
delete m_decal;
m_decal = nullptr;
}
}
void CDecalRenderNode::SetCommonProperties(CryEngineDecalInfo& decalInfo)
{
decalInfo.fSize = m_decalProperties.m_radius;
decalInfo.pExplicitRightUpFront = &m_decalProperties.m_explicitRightUpFront;
decalInfo.sortPrio = m_decalProperties.m_sortPrio;
decalInfo.pIStatObj = nullptr;
decalInfo.ownerInfo.pRenderNode = nullptr;
decalInfo.fLifeTime = 1.0f; // default life time for rendering, decal won't grow older as we don't update it
decalInfo.fGrowTime = 0.0f;
decalInfo.fAngle = 0.0f;
// We don't set decalInfo.szMaterialName here because that is handled in CDecalRenderNode::CreateDecal()
}
void CDecalRenderNode::CreatePlanarDecal()
{
CryEngineDecalInfo decalInfo;
SetCommonProperties(decalInfo);
// necessary params
decalInfo.vPos = m_decalProperties.m_pos;
decalInfo.vNormal = m_decalProperties.m_normal;
// default for all other
decalInfo.vHitDirection = Vec3(0, 0, 0);
decalInfo.preventDecalOnGround = true;
CreateDecal(decalInfo);
}
void CDecalRenderNode::CreateDecalOnTerrain()
{
bool terrainExists = false;
float terrainHeight = AZ::Constants::FloatMax;
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(terrainHeight
, &AzFramework::Terrain::TerrainDataRequests::GetHeightFromFloats
, m_decalProperties.m_pos.x, m_decalProperties.m_pos.y, AzFramework::Terrain::TerrainDataRequests::Sampler::BILINEAR, &terrainExists);
if (!terrainExists)
{
//No terrain system available, or there's a hole at the given location.
return;
}
float terrainDelta(m_decalProperties.m_pos.z - terrainHeight);
if (terrainDelta < m_decalProperties.m_radius && terrainDelta > -0.5f)
{
CryEngineDecalInfo decalInfo;
SetCommonProperties(decalInfo);
// necessary params
decalInfo.vPos = Vec3(m_decalProperties.m_pos.x, m_decalProperties.m_pos.y, terrainHeight);
decalInfo.vNormal = Vec3(0, 0, 1);
decalInfo.vHitDirection = Vec3(0, 0, -1);
decalInfo.preventDecalOnGround = false;
CreateDecal(decalInfo);
}
}
void CDecalRenderNode::CreateDecal(const CryEngineDecalInfo& decalInfo)
{
m_decal = new CDecal();
if (m_p3DEngine->CreateDecalInstance(decalInfo, m_decal))
{
// Rather than setting decalInfo.szMaterialName in SetCommonProperties(), it's better to set IMaterial directly since we already have the desired material.
// This is more reliable than using the material name. For example, if the material was cloned from another one it would have the same name
// as the original, and CreateDecalInstance() would load the original from disk rather than the clone.
m_decal->m_pMaterial = m_pMaterial;
}
else
{
DeleteDecal();
}
}
void CDecalRenderNode::CreateDecals()
{
DeleteDecal();
if (m_decalProperties.m_deferred)
{
return;
}
_smart_ptr<IMaterial> pMaterial(GetMaterial());
assert(0 != pMaterial && "CDecalRenderNode::CreateDecals() -- Invalid Material!");
if (!pMaterial)
{
return;
}
switch (m_decalProperties.m_projectionType)
{
case SDecalProperties::ePlanar:
{
CreatePlanarDecal();
break;
}
case SDecalProperties::eProjectOnTerrain:
{
CreateDecalOnTerrain();
break;
}
default:
{
assert(!"CDecalRenderNode::CreateDecals() : Unsupported decal projection type!");
break;
}
}
}
void CDecalRenderNode::ProcessUpdateRequest()
{
if (!m_updateRequested || m_nFillBigDecalIndicesCounter >= GetCVars()->e_DecalsMaxUpdatesPerFrame)
{
return;
}
CreateDecals();
m_updateRequested = false;
}
void CDecalRenderNode::UpdateAABBFromRenderMeshes()
{
if (m_decalProperties.m_projectionType == SDecalProperties::eProjectOnTerrain)
{
AABB WSBBox;
WSBBox.Reset();
if (m_decal && m_decal->m_pRenderMesh && m_decal->m_eDecalType != eDecalType_OS_OwnersVerticesUsed)
{
AABB aabb;
m_decal->m_pRenderMesh->GetBBox(aabb.min, aabb.max);
if (m_decal->m_eDecalType == eDecalType_WS_Merged || m_decal->m_eDecalType == eDecalType_WS_OnTheGround)
{
aabb.min += m_decal->m_vPos;
aabb.max += m_decal->m_vPos;
}
WSBBox.Add(aabb);
}
if (!WSBBox.IsReset())
{
m_WSBBox = WSBBox;
}
}
}
//special check for def decals forcing
bool CDecalRenderNode::CheckForceDeferred()
{
if (m_pMaterial != NULL)
{
SShaderItem& sItem = m_pMaterial->GetShaderItem(0);
if (sItem.m_pShaderResources != NULL)
{
float fCosA = m_decalProperties.m_normal.GetNormalized().Dot(Vec3(0, 0, 1));
if (fCosA > 0.5f)
{
return false;
}
if (SEfResTexture* pEnvRes0 = sItem.m_pShaderResources->GetTextureResource(EFTT_ENV))
{
if (pEnvRes0->m_Sampler.m_pITex == NULL)
{
m_decalProperties.m_projectionType = SDecalProperties::ePlanar;
m_decalProperties.m_deferred = true;
return true;
}
}
else
{
m_decalProperties.m_projectionType = SDecalProperties::ePlanar;
m_decalProperties.m_deferred = true;
return true;
}
}
}
return false;
}
void CDecalRenderNode::SetDecalProperties(const SDecalProperties& properties)
{
// update bounds
m_localBounds = AABB(-properties.m_radius * Vec3(1, 1, 1), properties.m_radius * Vec3(1, 1, 1));
// register material
m_pMaterial = GetMatMan()->LoadMaterial(properties.m_pMaterialName, false);
// copy decal properties
m_decalProperties = properties;
m_decalProperties.m_pMaterialName = 0; // reset this as it's assumed to be a temporary pointer only, refer to m_materialID to get material
// request update
m_updateRequested = true;
bool bForced = 0;
if (properties.m_deferred || (GetCVars()->e_DecalsDefferedStatic && (m_decalProperties.m_projectionType != SDecalProperties::ePlanar && m_decalProperties.m_projectionType != SDecalProperties::eProjectOnTerrain)))
{
m_decalProperties.m_deferred = true;
}
if (GetCVars()->e_DecalsForceDeferred)
{
if (CheckForceDeferred())
{
bForced = true;
}
}
// set normal just in case; normal direction will be determined by m_explicitRightUpFront
m_decalProperties.m_normal = properties.m_normal;
m_fWSMaxViewDist = properties.m_maxViewDist;
// set matrix
m_Matrix.SetRotation33(m_decalProperties.m_explicitRightUpFront);
Matrix33 matScale;
if (bForced && !properties.m_deferred)
{
matScale.SetScale(Vec3(properties.m_radius, properties.m_radius, properties.m_radius * 0.05f));
}
else
{
matScale.SetScale(Vec3(properties.m_radius, properties.m_radius, properties.m_radius * properties.m_depth));
}
m_Matrix = m_Matrix * matScale;
m_Matrix.SetTranslation(properties.m_pos);
}
IRenderNode* CDecalRenderNode::Clone() const
{
CDecalRenderNode* pDestDecal = new CDecalRenderNode();
// CDecalRenderNode member vars
pDestDecal->m_pos = m_pos;
pDestDecal->m_localBounds = m_localBounds;
pDestDecal->m_pMaterial = m_pMaterial;
pDestDecal->m_updateRequested = true;
pDestDecal->m_decalProperties = m_decalProperties;
pDestDecal->m_WSBBox = m_WSBBox;
pDestDecal->m_Matrix = m_Matrix;
pDestDecal->m_nLayerId = m_nLayerId;
//IRenderNode member vars
// We cannot just copy over due to issues with the linked list of IRenderNode objects
CopyIRenderNodeData(pDestDecal);
return pDestDecal;
}
void CDecalRenderNode::SetMatrix(const Matrix34& mat)
{
m_pos = mat.GetTranslation();
if (m_decalProperties.m_projectionType == SDecalProperties::ePlanar)
{
m_WSBBox.SetTransformedAABB(m_Matrix, AABB(-Vec3(1, 1, 0.5f), Vec3(1, 1, 0.5f)));
}
else
{
m_WSBBox.SetTransformedAABB(m_Matrix, AABB(-Vec3(1, 1, 1), Vec3(1, 1, 1)));
}
Get3DEngine()->RegisterEntity(this);
}
void CDecalRenderNode::SetMatrixFull(const Matrix34& mat)
{
m_Matrix = mat;
m_pos = mat.GetTranslation();
if (m_decalProperties.m_projectionType == SDecalProperties::ePlanar)
{
m_WSBBox.SetTransformedAABB(m_Matrix, AABB(-Vec3(1, 1, 0.5f), Vec3(1, 1, 0.5f)));
}
else
{
m_WSBBox.SetTransformedAABB(m_Matrix, AABB(-Vec3(1, 1, 1), Vec3(1, 1, 1)));
}
}
const char* CDecalRenderNode::GetEntityClassName() const
{
return "Decal";
}
const char* CDecalRenderNode::GetName() const
{
return "Decal";
}
void CDecalRenderNode::Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE;
if (!passInfo.RenderDecals())
{
return; // false;
}
float distFading = SATURATE((1.f - rParam.fDistance / m_fWSMaxViewDist) * DIST_FADING_FACTOR);
if (m_decalProperties.m_deferred)
{
if (passInfo.IsShadowPass())
{
return; // otherwise causing flickering with GI
}
SDeferredDecal newItem;
newItem.fAlpha = m_decalProperties.m_opacity;
newItem.angleAttenuation = m_decalProperties.m_angleAttenuation;
newItem.pMaterial = m_pMaterial;
newItem.projMatrix = m_Matrix;
newItem.nSortOrder = m_decalProperties.m_sortPrio;
newItem.nFlags = DECAL_STATIC;
GetRenderer()->EF_AddDeferredDecal(newItem);
return;
}
// update last rendered frame id
m_nLastRenderedFrameId = passInfo.GetMainFrameID();
bool bUpdateAABB = m_updateRequested;
if (passInfo.IsGeneralPass())
{
ProcessUpdateRequest();
}
if (m_decal && 0 != m_decal->m_pMaterial)
{
m_decal->m_vAmbient.x = rParam.AmbientColor.r;
m_decal->m_vAmbient.y = rParam.AmbientColor.g;
m_decal->m_vAmbient.z = rParam.AmbientColor.b;
bool bAfterWater = GetObjManager()->IsAfterWater(m_decal->m_vWSPos, passInfo);
m_decal->Render(0, bAfterWater, distFading, rParam.fDistance, passInfo, SRendItemSorter(rParam.rendItemSorter));
}
// terrain decal meshes are created only during rendering so only after that bbox can be computed
if (bUpdateAABB)
{
UpdateAABBFromRenderMeshes();
}
}
void CDecalRenderNode::SetMaterial(_smart_ptr<IMaterial> pMat)
{
if (m_decal)
{
m_decal->m_pMaterial = pMat;
}
m_pMaterial = pMat;
//special check for def decals forcing
if (GetCVars()->e_DecalsForceDeferred)
{
CheckForceDeferred();
}
}
void CDecalRenderNode::Precache()
{
ProcessUpdateRequest();
}
void CDecalRenderNode::GetMemoryUsage(ICrySizer* pSizer) const
{
SIZER_COMPONENT_NAME(pSizer, "DecalNode");
pSizer->AddObject(this, sizeof(*this));
pSizer->AddObject(m_decal);
}
void CDecalRenderNode::CleanUpOldDecals()
{
if (m_nLastRenderedFrameId != 0 && // was rendered at least once
(int)GetRenderer()->GetFrameID(false) > (int)m_nLastRenderedFrameId + GetCVars()->e_DecalsMaxValidFrames)
{
DeleteDecal();
m_nLastRenderedFrameId = 0;
m_updateRequested = true; // make sure if rendered again, that the decal is recreated
}
}
void CDecalRenderNode::OffsetPosition(const Vec3& delta)
{
if (m_pRNTmpData)
{
m_pRNTmpData->OffsetPosition(delta);
}
m_pos += delta;
m_WSBBox.Move(delta);
m_Matrix.SetTranslation(m_Matrix.GetTranslation() + delta);
}
@@ -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_DECALRENDERNODE_H
#define CRYINCLUDE_CRY3DENGINE_DECALRENDERNODE_H
#pragma once
#include "DecalManager.h"
class CDecalRenderNode
: public IDecalRenderNode
, public Cry3DEngineBase
{
public:
// implements IDecalRenderNode
virtual void SetDecalProperties(const SDecalProperties& properties);
virtual const SDecalProperties* GetDecalProperties() const;
virtual void CleanUpOldDecals();
// implements IRenderNode
virtual IRenderNode* Clone() const;
virtual void SetMatrix(const Matrix34& mat);
virtual const Matrix34& GetMatrix() { return m_Matrix; }
virtual EERType GetRenderNodeType();
virtual const char* GetEntityClassName() const;
virtual const char* GetName() const;
virtual Vec3 GetPos(bool bWorldOnly = true) const;
virtual void Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo);
void SetMaterial(_smart_ptr<IMaterial> pMat) override;
virtual _smart_ptr<IMaterial> GetMaterial(Vec3* pHitPos = 0);
virtual _smart_ptr<IMaterial> GetMaterialOverride() { return m_pMaterial; }
virtual float GetMaxViewDist();
virtual void Precache();
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
virtual const AABB GetBBox() const { return m_WSBBox; }
virtual void SetBBox(const AABB& WSBBox) { m_WSBBox = WSBBox; }
virtual void FillBBox(AABB& aabb);
virtual void OffsetPosition(const Vec3& delta);
virtual uint8 GetSortPriority() { return m_decalProperties.m_sortPrio; }
virtual void SetLayerId(uint16 nLayerId) { m_nLayerId = nLayerId; }
virtual uint16 GetLayerId() { return m_nLayerId; }
static void ResetDecalUpdatesCounter() { CDecalRenderNode::m_nFillBigDecalIndicesCounter = 0; }
// SetMatrix only supports changing position, this will do the full transform
void SetMatrixFull(const Matrix34& mat);
public:
CDecalRenderNode();
void RequestUpdate() { m_updateRequested = true; DeleteDecal(); }
void DeleteDecal();
private:
~CDecalRenderNode();
void CreateDecals();
void ProcessUpdateRequest();
void UpdateAABBFromRenderMeshes();
bool CheckForceDeferred();
void SetCommonProperties(CryEngineDecalInfo& decalInfo);
void CreatePlanarDecal();
void CreateDecalOnTerrain();
void CreateDecal(const CryEngineDecalInfo& decalInfo);
private:
Vec3 m_pos;
AABB m_localBounds;
_smart_ptr<IMaterial> m_pMaterial;
bool m_updateRequested;
SDecalProperties m_decalProperties;
CDecal* m_decal;
AABB m_WSBBox;
Matrix34 m_Matrix;
uint32 m_nLastRenderedFrameId;
uint16 m_nLayerId;
public:
static int m_nFillBigDecalIndicesCounter;
};
#endif // CRYINCLUDE_CRY3DENGINE_DECALRENDERNODE_H
@@ -1,226 +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 "DeferredCollisionEvent.h"
CDeferredPhysicsEventManager::CDeferredPhysicsEventManager()
: m_hThreadPool(-1)
, m_bEntitySystemReset(false)
{
if (gEnv->IsDedicated())
{
return;
}
// Disable MT if Editor.
if (gEnv->IsEditor())
{
return;
}
ThreadPoolDesc threadPoolDesc;
threadPoolDesc.sPoolName = "DeferredPhysicsEvents";
threadPoolDesc.nThreadStackSizeKB = 24;
// let the DeferredPhysicsEvents run on Core3
if (!threadPoolDesc.CreateThread(BIT(3)))
{
return;
}
IThreadTaskManager* pThreadTaskManager = gEnv->pSystem->GetIThreadTaskManager();
assert(pThreadTaskManager);
m_hThreadPool = pThreadTaskManager->CreateThreadsPool(threadPoolDesc);
}
CDeferredPhysicsEventManager::~CDeferredPhysicsEventManager()
{
}
void CDeferredPhysicsEventManager::DispatchDeferredEvent(IDeferredPhysicsEvent* pEvent)
{
assert(pEvent);
// execute immediately if we don't use deferred physcis events
if (GetCVars()->e_DeferredPhysicsEvents == 0 || m_hThreadPool < 0)
{
pEvent->OnUpdate();
return;
}
// Register the task with the ThreadTask manager
IThreadTaskManager* pThreadTaskManager = gEnv->pSystem->GetIThreadTaskManager();
assert(pThreadTaskManager);
pEvent->GetTaskInfo()->m_params.name = "DeferredPhysicsEvents";
pEvent->GetTaskInfo()->m_params.nFlags = THREAD_TASK_ASSIGN_TO_POOL;
pEvent->GetTaskInfo()->m_params.nThreadsGroupId = m_hThreadPool;
pEvent->GetTaskInfo()->m_pThread = NULL;
pThreadTaskManager->RegisterTask(pEvent, pEvent->GetTaskInfo()->m_params);
}
void ApplyCollisionImpulse(EventPhysCollision* pCollision)
{
if (pCollision->normImpulse && pCollision->pEntity[1] &&
pCollision->pEntity[0] && pCollision->pEntity[0]->GetType() == PE_PARTICLE &&
pCollision->pEntity[0]->GetForeignData(pCollision->pEntity[0]->GetiForeignData())) // no foreign data mean it's likely scheduled for deletion
{
pe_action_impulse ai;
ai.point = pCollision->pt;
ai.partid = pCollision->partid[1];
ai.impulse = (pCollision->vloc[0] - pCollision->vloc[1]) * pCollision->normImpulse;
pCollision->pEntity[1]->Action(&ai);
}
}
int CDeferredPhysicsEventManager::HandleEvent(const EventPhys* pEvent, IDeferredPhysicsEventManager::CreateEventFunc pCreateFunc, [[maybe_unused]] IDeferredPhysicsEvent::DeferredEventType type)
{
EventPhysCollision* pCollision = (EventPhysCollision*)pEvent;
assert(pCollision);
if (pCollision->deferredState == EPC_DEFERRED_FINISHED)
{
ApplyCollisionImpulse(pCollision);
return pCollision->deferredResult;
}
// == create new deferred event object, and do some housekeeping(ensuring entities not deleted, remebering event for cleanup) == //
IDeferredPhysicsEvent* pDeferredEvent = pCreateFunc(pEvent);
// == start executing == //
pDeferredEvent->Start();
// == check if we really needed to deferred this event(early outs, not deferred code paths) == //
if (GetCVars()->e_DeferredPhysicsEvents == 0 || pDeferredEvent->HasFinished())
{
int nResult = pDeferredEvent->Result((EventPhys*)pEvent);
SAFE_DELETE(pDeferredEvent);
ApplyCollisionImpulse(pCollision);
return nResult;
}
if (pCollision->pEntity[0])
{
pCollision->pEntity[0]->AddRef();
}
if (pCollision->pEntity[1])
{
pCollision->pEntity[1]->AddRef();
}
// == re-queue event for the next frame, to keep the physical entity alive == //
RegisterDeferredEvent(pDeferredEvent);
return 0;
}
void CDeferredPhysicsEventManager::RegisterDeferredEvent(IDeferredPhysicsEvent* pDeferredEvent)
{
assert(pDeferredEvent);
m_activeDeferredEvents.push_back(pDeferredEvent);
}
void CDeferredPhysicsEventManager::UnRegisterDeferredEvent(IDeferredPhysicsEvent* pDeferredEvent)
{
std::vector<IDeferredPhysicsEvent*>::iterator it = std::find(m_activeDeferredEvents.begin(), m_activeDeferredEvents.end(), pDeferredEvent);
if (it == m_activeDeferredEvents.end())
{
return;
}
// == remove from active list == //
m_activeDeferredEvents.erase(it);
if (m_bEntitySystemReset)
{
return;
}
// == decrement keep alive counter on entity == //
EventPhysCollision* pCollision = (EventPhysCollision*)pDeferredEvent->PhysicsEvent();
if (pCollision->pEntity[0])
{
pCollision->pEntity[0]->Release();
}
if (pCollision->pEntity[1])
{
pCollision->pEntity[1]->Release();
}
}
void CDeferredPhysicsEventManager::ClearDeferredEvents()
{
// move content of the active deferred events array to a tmp one to prevent provlems with UnRegisterDeferredEvent called by destructors
std::vector<IDeferredPhysicsEvent*> tmp = m_activeDeferredEvents;
m_bEntitySystemReset = true;
for (std::vector<IDeferredPhysicsEvent*>::iterator it = tmp.begin(); it != tmp.end(); ++it)
{
(*it)->Sync();
delete *it;
}
stl::free_container(m_activeDeferredEvents);
m_bEntitySystemReset = false;
}
void CDeferredPhysicsEventManager::Update()
{
std::vector<IDeferredPhysicsEvent*> tmp = m_activeDeferredEvents;
for (std::vector<IDeferredPhysicsEvent*>::iterator it = tmp.begin(), end = tmp.end(); it != end; ++it)
{
IDeferredPhysicsEvent* collisionEvent = *it;
assert(collisionEvent);
PREFAST_ASSUME(collisionEvent);
EventPhysCollision* epc = (EventPhysCollision*) collisionEvent->PhysicsEvent();
if (collisionEvent->HasFinished() == false)
{
continue;
}
epc->deferredResult = collisionEvent->Result();
if (epc->deferredState != EPC_DEFERRED_FINISHED)
{
epc->deferredState = EPC_DEFERRED_FINISHED;
}
else
{
SAFE_DELETE(collisionEvent);
}
}
}
IDeferredPhysicsEvent* CDeferredPhysicsEventManager::GetLastCollisionEventForEntity(IPhysicalEntity* pPhysEnt)
{
EventPhysCollision* pLastPhysEvent;
for (int i = m_activeDeferredEvents.size() - 1; i >= 0; i--)
{
pLastPhysEvent = (EventPhysCollision*)m_activeDeferredEvents[i]->PhysicsEvent();
if (pLastPhysEvent && pLastPhysEvent->idval == EventPhysCollision::id && pLastPhysEvent->pEntity[0] == pPhysEnt)
{
return m_activeDeferredEvents[i];
}
}
return 0;
}
@@ -1,47 +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_DEFERREDCOLLISIONEVENT_H
#define CRYINCLUDE_CRY3DENGINE_DEFERREDCOLLISIONEVENT_H
#pragma once
#include <IDeferredCollisionEvent.h>
// Implementation class for the DeferredPhysicsEvent Manager
class CDeferredPhysicsEventManager
: public IDeferredPhysicsEventManager
, public Cry3DEngineBase
{
public:
CDeferredPhysicsEventManager();
virtual ~CDeferredPhysicsEventManager();
virtual void DispatchDeferredEvent(IDeferredPhysicsEvent* pEvent);
virtual int HandleEvent(const EventPhys* pEvent, IDeferredPhysicsEventManager::CreateEventFunc, IDeferredPhysicsEvent::DeferredEventType);
virtual void RegisterDeferredEvent(IDeferredPhysicsEvent* pDeferredEvent);
virtual void UnRegisterDeferredEvent(IDeferredPhysicsEvent* pDeferredEvent);
virtual void ClearDeferredEvents();
virtual void Update();
virtual IDeferredPhysicsEvent* GetLastCollisionEventForEntity(IPhysicalEntity* pPhysEnt);
private:
ThreadPoolHandle m_hThreadPool; // thread pool to use for deferred event tasks
std::vector<IDeferredPhysicsEvent*> m_activeDeferredEvents; // list of all active deferred events, used for cleanup and statistics
bool m_bEntitySystemReset; // means all entity ptrs in events are stale
};
#endif // CRYINCLUDE_CRY3DENGINE_DEFERREDCOLLISIONEVENT_H
@@ -1,194 +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 "DistanceCloudRenderNode.h"
#include "VisAreas.h"
#include "ObjMan.h"
#include "MatMan.h"
#include "Environment/OceanEnvironmentBus.h"
CDistanceCloudRenderNode::CDistanceCloudRenderNode()
: m_pos(0, 0, 0)
, m_sizeX(1)
, m_sizeY(1)
, m_rotationZ(0)
, m_pMaterial(NULL)
{
}
CDistanceCloudRenderNode::~CDistanceCloudRenderNode()
{
Get3DEngine()->FreeRenderNodeState(this);
}
SDistanceCloudProperties CDistanceCloudRenderNode::GetProperties() const
{
SDistanceCloudProperties properties;
properties.m_sizeX = m_sizeX;
properties.m_sizeY = m_sizeY;
properties.m_rotationZ = m_rotationZ;
properties.m_pos = m_pos;
properties.m_pMaterialName = 0; // query materialID instead!
return properties;
}
void CDistanceCloudRenderNode::SetProperties(const SDistanceCloudProperties& properties)
{
// register material
m_pMaterial = GetMatMan()->LoadMaterial(properties.m_pMaterialName, false);
// copy distance cloud properties
m_sizeX = properties.m_sizeX;
m_sizeY = properties.m_sizeY;
m_rotationZ = properties.m_rotationZ;
m_pos = properties.m_pos;
}
void CDistanceCloudRenderNode::SetMatrix(const Matrix34& mat)
{
Get3DEngine()->UnRegisterEntityAsJob(this);
m_pos = mat.GetTranslation();
m_WSBBox.SetTransformedAABB(mat, AABB(-Vec3(1, 1, 1e-4f), Vec3(1, 1, 1e-4f)));
Get3DEngine()->RegisterEntity(this);
}
const char* CDistanceCloudRenderNode::GetEntityClassName() const
{
return "DistanceCloud";
}
const char* CDistanceCloudRenderNode::GetName() const
{
return "DistanceCloud";
}
static inline uint16 HalfFlip(uint16 h)
{
uint16 mask = -int16(h >> 15) | 0x8000;
return h ^ mask;
}
void CDistanceCloudRenderNode::Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE;
_smart_ptr<IMaterial> pMaterial(GetMaterial());
if (!passInfo.RenderClouds() || !pMaterial)
{
return; // false;
}
CRenderObject* pOb(gEnv->pRenderer->EF_GetObject_Temp(passInfo.ThreadID()));
if (!pOb)
{
return; // false;
}
const CCamera& cam(passInfo.GetCamera());
float zDist = cam.GetPosition().z - m_pos.z;
if (cam.GetViewdir().z < 0)
{
zDist = -zDist;
}
pOb->m_nSort = HalfFlip(CryConvertFloatToHalf(zDist));
//pOb->m_II.m_Matrix.SetIdentity();
// fill general vertex data
f32 sinZ(0), cosZ(1);
sincos_tpl(DEG2RAD(m_rotationZ), &sinZ, &cosZ);
Vec3 right(m_sizeX * cosZ, m_sizeY * sinZ, 0);
Vec3 up(-m_sizeX * sinZ, m_sizeY * cosZ, 0);
SVF_P3F_C4B_T2F pVerts[4];
pVerts[0].xyz = (-right - up) + m_pos;
pVerts[0].st = Vec2(0, 1);
pVerts[0].color.dcolor = ~0;
pVerts[1].xyz = (right - up) + m_pos;
pVerts[1].st = Vec2(1, 1);
pVerts[1].color.dcolor = ~0;
pVerts[2].xyz = (right + up) + m_pos;
pVerts[2].st = Vec2(1, 0);
pVerts[2].color.dcolor = ~0;
pVerts[3].xyz = (-right + up) + m_pos;
pVerts[3].st = Vec2(0, 0);
pVerts[3].color.dcolor = ~0;
// prepare tangent space (tangent, bitangent) and fill it in
Vec3 rightUnit(cosZ, sinZ, 0);
Vec3 upUnit(-sinZ, cosZ, 0);
SPipTangents pTangents[4];
pTangents[0] = SPipTangents(rightUnit, -upUnit, 1);
pTangents[1] = pTangents[0];
pTangents[2] = pTangents[0];
pTangents[3] = pTangents[0];
// prepare indices
uint16 pIndices[6];
pIndices[0] = 0;
pIndices[1] = 1;
pIndices[2] = 2;
pIndices[3] = 0;
pIndices[4] = 2;
pIndices[5] = 3;
int afterWater(GetObjManager()->IsAfterWater(m_pos, passInfo));
GetRenderer()->EF_AddPolygonToScene(pMaterial->GetShaderItem(), 4, pVerts, pTangents, pOb, passInfo, pIndices, 6, afterWater, SRendItemSorter(rParam.rendItemSorter));
// return true;
}
void CDistanceCloudRenderNode::SetMaterial(_smart_ptr<IMaterial> pMat)
{
m_pMaterial = pMat;
}
void CDistanceCloudRenderNode::Precache()
{
}
void CDistanceCloudRenderNode::GetMemoryUsage(ICrySizer* pSizer) const
{
SIZER_COMPONENT_NAME(pSizer, "DistanceCloudNode");
pSizer->AddObject(this, sizeof(*this));
}
void CDistanceCloudRenderNode::OffsetPosition(const Vec3& delta)
{
if (m_pRNTmpData)
{
m_pRNTmpData->OffsetPosition(delta);
}
m_pos += delta;
m_WSBBox.Move(delta);
}
@@ -1,66 +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_DISTANCECLOUDRENDERNODE_H
#define CRYINCLUDE_CRY3DENGINE_DISTANCECLOUDRENDERNODE_H
#pragma once
class CDistanceCloudRenderNode
: public IDistanceCloudRenderNode
, public Cry3DEngineBase
{
public:
// implements IDistanceCloudRenderNode
virtual void SetProperties(const SDistanceCloudProperties& properties);
// implements IRenderNode
virtual void SetMatrix(const Matrix34& mat);
virtual EERType GetRenderNodeType();
virtual const char* GetEntityClassName() const;
virtual const char* GetName() const;
virtual Vec3 GetPos(bool bWorldOnly = true) const;
virtual void Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo);
void SetMaterial(_smart_ptr<IMaterial> pMat) override;
virtual _smart_ptr<IMaterial> GetMaterial(Vec3* pHitPos = 0);
virtual _smart_ptr<IMaterial> GetMaterialOverride() { return m_pMaterial; }
virtual float GetMaxViewDist();
virtual void Precache();
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
virtual const AABB GetBBox() const { return m_WSBBox; }
virtual void SetBBox(const AABB& WSBBox) { m_WSBBox = WSBBox; }
virtual void FillBBox(AABB& aabb);
virtual void OffsetPosition(const Vec3& delta);
virtual void SetLayerId(uint16 nLayerId) { m_nLayerId = nLayerId; }
virtual uint16 GetLayerId() { return m_nLayerId; }
public:
CDistanceCloudRenderNode();
SDistanceCloudProperties GetProperties() const;
private:
~CDistanceCloudRenderNode();
private:
Vec3 m_pos;
float m_sizeX;
float m_sizeY;
float m_rotationZ;
_smart_ptr< IMaterial > m_pMaterial;
AABB m_WSBBox;
uint16 m_nLayerId;
};
#endif // CRYINCLUDE_CRY3DENGINE_DISTANCECLOUDRENDERNODE_H
@@ -1,329 +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
#include <AzCore/EBus/EBus.h>
#include <AzCore/Math/Vector3.h>
#include <I3DEngine.h>
#include <ISystem.h>
#include <OceanConstants.h>
namespace AZ
{
/**
* Feature toggle for the ocean feature(s)
*/
class OceanFeatureToggle
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
using MutexType = AZStd::recursive_mutex;
//////////////////////////////////////////////////////////////////////////
virtual ~OceanFeatureToggle() = default;
virtual bool OceanComponentEnabled() const { return false; }
};
using OceanFeatureToggleBus = AZ::EBus<OceanFeatureToggle>;
/*!
* Messages services for environment data points
* Note: The Gem for Water is meant to override this when enabled in a project
*/
class OceanEnvironmentRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
using MutexType = AZStd::recursive_mutex;
//////////////////////////////////////////////////////////////////////////
// flags for toggling ocean reflections
enum class ReflectionFlags
{
Entities = SRenderingPassInfo::ENTITIES,
StaticObjects = SRenderingPassInfo::STATIC_OBJECTS
};
// Ocean requests
virtual bool OceanIsEnabled() const = 0;
// Fast option - use if just ocean height required
virtual float GetOceanLevel() const = 0;
virtual void SetOceanLevel(float oceanLevel) = 0;
virtual float GetOceanLevelOrDefault(const float defaultValue) const = 0;
// This will return ocean height or water volume height, optional for accurate water height query
virtual float GetWaterLevel(const Vec3& position) const = 0;
// Only use for Accurate query - this will return exact ocean height
virtual float GetAccurateOceanHeight(const Vec3& position) const = 0;
// gets the amount of water tessellation
virtual int GetWaterTessellationAmount() const = 0;
virtual void SetWaterTessellationAmount(int amount) = 0;
// the ocean material asset
virtual const AZStd::string& GetOceanMaterialName() const = 0;
virtual void SetOceanMaterialName(const AZStd::string& matName) = 0;
// Animation data
virtual float GetAnimationWindDirection() const = 0;
virtual float GetAnimationWindSpeed() const = 0;
virtual float GetAnimationWavesSpeed() const = 0;
virtual float GetAnimationWavesSize() const = 0;
virtual float GetAnimationWavesAmount() const = 0;
virtual void SetAnimationWindDirection(float dir) = 0;
virtual void SetAnimationWindSpeed(float speed) = 0;
virtual void SetAnimationWavesSpeed(float speed) = 0;
virtual void SetAnimationWavesSize(float size) = 0;
virtual void SetAnimationWavesAmount(float amount) = 0;
// Ocean reflection
virtual void ApplyReflectRenderFlags(int& flags) const = 0;
virtual bool GetReflectRenderFlag(ReflectionFlags flag) const = 0;
virtual float GetReflectResolutionScale() const = 0;
virtual bool GetReflectionAnisotropic() const = 0;
virtual void SetReflectRenderFlag(ReflectionFlags flag, bool value) = 0;
virtual void SetReflectResolutionScale(float scale) = 0;
virtual void SetReflectionAnisotropic(bool enabled) = 0;
// Ocean bottom
virtual bool GetUseOceanBottom() const = 0;
virtual void SetUseOceanBottom(bool use) = 0;
// Underwater Effects
virtual bool GetGodRaysEnabled() const = 0;
virtual void SetGodRaysEnabled(bool enabled) = 0;
virtual float GetUnderwaterDistortion() const = 0;
virtual void SetUnderwaterDistortion(float) = 0;
// Caustics
virtual bool GetCausticsEnabled() const = 0;
virtual float GetCausticsDepth() const = 0;
virtual float GetCausticsIntensity() const = 0;
virtual float GetCausticsTiling() const = 0;
virtual float GetCausticsDistanceAttenuation() const = 0;
virtual void SetCausticsEnabled(bool enable) = 0;
virtual void SetCausticsDepth(float depth) = 0;
virtual void SetCausticsIntensity(float intensity) = 0;
virtual void SetCausticsTiling(float tiling) = 0;
virtual void SetCausticsDistanceAttenuation(float dist) = 0;
// Ocean fog data
virtual AZ::Color GetFogColorPremultiplied() const = 0;
virtual AZ::Color GetFogColor() const = 0;
virtual void SetFogColor(const AZ::Color& fogColor) = 0;
virtual float GetFogColorMultiplier() const = 0;
virtual void SetFogColorMultiplier(float fogMultiplier) = 0;
virtual AZ::Color GetNearFogColor() const = 0;
virtual void SetNearFogColor(const AZ::Color& nearColor) = 0;
virtual float GetFogDensity() const = 0;
virtual void SetFogDensity(float density) = 0;
};
using OceanEnvironmentBus = AZ::EBus<OceanEnvironmentRequests>;
} // namespace AZ
namespace OceanToggle
{
/**
* As long as the Water gem is in a preview state, the legacy code and data will be protected by this feature toggle check.
*/
AZ_INLINE bool IsActive()
{
bool bHasOceanFeature = false;
AZ::OceanFeatureToggleBus::BroadcastResult(bHasOceanFeature, &AZ::OceanFeatureToggleBus::Events::OceanComponentEnabled);
return bHasOceanFeature;
}
} // namespace OceanToggle
namespace OceanRequest
{
AZ_INLINE bool OceanIsEnabled()
{
bool enabled = false;
AZ::OceanEnvironmentBus::BroadcastResult(enabled, &AZ::OceanEnvironmentBus::Events::OceanIsEnabled);
return enabled;
}
// Ocean level
AZ_INLINE float GetOceanLevel()
{
float fWaterLevel = AZ::OceanConstants::s_HeightUnknown;
AZ::OceanEnvironmentBus::BroadcastResult(fWaterLevel, &AZ::OceanEnvironmentBus::Events::GetOceanLevel);
return fWaterLevel;
}
AZ_INLINE float GetOceanLevelOrDefault(const float defaultValue)
{
return OceanIsEnabled() ? GetOceanLevel() : defaultValue;
}
AZ_INLINE float GetWaterLevel(const Vec3& position)
{
float fWaterLevel = AZ::OceanConstants::s_HeightUnknown;
AZ::OceanEnvironmentBus::BroadcastResult(fWaterLevel, &AZ::OceanEnvironmentBus::Events::GetWaterLevel, position);
return fWaterLevel;
}
AZ_INLINE float GetAccurateOceanHeight(const Vec3& position)
{
float fWaterLevel = AZ::OceanConstants::s_HeightUnknown;
AZ::OceanEnvironmentBus::BroadcastResult(fWaterLevel, &AZ::OceanEnvironmentBus::Events::GetAccurateOceanHeight, position);
return fWaterLevel;
}
// the ocean material
AZ_INLINE AZStd::string GetOceanMaterialName()
{
AZStd::string value = "EngineAssets/Materials/Water/Ocean_default.mtl";
AZ::OceanEnvironmentBus::BroadcastResult(value, &AZ::OceanEnvironmentBus::Events::GetOceanMaterialName);
return value;
}
// Wave animation data
AZ_INLINE float GetWavesAmount()
{
float value = AZ::OceanConstants::s_animationWavesAmountDefault;
AZ::OceanEnvironmentBus::BroadcastResult(value, &AZ::OceanEnvironmentBus::Events::GetAnimationWavesAmount);
return value;
}
AZ_INLINE float GetWavesSpeed()
{
float value = AZ::OceanConstants::s_animationWavesSpeedDefault;
AZ::OceanEnvironmentBus::BroadcastResult(value, &AZ::OceanEnvironmentBus::Events::GetAnimationWavesSpeed);
return value;
}
AZ_INLINE float GetWavesSize()
{
float value = AZ::OceanConstants::s_animationWavesSizeDefault;
AZ::OceanEnvironmentBus::BroadcastResult(value, &AZ::OceanEnvironmentBus::Events::GetAnimationWavesSize);
return value;
}
AZ_INLINE float GetWindDirection()
{
float value = AZ::OceanConstants::s_animationWindDirectionDefault;
AZ::OceanEnvironmentBus::BroadcastResult(value, &AZ::OceanEnvironmentBus::Events::GetAnimationWindDirection);
return value;
}
AZ_INLINE float GetWindSpeed()
{
float value = AZ::OceanConstants::s_animationWindSpeedDefault;
AZ::OceanEnvironmentBus::BroadcastResult(value, &AZ::OceanEnvironmentBus::Events::GetAnimationWindSpeed);
return value;
}
// Ocean bottom
AZ_INLINE bool GetUseOceanBottom()
{
bool useOceanBottom = AZ::OceanConstants::s_UseOceanBottom;
AZ::OceanEnvironmentBus::BroadcastResult(useOceanBottom, &AZ::OceanEnvironmentBus::Events::GetUseOceanBottom);
return useOceanBottom;
}
AZ_INLINE bool GetGodRaysEnabled()
{
bool godRaysEnabled = AZ::OceanConstants::s_GodRaysEnabled;
AZ::OceanEnvironmentBus::BroadcastResult(godRaysEnabled, &AZ::OceanEnvironmentBus::Events::GetGodRaysEnabled);
return godRaysEnabled;
}
AZ_INLINE float GetUnderwaterDistortion()
{
float underwaterDistortion = AZ::OceanConstants::s_UnderwaterDistortion;
AZ::OceanEnvironmentBus::BroadcastResult(underwaterDistortion, &AZ::OceanEnvironmentBus::Events::GetUnderwaterDistortion);
return underwaterDistortion;
}
// Cuastics
AZ_INLINE bool GetCausticsEnabled()
{
bool causticsEnabled = false;
AZ::OceanEnvironmentBus::BroadcastResult(causticsEnabled, &AZ::OceanEnvironmentBus::Events::GetCausticsEnabled);
return causticsEnabled;
}
AZ_INLINE float GetCausticsDepth()
{
float causticsDepth = AZ::OceanConstants::s_CausticsDepthDefault;
AZ::OceanEnvironmentBus::BroadcastResult(causticsDepth, &AZ::OceanEnvironmentBus::Events::GetCausticsDepth);
return causticsDepth;
}
AZ_INLINE float GetCausticsIntensity()
{
float causticsIntensity = AZ::OceanConstants::s_CausticsIntensityDefault;
AZ::OceanEnvironmentBus::BroadcastResult(causticsIntensity, &AZ::OceanEnvironmentBus::Events::GetCausticsIntensity);
return causticsIntensity;
}
AZ_INLINE float GetCausticsTiling()
{
float causticsTiling = AZ::OceanConstants::s_CausticsTilingDefault;
AZ::OceanEnvironmentBus::BroadcastResult(causticsTiling, &AZ::OceanEnvironmentBus::Events::GetCausticsTiling);
return causticsTiling;
}
AZ_INLINE float GetCausticsDistanceAttenuation()
{
float causticsDistanceAtten = AZ::OceanConstants::s_CausticsDistanceAttenDefault;
AZ::OceanEnvironmentBus::BroadcastResult(causticsDistanceAtten, &AZ::OceanEnvironmentBus::Events::GetCausticsDistanceAttenuation);
return causticsDistanceAtten;
}
// Ocean fog
AZ_INLINE AZ::Vector3 GetFogColorPremultiplied()
{
AZ::Color fogColor = AZ::OceanConstants::s_oceanFogColorDefault;
AZ::OceanEnvironmentBus::BroadcastResult(fogColor, &AZ::OceanEnvironmentBus::Events::GetFogColorPremultiplied);
return fogColor.GetAsVector3();
}
AZ_INLINE AZ::Vector3 GetNearFogColor()
{
AZ::Color nearFogColor = AZ::OceanConstants::s_oceanNearFogColorDefault;
AZ::OceanEnvironmentBus::BroadcastResult(nearFogColor, &AZ::OceanEnvironmentBus::Events::GetNearFogColor);
return nearFogColor.GetAsVector3();
}
AZ_INLINE float GetFogDensity()
{
float fogDensity = AZ::OceanConstants::s_oceanFogDensityDefault;
AZ::OceanEnvironmentBus::BroadcastResult(fogDensity, &AZ::OceanEnvironmentBus::Events::GetFogDensity);
return fogDensity;
}
} // namespace OceanRequest
@@ -1,546 +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 "ITimeOfDay.h"
#include "EnvironmentPreset.h"
#include <Serialization/IArchive.h>
#include <Serialization/IArchiveHost.h>
#include <Serialization/ClassFactory.h>
#include <Serialization/Enum.h>
#include <Bezier.h>
#include <Serialization/Enum.h>
SERIALIZATION_ENUM_BEGIN_NESTED(SBezierControlPoint, ETangentType, "TangentType")
SERIALIZATION_ENUM_VALUE_NESTED(SBezierControlPoint, eTangentType_Custom, "Custom")
SERIALIZATION_ENUM_VALUE_NESTED(SBezierControlPoint, eTangentType_Auto, "Smooth")
SERIALIZATION_ENUM_VALUE_NESTED(SBezierControlPoint, eTangentType_Zero, "Zero")
SERIALIZATION_ENUM_VALUE_NESTED(SBezierControlPoint, eTangentType_Step, "Step")
SERIALIZATION_ENUM_VALUE_NESTED(SBezierControlPoint, eTangentType_Linear, "Linear")
SERIALIZATION_ENUM_END()
namespace EnvironmentPresetDetails
{
static const float sBezierSplineKeyValueEpsilon = 0.001f;
//////////////////////////////////////////////////////////////////////////
SBezierKey ApplyInTangent(const SBezierKey& key, const SBezierKey& leftKey, const SBezierKey* pRightKey)
{
SBezierKey newKey = key;
if (leftKey.m_controlPoint.m_outTangentType == SBezierControlPoint::eTangentType_Step)
{
newKey.m_controlPoint.m_inTangent = Vec2(0.0f, 0.0f);
return newKey;
}
else if (key.m_controlPoint.m_inTangentType != SBezierControlPoint::eTangentType_Step)
{
const SAnimTime leftTime = leftKey.m_time;
const SAnimTime rightTime = pRightKey ? pRightKey->m_time : key.m_time;
// Rebase to [0, rightTime - leftTime] to increase float precision
const float floatTime = (key.m_time - leftTime).ToFloat();
const float floatLeftTime = 0.0f;
const float floatRightTime = (rightTime - leftTime).ToFloat();
newKey.m_controlPoint = Bezier::CalculateInTangent(floatTime, key.m_controlPoint,
floatLeftTime, &leftKey.m_controlPoint,
floatRightTime, pRightKey ? &pRightKey->m_controlPoint : NULL);
}
else
{
newKey.m_controlPoint.m_inTangent = Vec2(0.0f, 0.0f);
newKey.m_controlPoint.m_value = leftKey.m_controlPoint.m_value;
}
return newKey;
}
SBezierKey ApplyOutTangent(const SBezierKey& key, const SBezierKey* pLeftKey, const SBezierKey& rightKey)
{
SBezierKey newKey = key;
if (rightKey.m_controlPoint.m_inTangentType == SBezierControlPoint::eTangentType_Step
&& key.m_controlPoint.m_outTangentType != SBezierControlPoint::eTangentType_Step)
{
newKey.m_controlPoint.m_outTangent = Vec2(0.0f, 0.0f);
}
else if (key.m_controlPoint.m_outTangentType != SBezierControlPoint::eTangentType_Step)
{
const SAnimTime leftTime = pLeftKey ? pLeftKey->m_time : key.m_time;
const SAnimTime rightTime = rightKey.m_time;
// Rebase to [0, rightTime - leftTime] to increase float precision
const float floatTime = (key.m_time - leftTime).ToFloat();
const float floatLeftTime = 0.0f;
const float floatRightTime = (rightTime - leftTime).ToFloat();
newKey.m_controlPoint = Bezier::CalculateOutTangent(floatTime, key.m_controlPoint,
floatLeftTime, pLeftKey ? &pLeftKey->m_controlPoint : NULL,
floatRightTime, &rightKey.m_controlPoint);
}
else
{
newKey.m_controlPoint.m_outTangent = Vec2(0.0f, 0.0f);
newKey.m_controlPoint.m_value = rightKey.m_controlPoint.m_value;
}
return newKey;
}
}
CBezierSpline::CBezierSpline()
{
m_keys.reserve(2);
}
CBezierSpline::~CBezierSpline()
{
}
void CBezierSpline::Init(float fDefaultValue)
{
m_keys.clear();
InsertKey(SAnimTime(0.0f), fDefaultValue);
InsertKey(SAnimTime(1.0f), fDefaultValue);
}
float CBezierSpline::Evaluate(float t) const
{
if (m_keys.size() == 0)
{
return 0.0f;
}
if (m_keys.size() == 1)
{
return m_keys.front().m_controlPoint.m_value;
}
const SAnimTime time(t);
if (time <= m_keys.front().m_time)
{
return m_keys.front().m_controlPoint.m_value;
}
else if (time >= m_keys.back().m_time)
{
return m_keys.back().m_controlPoint.m_value;
}
const TKeyContainer::const_iterator it = std::upper_bound(m_keys.begin(), m_keys.end(), time, SCompKeyTime());
const TKeyContainer::const_iterator startIt = it - 1;
if (startIt->m_controlPoint.m_outTangentType == SBezierControlPoint::eTangentType_Step)
{
return it->m_controlPoint.m_value;
}
if (it->m_controlPoint.m_inTangentType == SBezierControlPoint::eTangentType_Step)
{
return startIt->m_controlPoint.m_value;
}
const SAnimTime deltaTime = it->m_time - startIt->m_time;
if (deltaTime == SAnimTime(0))
{
return startIt->m_controlPoint.m_value;
}
const float timeInSegment = (time - startIt->m_time).ToFloat();
const SBezierKey* pKeyLeftOfSegment = (startIt != m_keys.begin()) ? &*(startIt - 1) : NULL;
const SBezierKey* pKeyRightOfSegment = (startIt != (m_keys.end() - 2)) ? &*(startIt + 2) : NULL;
const SBezierKey segmentStart = EnvironmentPresetDetails::ApplyOutTangent(*startIt, pKeyLeftOfSegment, *(startIt + 1));
const SBezierKey segmentEnd = EnvironmentPresetDetails::ApplyInTangent(*(startIt + 1), *startIt, pKeyRightOfSegment);
const float factor = Bezier::InterpolationFactorFromX(timeInSegment, deltaTime.ToFloat(), segmentStart.m_controlPoint, segmentEnd.m_controlPoint);
const float fResult = Bezier::EvaluateY(factor, segmentStart.m_controlPoint, segmentEnd.m_controlPoint);
return fResult;
}
void CBezierSpline::InsertKey(SAnimTime time, float value)
{
SBezierKey key;
key.m_time = time;
key.m_controlPoint.m_value = value;
const size_t nKeyNum = m_keys.size();
for (size_t i = 0; i < nKeyNum; ++i)
{
if (m_keys[i].m_time > time)
{
m_keys.insert(m_keys.begin() + i, key);
return;
}
}
m_keys.push_back(key);
}
void CBezierSpline::UpdateKeyForTime(float fTime, float value)
{
const SAnimTime time(fTime);
const size_t nKeyNum = m_keys.size();
for (size_t i = 0; i < nKeyNum; ++i)
{
if (fabs(m_keys[i].m_time.ToFloat() - fTime) < EnvironmentPresetDetails::sBezierSplineKeyValueEpsilon)
{
m_keys[i].m_controlPoint.m_value = value;
return;
}
}
InsertKey(time, value);
}
void CBezierSpline::Serialize(Serialization::IArchive& ar)
{
ar(m_keys, "keys");
}
//////////////////////////////////////////////////////////////////////////
CTimeOfDayVariable::CTimeOfDayVariable()
: m_id(ITimeOfDay::PARAM_TOTAL)
, m_type(ITimeOfDay::TYPE_FLOAT)
, m_name(NULL)
, m_displayName(NULL)
, m_group(NULL)
, m_minValue(0.0f)
, m_maxValue(0.0f)
, m_value(ZERO)
{
}
CTimeOfDayVariable::~CTimeOfDayVariable()
{
}
void CTimeOfDayVariable::Init(const char* group, const char* displayName, const char* name, ITimeOfDay::ETimeOfDayParamID nParamId, ITimeOfDay::EVariableType type, float defVal0, float defVal1, float defVal2)
{
m_id = nParamId;
m_type = type;
m_name = name;
m_displayName = (displayName && *displayName) ? displayName : name;
m_group = (group && *group) ? group : "Default";
if (ITimeOfDay::TYPE_FLOAT == type)
{
m_value.x = defVal0;
m_minValue = defVal1;
m_maxValue = defVal2;
m_spline[0].Init(defVal0);
}
else if (ITimeOfDay::TYPE_COLOR == type)
{
m_value.x = defVal0;
m_value.y = defVal1;
m_value.z = defVal2;
m_minValue = 0.0f;
m_maxValue = 1.0f;
m_spline[0].Init(defVal0);
m_spline[1].Init(defVal1);
m_spline[2].Init(defVal2);
}
}
void CTimeOfDayVariable::Update(float time)
{
m_value = GetInterpolatedAt(time);
}
Vec3 CTimeOfDayVariable::GetInterpolatedAt(float t) const
{
Vec3 result;
result.x = clamp_tpl(m_spline[0].Evaluate(t), m_minValue, m_maxValue);
result.y = clamp_tpl(m_spline[1].Evaluate(t), m_minValue, m_maxValue);
result.z = clamp_tpl(m_spline[2].Evaluate(t), m_minValue, m_maxValue);
return result;
}
size_t CTimeOfDayVariable::GetSplineKeyCount(int nSpline) const
{
if (const CBezierSpline* pSpline = GetSpline(nSpline))
{
return pSpline->GetKeyCount();
}
return 0;
}
bool CTimeOfDayVariable::GetSplineKeys(int nSpline, SBezierKey* keysArray, unsigned int keysArraySize) const
{
if (const CBezierSpline* pSpline = GetSpline(nSpline))
{
if (keysArraySize < pSpline->GetKeyCount())
{
return false;
}
pSpline->GetKeys(keysArray);
return true;
}
return false;
}
bool CTimeOfDayVariable::SetSplineKeys(int nSpline, const SBezierKey* keysArray, unsigned int keysArraySize)
{
if (CBezierSpline* pSpline = GetSpline(nSpline))
{
pSpline->SetKeys(keysArray, keysArraySize);
return true;
}
return false;
}
bool CTimeOfDayVariable::UpdateSplineKeyForTime(int nSpline, float fTime, float newKey)
{
if (CBezierSpline* pSpline = GetSpline(nSpline))
{
pSpline->UpdateKeyForTime(fTime, newKey);
return true;
}
return false;
}
void CTimeOfDayVariable::Serialize(Serialization::IArchive& ar)
{
ITimeOfDay::ETimeOfDayParamID defID = m_id;
ITimeOfDay::EVariableType defType = m_type;
ar(defID, "id");
ar(defType, "type");
if (!ar.IsInput() || (defID == m_id && defType == m_type))
{ // Write always, Read only when ID and Type are correct/Schema hasn't changed
ar(m_minValue, "minValue");
ar(m_maxValue, "maxValue");
ar(m_spline[0], "spline0");
ar(m_spline[1], "spline1");
ar(m_spline[2], "spline2");
}
}
//////////////////////////////////////////////////////////////////////////
CEnvironmentPreset::CEnvironmentPreset()
{
ResetVariables();
}
CEnvironmentPreset::~CEnvironmentPreset()
{
}
void CEnvironmentPreset::ResetVariables()
{
const float fRecip255 = 1.0f / 255.0f;
AddVar("Sun", "", "Sun color", ITimeOfDay::PARAM_SUN_COLOR, ITimeOfDay::TYPE_COLOR, 255.0f * fRecip255, 248.0f * fRecip255, 248.0f * fRecip255);
AddVar("Sun", "Sun intensity (lux)", "Sun intensity", ITimeOfDay::PARAM_SUN_INTENSITY, ITimeOfDay::TYPE_FLOAT, 119000.0f, 0.0f, 550000.0f);
AddVar("Sun", "", "Sun specular multiplier", ITimeOfDay::PARAM_SUN_SPECULAR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 4.0f);
AddVar("Fog", "Color (bottom)", "Fog color", ITimeOfDay::PARAM_FOG_COLOR, ITimeOfDay::TYPE_COLOR, 0.0f, 0.0f, 0.0f);
AddVar("Fog", "Color (bottom) multiplier", "Fog color multiplier", ITimeOfDay::PARAM_FOG_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 16.0f);
AddVar("Fog", "Height (bottom)", "Fog height (bottom)", ITimeOfDay::PARAM_VOLFOG_HEIGHT, ITimeOfDay::TYPE_FLOAT, 0.0f, -5000.0f, 30000.0f);
AddVar("Fog", "Density (bottom)", "Fog layer density (bottom)", ITimeOfDay::PARAM_VOLFOG_DENSITY, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Fog", "Color (top)", "Fog color (top)", ITimeOfDay::PARAM_FOG_COLOR2, ITimeOfDay::TYPE_COLOR, 0.0f, 0.0f, 0.0f);
AddVar("Fog", "Color (top) multiplier", "Fog color (top) multiplier", ITimeOfDay::PARAM_FOG_COLOR2_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 16.0f);
AddVar("Fog", "Height (top)", "Fog height (top)", ITimeOfDay::PARAM_VOLFOG_HEIGHT2, ITimeOfDay::TYPE_FLOAT, 4000.0f, -5000.0f, 30000.0f);
AddVar("Fog", "Density (top)", "Fog layer density (top)", ITimeOfDay::PARAM_VOLFOG_DENSITY2, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 1.0f);
AddVar("Fog", "Color height offset", "Fog color height offset", ITimeOfDay::PARAM_VOLFOG_HEIGHT_OFFSET, ITimeOfDay::TYPE_FLOAT, 0.0f, -1.0f, 1.0f);
AddVar("Fog", "Color (radial)", "Fog color (radial)", ITimeOfDay::PARAM_FOG_RADIAL_COLOR, ITimeOfDay::TYPE_COLOR, 0.0f, 0.0f, 0.0f);
AddVar("Fog", "Color (radial) multiplier", "Fog color (radial) multiplier", ITimeOfDay::PARAM_FOG_RADIAL_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 16.0f);
AddVar("Fog", "Radial size", "Fog radial size", ITimeOfDay::PARAM_VOLFOG_RADIAL_SIZE, ITimeOfDay::TYPE_FLOAT, 0.75f, 0.0f, 1.0f);
AddVar("Fog", "Radial lobe", "Fog radial lobe", ITimeOfDay::PARAM_VOLFOG_RADIAL_LOBE, ITimeOfDay::TYPE_FLOAT, 0.5f, 0.0f, 1.0f);
AddVar("Fog", "Global density", "Volumetric fog: Global density", ITimeOfDay::PARAM_VOLFOG_GLOBAL_DENSITY, ITimeOfDay::TYPE_FLOAT, 0.02f, 0.0f, 100.0f);
AddVar("Fog", "Final density clamp", "Volumetric fog: Final density clamp", ITimeOfDay::PARAM_VOLFOG_FINAL_DENSITY_CLAMP, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Fog", "Ramp start", "Volumetric fog: Ramp start", ITimeOfDay::PARAM_VOLFOG_RAMP_START, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 30000.0f);
AddVar("Fog", "Ramp end", "Volumetric fog: Ramp end", ITimeOfDay::PARAM_VOLFOG_RAMP_END, ITimeOfDay::TYPE_FLOAT, 100.0f, 0.0f, 30000.0f);
AddVar("Fog", "Ramp influence", "Volumetric fog: Ramp influence", ITimeOfDay::PARAM_VOLFOG_RAMP_INFLUENCE, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 1.0f);
AddVar("Fog", "Shadow darkening", "Volumetric fog: Shadow darkening", ITimeOfDay::PARAM_VOLFOG_SHADOW_DARKENING, ITimeOfDay::TYPE_FLOAT, 0.25f, 0.0f, 1.0f);
AddVar("Fog", "Shadow darkening sun", "Volumetric fog: Shadow darkening sun", ITimeOfDay::PARAM_VOLFOG_SHADOW_DARKENING_SUN, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Fog", "Shadow darkening ambient", "Volumetric fog: Shadow darkening ambient", ITimeOfDay::PARAM_VOLFOG_SHADOW_DARKENING_AMBIENT, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Fog", "Shadow range", "Volumetric fog: Shadow range", ITimeOfDay::PARAM_VOLFOG_SHADOW_RANGE, ITimeOfDay::TYPE_FLOAT, 0.1f, 0.0f, 1.0f);
AddVar("Volumetric fog", "Height (bottom)", "Volumetric fog 2: Fog height (bottom)", ITimeOfDay::PARAM_VOLFOG2_HEIGHT, ITimeOfDay::TYPE_FLOAT, 0.0f, -5000.0f, 30000.0f);
AddVar("Volumetric fog", "Density (bottom)", "Volumetric fog 2: Fog layer density (bottom)", ITimeOfDay::PARAM_VOLFOG2_DENSITY, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Volumetric fog", "Height (top)", "Volumetric fog 2: Fog height (top)", ITimeOfDay::PARAM_VOLFOG2_HEIGHT2, ITimeOfDay::TYPE_FLOAT, 4000.0f, -5000.0f, 30000.0f);
AddVar("Volumetric fog", "Density (top)", "Volumetric fog 2: Fog layer density (top)", ITimeOfDay::PARAM_VOLFOG2_DENSITY2, ITimeOfDay::TYPE_FLOAT, 0.0001f, 0.0f, 1.0f);
AddVar("Volumetric fog", "Global density", "Volumetric fog 2: Global fog density", ITimeOfDay::PARAM_VOLFOG2_GLOBAL_DENSITY, ITimeOfDay::TYPE_FLOAT, 0.1f, 0.0f, 100.0f);
AddVar("Volumetric fog", "Ramp start", "Volumetric fog 2: Ramp start", ITimeOfDay::PARAM_VOLFOG2_RAMP_START, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 30000.0f);
AddVar("Volumetric fog", "Ramp end", "Volumetric fog 2: Ramp end", ITimeOfDay::PARAM_VOLFOG2_RAMP_END, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 30000.0f);
AddVar("Volumetric fog", "Color (atmosphere)", "Volumetric fog 2: Fog albedo color (atmosphere)", ITimeOfDay::PARAM_VOLFOG2_COLOR1, ITimeOfDay::TYPE_COLOR, 1.0f, 1.0f, 1.0f);
AddVar("Volumetric fog", "Anisotropy (atmosphere)", "Volumetric fog 2: Anisotropy factor (atmosphere)", ITimeOfDay::PARAM_VOLFOG2_ANISOTROPIC1, ITimeOfDay::TYPE_FLOAT, 0.2f, -1.0f, 1.0f);
AddVar("Volumetric fog", "Color (sun radial)", "Volumetric fog 2: Fog albedo color (sun radial)", ITimeOfDay::PARAM_VOLFOG2_COLOR2, ITimeOfDay::TYPE_COLOR, 1.0f, 1.0f, 1.0f);
AddVar("Volumetric fog", "Anisotropy (sun radial)", "Volumetric fog 2: Anisotropy factor (sun radial)", ITimeOfDay::PARAM_VOLFOG2_ANISOTROPIC2, ITimeOfDay::TYPE_FLOAT, 0.95f, -1.0f, 1.0f);
AddVar("Volumetric fog", "Radial blend factor", "Volumetric fog 2: Blend factor for sun scattering", ITimeOfDay::PARAM_VOLFOG2_BLEND_FACTOR, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Volumetric fog", "Radial blend mode", "Volumetric fog 2: Blend mode for sun scattering", ITimeOfDay::PARAM_VOLFOG2_BLEND_MODE, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 1.0f);
AddVar("Volumetric fog", "Range", "Volumetric fog 2: Maximum range of ray-marching", ITimeOfDay::PARAM_VOLFOG2_RANGE, ITimeOfDay::TYPE_FLOAT, 64.0f, 0.0f, 8192.0f);
AddVar("Volumetric fog", "In-scattering", "Volumetric fog 2: In-scattering factor", ITimeOfDay::PARAM_VOLFOG2_INSCATTER, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 100.0f);
AddVar("Volumetric fog", "Extinction", "Volumetric fog 2: Extinction factor", ITimeOfDay::PARAM_VOLFOG2_EXTINCTION, ITimeOfDay::TYPE_FLOAT, 0.3f, 0.0f, 100.0f);
AddVar("Volumetric fog", "Color (entities)", "Volumetric fog 2: Fog albedo color (entities)", ITimeOfDay::PARAM_VOLFOG2_COLOR, ITimeOfDay::TYPE_COLOR, 1.0f, 1.0f, 1.0f);
AddVar("Volumetric fog", "Anisotropy (entities)", "Volumetric fog 2: Anisotropy factor (entities)", ITimeOfDay::PARAM_VOLFOG2_ANISOTROPIC, ITimeOfDay::TYPE_FLOAT, 0.6f, -1.0f, 1.0f);
AddVar("Volumetric fog", "Analytical fog visibility", "Volumetric fog 2: Analytical volumetric fog visibility", ITimeOfDay::PARAM_VOLFOG2_GLOBAL_FOG_VISIBILITY, ITimeOfDay::TYPE_FLOAT, 0.5f, 0.0f, 1.0f);
AddVar("Volumetric fog", "Final density clamp", "Volumetric fog 2: Final density clamp", ITimeOfDay::PARAM_VOLFOG2_FINAL_DENSITY_CLAMP, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Sky Light", "Sun intensity", "Sky light: Sun intensity", ITimeOfDay::PARAM_SKYLIGHT_SUN_INTENSITY, ITimeOfDay::TYPE_COLOR, 1.0f, 1.0f, 1.0f);
AddVar("Sky Light", "Sun intensity multiplier", "Sky light: Sun intensity multiplier", ITimeOfDay::PARAM_SKYLIGHT_SUN_INTENSITY_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 50.0f, 0.0f, 1000.0f);
AddVar("Sky Light", "Mie scattering", "Sky light: Mie scattering", ITimeOfDay::PARAM_SKYLIGHT_KM, ITimeOfDay::TYPE_FLOAT, 4.8f, 0.0f, 1000.0f);
AddVar("Sky Light", "Rayleigh scattering", "Sky light: Rayleigh scattering", ITimeOfDay::PARAM_SKYLIGHT_KR, ITimeOfDay::TYPE_FLOAT, 2.0f, 0.0f, 1000.0f);
AddVar("Sky Light", "Sun anisotropy factor", "Sky light: Sun anisotropy factor", ITimeOfDay::PARAM_SKYLIGHT_G, ITimeOfDay::TYPE_FLOAT, -0.997f, -0.9999f, 0.9999f);
AddVar("Sky Light", "Wavelength (R)", "Sky light: Wavelength (R)", ITimeOfDay::PARAM_SKYLIGHT_WAVELENGTH_R, ITimeOfDay::TYPE_FLOAT, 694.0f, 380.0f, 780.0f);
AddVar("Sky Light", "Wavelength (G)", "Sky light: Wavelength (G)", ITimeOfDay::PARAM_SKYLIGHT_WAVELENGTH_G, ITimeOfDay::TYPE_FLOAT, 597.0f, 380.0f, 780.0f);
AddVar("Sky Light", "Wavelength (B)", "Sky light: Wavelength (B)", ITimeOfDay::PARAM_SKYLIGHT_WAVELENGTH_B, ITimeOfDay::TYPE_FLOAT, 488.0f, 380.0f, 780.0f);
AddVar("Night Sky", "Horizon color", "Night sky: Horizon color", ITimeOfDay::PARAM_NIGHSKY_HORIZON_COLOR, ITimeOfDay::TYPE_COLOR, 222.0f * fRecip255, 148.0f * fRecip255, 47.0f * fRecip255);
AddVar("Night Sky", "Zenith color", "Night sky: Zenith color", ITimeOfDay::PARAM_NIGHSKY_ZENITH_COLOR, ITimeOfDay::TYPE_COLOR, 17.0f * fRecip255, 38.0f * fRecip255, 78.0f * fRecip255);
AddVar("Night Sky", "Zenith shift", "Night sky: Zenith shift", ITimeOfDay::PARAM_NIGHSKY_ZENITH_SHIFT, ITimeOfDay::TYPE_FLOAT, 0.25f, 0.0f, 16.0f);
AddVar("Night Sky", "Star intensity", "Night sky: Star intensity", ITimeOfDay::PARAM_NIGHSKY_START_INTENSITY, ITimeOfDay::TYPE_FLOAT, 0.01f, 0.0f, 16.0f);
AddVar("Night Sky", "Moon color", "Night sky: Moon color", ITimeOfDay::PARAM_NIGHSKY_MOON_COLOR, ITimeOfDay::TYPE_COLOR, 255.0f * fRecip255, 255.0f * fRecip255, 255.0f * fRecip255);
AddVar("Night Sky", "Moon inner corona color", "Night sky: Moon inner corona color", ITimeOfDay::PARAM_NIGHSKY_MOON_INNERCORONA_COLOR, ITimeOfDay::TYPE_COLOR, 230.0f * fRecip255, 255.0f * fRecip255, 255.0f * fRecip255);
AddVar("Night Sky", "Moon inner corona scale", "Night sky: Moon inner corona scale", ITimeOfDay::PARAM_NIGHSKY_MOON_INNERCORONA_SCALE, ITimeOfDay::TYPE_FLOAT, 0.499f, 0.0f, 2.0f);
AddVar("Night Sky", "Moon outer corona color", "Night sky: Moon outer corona color", ITimeOfDay::PARAM_NIGHSKY_MOON_OUTERCORONA_COLOR, ITimeOfDay::TYPE_COLOR, 128.0f * fRecip255, 200.0f * fRecip255, 255.0f * fRecip255);
AddVar("Night Sky", "Moon outer corona scale", "Night sky: Moon outer corona scale", ITimeOfDay::PARAM_NIGHSKY_MOON_OUTERCORONA_SCALE, ITimeOfDay::TYPE_FLOAT, 0.006f, 0.0f, 2.0f);
AddVar("Night Sky Multiplier", "Horizon color", "Night sky: Horizon color multiplier", ITimeOfDay::PARAM_NIGHSKY_HORIZON_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.0001f, 0.0f, 1.0f);
AddVar("Night Sky Multiplier", "Zenith color", "Night sky: Zenith color multiplier", ITimeOfDay::PARAM_NIGHSKY_ZENITH_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.00002f, 0.0f, 1.0f);
AddVar("Night Sky Multiplier", "Moon color", "Night sky: Moon color multiplier", ITimeOfDay::PARAM_NIGHSKY_MOON_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.01f, 0.0f, 1.0f);
AddVar("Night Sky Multiplier", "Moon inner corona color", "Night sky: Moon inner corona color multiplier", ITimeOfDay::PARAM_NIGHSKY_MOON_INNERCORONA_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.0001f, 0.0f, 1.0f);
AddVar("Night Sky Multiplier", "Moon outer corona color", "Night sky: Moon outer corona color multiplier", ITimeOfDay::PARAM_NIGHSKY_MOON_OUTERCORONA_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.00005f, 0.0f, 1.0f);
AddVar("Cloud Shading", "Sun contribution", "Cloud shading: Sun light multiplier", ITimeOfDay::PARAM_CLOUDSHADING_SUNLIGHT_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 1.96f, 0.0f, 16.0f);
AddVar("Cloud Shading", "Sun custom color", "Cloud shading: Sun custom color", ITimeOfDay::PARAM_CLOUDSHADING_SUNLIGHT_CUSTOM_COLOR, ITimeOfDay::TYPE_COLOR, 215.0f * fRecip255, 200.0f * fRecip255, 170.0f * fRecip255);
AddVar("Cloud Shading", "Sun custom color multiplier", "Cloud shading: Sun custom color multiplier", ITimeOfDay::PARAM_CLOUDSHADING_SUNLIGHT_CUSTOM_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 16.0f);
AddVar("Cloud Shading", "Sun custom color influence", "Cloud shading: Sun custom color influence", ITimeOfDay::PARAM_CLOUDSHADING_SUNLIGHT_CUSTOM_COLOR_INFLUENCE, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 1.0f);
AddVar("Sun Rays Effect", "", "Sun shafts visibility", ITimeOfDay::PARAM_SUN_SHAFTS_VISIBILITY, ITimeOfDay::TYPE_FLOAT, 0.25f, 0.0f, 1.0f);
AddVar("Sun Rays Effect", "", "Sun rays visibility", ITimeOfDay::PARAM_SUN_RAYS_VISIBILITY, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 10.0f);
AddVar("Sun Rays Effect", "", "Sun rays attenuation", ITimeOfDay::PARAM_SUN_RAYS_ATTENUATION, ITimeOfDay::TYPE_FLOAT, 5.0f, 0.0f, 10.0f);
AddVar("Sun Rays Effect", "", "Sun rays suncolor influence", ITimeOfDay::PARAM_SUN_RAYS_SUNCOLORINFLUENCE, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Sun Rays Effect", "", "Sun rays custom color", ITimeOfDay::PARAM_SUN_RAYS_CUSTOMCOLOR, ITimeOfDay::TYPE_COLOR, 1.0f, 1.0f, 1.0f);
AddVar("HDR", "", "Film curve shoulder scale", ITimeOfDay::PARAM_HDR_FILMCURVE_SHOULDER_SCALE, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 10.0f);
AddVar("HDR", "", "Film curve midtones scale", ITimeOfDay::PARAM_HDR_FILMCURVE_LINEAR_SCALE, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 10.0f);
AddVar("HDR", "", "Film curve toe scale", ITimeOfDay::PARAM_HDR_FILMCURVE_TOE_SCALE, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 10.0f);
AddVar("HDR", "", "Film curve whitepoint", ITimeOfDay::PARAM_HDR_FILMCURVE_WHITEPOINT, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 10.0f);
AddVar("HDR", "", "Saturation", ITimeOfDay::PARAM_HDR_COLORGRADING_COLOR_SATURATION, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 2.0f);
AddVar("HDR", "", "Color balance", ITimeOfDay::PARAM_HDR_COLORGRADING_COLOR_BALANCE, ITimeOfDay::TYPE_COLOR, 1.0f, 1.0f, 1.0f);
AddVar("HDR", "(Dep) Scene key", "Scene key", ITimeOfDay::PARAM_HDR_EYEADAPTATION_SCENEKEY, ITimeOfDay::TYPE_FLOAT, 0.18f, 0.0f, 1.0f);
AddVar("HDR", "(Dep) Min exposure", "Min exposure", ITimeOfDay::PARAM_HDR_EYEADAPTATION_MIN_EXPOSURE, ITimeOfDay::TYPE_FLOAT, 0.36f, 0.0f, 10.0f);
AddVar("HDR", "(Dep) Max exposure", "Max exposure", ITimeOfDay::PARAM_HDR_EYEADAPTATION_MAX_EXPOSURE, ITimeOfDay::TYPE_FLOAT, 2.8f, 0.0f, 10.0f);
AddVar("HDR", "", "EV Min", ITimeOfDay::PARAM_HDR_EYEADAPTATION_EV_MIN, ITimeOfDay::TYPE_FLOAT, 4.5f, -10.0f, 20.0f);
AddVar("HDR", "", "EV Max", ITimeOfDay::PARAM_HDR_EYEADAPTATION_EV_MAX, ITimeOfDay::TYPE_FLOAT, 17.0f, -10.0f, 20.0f);
AddVar("HDR", "", "EV Auto compensation", ITimeOfDay::PARAM_HDR_EYEADAPTATION_EV_AUTO_COMPENSATION, ITimeOfDay::TYPE_FLOAT, 1.5f, -5.0f, 5.0f);
AddVar("HDR", "", "Bloom amount", ITimeOfDay::PARAM_HDR_BLOOM_AMOUNT, ITimeOfDay::TYPE_FLOAT, 0.1f, 0.0f, 10.0f);
AddVar("Filters", "Grain", "Filters: grain", ITimeOfDay::PARAM_COLORGRADING_FILTERS_GRAIN, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 8.0f); // deprecated
AddVar("Filters", "Photofilter color", "Filters: photofilter color", ITimeOfDay::PARAM_COLORGRADING_FILTERS_PHOTOFILTER_COLOR, ITimeOfDay::TYPE_COLOR, 0.952f, 0.517f, 0.09f); // deprecated
AddVar("Filters", "Photofilter density", "Filters: photofilter density", ITimeOfDay::PARAM_COLORGRADING_FILTERS_PHOTOFILTER_DENSITY, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 1.0f); // deprecated
AddVar("Depth Of Field", "Focus range", "Dof: focus range", ITimeOfDay::PARAM_COLORGRADING_DOF_FOCUSRANGE, ITimeOfDay::TYPE_FLOAT, 1000.0f, 0.0f, 10000.0f);
AddVar("Depth Of Field", "Blur amount", "Dof: blur amount", ITimeOfDay::PARAM_COLORGRADING_DOF_BLURAMOUNT, ITimeOfDay::TYPE_FLOAT, 0.0f, 0.0f, 1.0f);
AddVar("Advanced", "", "Ocean fog color", ITimeOfDay::PARAM_OCEANFOG_COLOR, ITimeOfDay::TYPE_COLOR, 29.0f * fRecip255, 102.0f * fRecip255, 141.0f * fRecip255);
AddVar("Advanced", "", "Ocean fog color multiplier", ITimeOfDay::PARAM_OCEANFOG_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
AddVar("Advanced", "", "Ocean fog density", ITimeOfDay::PARAM_OCEANFOG_DENSITY, ITimeOfDay::TYPE_FLOAT, 0.2f, 0.0f, 1.0f);
AddVar("Advanced", "", "Static skybox multiplier", ITimeOfDay::PARAM_SKYBOX_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 1.0f);
const float arrDepthConstBias[] = {1.0f, 1.0f, 1.9f, 3.0f, 2.0f, 2.0f, 2.0f, 2.0f};
const float arrDepthSlopeBias[] = {4.0f, 2.0f, 0.24f, 0.24f, 0.5f, 0.5f, 0.5f, 0.5f};
AddVar("Shadows", "", "Cascade 0: Bias", ITimeOfDay::PARAM_SHADOWSC0_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[0], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 0: Slope Bias", ITimeOfDay::PARAM_SHADOWSC0_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[0], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 1: Bias", ITimeOfDay::PARAM_SHADOWSC1_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[1], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 1: Slope Bias", ITimeOfDay::PARAM_SHADOWSC1_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[1], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 2: Bias", ITimeOfDay::PARAM_SHADOWSC2_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[2], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 2: Slope Bias", ITimeOfDay::PARAM_SHADOWSC2_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[2], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 3: Bias", ITimeOfDay::PARAM_SHADOWSC3_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[3], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 3: Slope Bias", ITimeOfDay::PARAM_SHADOWSC3_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[3], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 4: Bias", ITimeOfDay::PARAM_SHADOWSC4_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[4], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 4: Slope Bias", ITimeOfDay::PARAM_SHADOWSC4_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[4], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 5: Bias", ITimeOfDay::PARAM_SHADOWSC5_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[5], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 5: Slope Bias", ITimeOfDay::PARAM_SHADOWSC5_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[5], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 6: Bias", ITimeOfDay::PARAM_SHADOWSC6_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[6], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 6: Slope Bias", ITimeOfDay::PARAM_SHADOWSC6_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[6], 0.0f, 500.0f);
AddVar("Shadows", "", "Cascade 7: Bias", ITimeOfDay::PARAM_SHADOWSC7_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthConstBias[7], 0.0f, 10.0f);
AddVar("Shadows", "", "Cascade 7: Slope Bias", ITimeOfDay::PARAM_SHADOWSC7_SLOPE_BIAS, ITimeOfDay::TYPE_FLOAT, arrDepthSlopeBias[7], 0.0f, 500.0f);
AddVar("Shadows", "", "Shadow jittering", ITimeOfDay::PARAM_SHADOW_JITTERING, ITimeOfDay::TYPE_FLOAT, 2.5f, 0.f, 10.f);
AddVar("Obsolete", "", "HDR dynamic power factor", ITimeOfDay::PARAM_HDR_DYNAMIC_POWER_FACTOR, ITimeOfDay::TYPE_FLOAT, 0.0f, -4.0f, 4.0f);
AddVar("Obsolete", "", "Sky brightening (terrain occlusion)", ITimeOfDay::PARAM_TERRAIN_OCCL_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 0.3f, 0.f, 1.f);
AddVar("Obsolete", "", "Sun color multiplier", ITimeOfDay::PARAM_SUN_COLOR_MULTIPLIER, ITimeOfDay::TYPE_FLOAT, 1.0f, 0.0f, 16.0f);
}
void CEnvironmentPreset::Serialize(Serialization::IArchive& ar)
{
for (size_t i = 0; i < ITimeOfDay::PARAM_TOTAL; ++i)
{
ar(m_vars[i], "var");
}
}
void CEnvironmentPreset::Update(float t)
{
for (size_t i = 0; i < ITimeOfDay::PARAM_TOTAL; ++i)
{
m_vars[i].Update(t);
}
}
CTimeOfDayVariable* CEnvironmentPreset::GetVar(const char* varName)
{
for (size_t i = 0; i < ITimeOfDay::PARAM_TOTAL; ++i)
{
if (strcmp(m_vars[i].GetName(), varName) == 0)
{
return &m_vars[i];
}
}
return NULL;
}
bool CEnvironmentPreset::InterpolateVarInRange(ITimeOfDay::ETimeOfDayParamID id, float fMin, float fMax, unsigned int nCount, Vec3* resultArray) const
{
const float fdx = 1.0f / float(nCount);
float normX = 0.0f;
for (unsigned int i = 0; i < nCount; ++i)
{
const float time = Lerp(fMin, fMax, normX);
resultArray[i] = m_vars[id].GetInterpolatedAt(time);
normX += fdx;
}
return true;
}
void CEnvironmentPreset::AddVar(const char* group, const char* displayName, const char* name, ITimeOfDay::ETimeOfDayParamID nParamId, ITimeOfDay::EVariableType type, float defVal0, float defVal1, float defVal2)
{
CTimeOfDayVariable& var = m_vars[nParamId];
var.Init(group, displayName, name, nParamId, type, defVal0, defVal1, defVal2);
}
@@ -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 _environment_preset_h_
#define _environment_preset_h_
#pragma once
#include <Bezier.h>
class CBezierSpline
{
public:
CBezierSpline();
~CBezierSpline();
void Init(float fDefaultValue);
float Evaluate(float t) const;
void SetKeys(const SBezierKey* keysArray, unsigned int keysArraySize) { m_keys.resize(keysArraySize); memcpy(&m_keys[0], keysArray, keysArraySize * sizeof(SBezierKey)); }
void GetKeys(SBezierKey* keys) const { memcpy(keys, &m_keys[0], m_keys.size() * sizeof(SBezierKey)); }
void InsertKey(SAnimTime time, float value);
void UpdateKeyForTime(float fTime, float value);
void Resize(size_t nSize) { m_keys.resize(nSize); }
size_t GetKeyCount() const { return m_keys.size(); }
const SBezierKey& GetKey(size_t nIndex) const { return m_keys[nIndex]; }
SBezierKey& GetKey(size_t nIndex) { return m_keys[nIndex]; }
void Serialize(Serialization::IArchive& ar);
private:
typedef std::vector<SBezierKey> TKeyContainer;
TKeyContainer m_keys;
struct SCompKeyTime
{
bool operator()(const TKeyContainer::value_type& l, const TKeyContainer::value_type& r) const { return l.m_time < r.m_time; }
bool operator()(SAnimTime l, const TKeyContainer::value_type& r) const { return l < r.m_time; }
bool operator()(const TKeyContainer::value_type& l, SAnimTime r) const { return l.m_time < r; }
};
};
//////////////////////////////////////////////////////////////////////////
class CTimeOfDayVariable
{
public:
CTimeOfDayVariable();
~CTimeOfDayVariable();
void Init(const char* group, const char* displayName, const char* name, ITimeOfDay::ETimeOfDayParamID nParamId, ITimeOfDay::EVariableType type, float defVal0, float defVal1, float defVal2);
void Update(float time);
Vec3 GetInterpolatedAt(float t) const;
ITimeOfDay::EVariableType GetType() const {return m_type; }
const char* GetName() const { return m_name; }
const char* GetDisplayName() const { return m_displayName; }
const char* GetGroupName() const { return m_group; }
const Vec3 GetValue() const { return m_value; }
float GetMinValue() const { return m_minValue; }
float GetMaxValue() const { return m_maxValue; }
const CBezierSpline* GetSpline(int nIndex) const
{
if (nIndex >= 0 && nIndex < Vec3::component_count)
{
return &m_spline[nIndex];
}
else
{
return NULL;
}
}
CBezierSpline* GetSpline(int nIndex)
{
if (nIndex >= 0 && nIndex < Vec3::component_count)
{
return &m_spline[nIndex];
}
else
{
return NULL;
}
}
size_t GetSplineKeyCount(int nSpline) const;
bool GetSplineKeys(int nSpline, SBezierKey* keysArray, unsigned int keysArraySize) const;
bool SetSplineKeys(int nSpline, const SBezierKey* keysArray, unsigned int keysArraySize);
bool UpdateSplineKeyForTime(int nSpline, float fTime, float newKey);
void Serialize(Serialization::IArchive& ar);
private:
ITimeOfDay::ETimeOfDayParamID m_id;
ITimeOfDay::EVariableType m_type;
const char* m_name; // Variable name.
const char* m_displayName; // Variable user readable name.
const char* m_group; // Group name.
float m_minValue;
float m_maxValue;
Vec3 m_value;
CBezierSpline m_spline[Vec3::component_count]; //spline for each component in m_value
};
//////////////////////////////////////////////////////////////////////////
class CEnvironmentPreset
{
public:
CEnvironmentPreset();
~CEnvironmentPreset();
void ResetVariables();
void Update(float t);
const CTimeOfDayVariable* GetVar(ITimeOfDay::ETimeOfDayParamID id) const { return &m_vars[id]; }
CTimeOfDayVariable* GetVar(ITimeOfDay::ETimeOfDayParamID id) { return &m_vars[id]; }
CTimeOfDayVariable* GetVar(const char* varName);
bool InterpolateVarInRange(ITimeOfDay::ETimeOfDayParamID id, float fMin, float fMax, unsigned int nCount, Vec3* resultArray) const;
void Serialize(Serialization::IArchive& ar);
private:
void AddVar(const char* group, const char* displayName, const char* name, ITimeOfDay::ETimeOfDayParamID nParamId, ITimeOfDay::EVariableType type, float defVal0, float defVal1, float defVal2);
CTimeOfDayVariable m_vars[ITimeOfDay::PARAM_TOTAL];
};
#endif //_environment_preset_h_
@@ -1,559 +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 "FogVolumeRenderNode.h"
#include "VisAreas.h"
#include "CREFogVolume.h"
#include "Cry_Geo.h"
#include "ObjMan.h"
#include "ClipVolumeManager.h"
#include "Environment/OceanEnvironmentBus.h"
#include <limits>
AABB CFogVolumeRenderNode::s_tracableFogVolumeArea(Vec3(0, 0, 0), Vec3(0, 0, 0));
StaticInstance<CFogVolumeRenderNode::CachedFogVolumes> CFogVolumeRenderNode::s_cachedFogVolumes;
StaticInstance<CFogVolumeRenderNode::GlobalFogVolumeMap> CFogVolumeRenderNode::s_globalFogVolumeMap;
bool CFogVolumeRenderNode::s_forceTraceableAreaUpdate(false);
void CFogVolumeRenderNode::StaticReset()
{
stl::free_container(s_cachedFogVolumes);
}
void CFogVolumeRenderNode::ForceTraceableAreaUpdate()
{
s_forceTraceableAreaUpdate = true;
}
void CFogVolumeRenderNode::SetTraceableArea(const AABB& traceableArea, [[maybe_unused]] const SRenderingPassInfo& passInfo)
{
// do we bother?
if (!GetCVars()->e_Fog || !GetCVars()->e_FogVolumes)
{
return;
}
if (GetCVars()->e_VolumetricFog != 0)
{
return;
}
// is update of traceable areas necessary
if (!s_forceTraceableAreaUpdate)
{
if ((s_tracableFogVolumeArea.GetCenter() - traceableArea.GetCenter()).GetLengthSquared() < 1e-4f && (s_tracableFogVolumeArea.GetSize() - traceableArea.GetSize()).GetLengthSquared() < 1e-4f)
{
return;
}
}
// set new area and reset list of traceable fog volumes
s_tracableFogVolumeArea = traceableArea;
s_cachedFogVolumes.resize(0);
// collect all candidates
Vec3 traceableAreaCenter(s_tracableFogVolumeArea.GetCenter());
IVisArea* pVisAreaOfCenter(GetVisAreaManager() ? GetVisAreaManager()->GetVisAreaFromPos(traceableAreaCenter) : NULL);
GlobalFogVolumeMap::const_iterator itEnd(s_globalFogVolumeMap.end());
for (GlobalFogVolumeMap::const_iterator it(s_globalFogVolumeMap.begin()); it != itEnd; ++it)
{
const CFogVolumeRenderNode* pFogVolume(*it);
if (pVisAreaOfCenter || (!pVisAreaOfCenter && !pFogVolume->GetEntityVisArea())) // if outside only add fog volumes which are outside as well
{
if (Overlap::AABB_AABB(s_tracableFogVolumeArea, pFogVolume->m_WSBBox)) // bb of fog volume overlaps with traceable area
{
s_cachedFogVolumes.push_back(SCachedFogVolume(pFogVolume, Vec3(pFogVolume->m_pos - traceableAreaCenter).GetLengthSquared()));
}
}
}
// sort by distance
std::sort(s_cachedFogVolumes.begin(), s_cachedFogVolumes.end());
// reset force-update flags
s_forceTraceableAreaUpdate = false;
}
void CFogVolumeRenderNode::RegisterFogVolume(const CFogVolumeRenderNode* pFogVolume)
{
GlobalFogVolumeMap::const_iterator it(s_globalFogVolumeMap.find(pFogVolume));
assert(it == s_globalFogVolumeMap.end() &&
"CFogVolumeRenderNode::RegisterFogVolume() -- Fog volume already registered!");
if (it == s_globalFogVolumeMap.end())
{
s_globalFogVolumeMap.insert(pFogVolume);
ForceTraceableAreaUpdate();
}
}
void CFogVolumeRenderNode::UnregisterFogVolume(const CFogVolumeRenderNode* pFogVolume)
{
GlobalFogVolumeMap::iterator it(s_globalFogVolumeMap.find(pFogVolume));
assert(it != s_globalFogVolumeMap.end() &&
"CFogVolumeRenderNode::UnRegisterFogVolume() -- Fog volume previously not registered!");
if (it != s_globalFogVolumeMap.end())
{
s_globalFogVolumeMap.erase(it);
ForceTraceableAreaUpdate();
}
}
CFogVolumeRenderNode::CFogVolumeRenderNode()
: m_matNodeWS()
, m_matWS()
, m_matWSInv()
, m_volumeType(0)
, m_pos(0, 0, 0)
, m_x(1, 0, 0)
, m_y(0, 1, 0)
, m_z(0, 0, 1)
, m_size(1, 1, 1)
, m_scale(1, 1, 1)
, m_globalDensity(1)
, m_densityOffset(0)
, m_nearCutoff(0)
, m_fHDRDynamic(0)
, m_softEdges(1)
, m_color(1, 1, 1, 1)
, m_useGlobalFogColor(false)
, m_affectsThisAreaOnly(false)
, m_rampParams(0, 1, 0)
, m_updateFrameID(0)
, m_windInfluence(1)
, m_noiseElapsedTime(-5000.0f)
, m_densityNoiseScale(0)
, m_densityNoiseOffset(0)
, m_densityNoiseTimeFrequency(0)
, m_densityNoiseFrequency(1, 1, 1)
, m_heightFallOffDir(0, 0, 1)
, m_heightFallOffDirScaled(0, 0, 1)
, m_heightFallOffShift(0, 0, 0)
, m_heightFallOffBasePoint(0, 0, 0)
, m_localBounds(Vec3(-0.5f, -0.5f, -0.5f), Vec3(0.5f, 0.5f, 0.5f))
, m_globalDensityFader()
, m_pMatFogVolEllipsoid(0)
, m_pMatFogVolBox(0)
, m_WSBBox()
, m_cachedSoftEdgesLerp(1, 0)
, m_cachedFogColor(1, 1, 1, 1)
{
m_matNodeWS.SetIdentity();
m_matWS.SetIdentity();
m_matWSInv.SetIdentity();
m_windOffset.x = cry_random(0.0f, 1000.0f);
m_windOffset.y = cry_random(0.0f, 1000.0f);
m_windOffset.z = cry_random(0.0f, 1000.0f);
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
m_pFogVolumeRenderElement[i] = (CREFogVolume*) GetRenderer()->EF_CreateRE(eDATA_FogVolume);
}
m_pMatFogVolEllipsoid = Get3DEngine()->m_pMatFogVolEllipsoid;
m_pMatFogVolBox = Get3DEngine()->m_pMatFogVolBox;
//Get3DEngine()->RegisterEntity( this );
RegisterFogVolume(this);
}
CFogVolumeRenderNode::~CFogVolumeRenderNode()
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
if (m_pFogVolumeRenderElement[i])
{
m_pFogVolumeRenderElement[i]->Release(false);
m_pFogVolumeRenderElement[i] = 0;
}
}
UnregisterFogVolume(this);
Get3DEngine()->FreeRenderNodeState(this);
}
void CFogVolumeRenderNode::UpdateFogVolumeMatrices()
{
// update matrices used for ray tracing, distance sorting, etc.
Matrix34 mtx = Matrix34::CreateFromVectors(m_size.x * m_x * 0.5f, m_size.y * m_y * 0.5f, m_size.z * m_z * 0.5f, m_pos);
m_matWS = mtx;
m_matWSInv = mtx.GetInverted();
}
void CFogVolumeRenderNode::UpdateWorldSpaceBBox()
{
// update bounding box in world space used for culling
m_WSBBox.SetTransformedAABB(m_matNodeWS, m_localBounds);
}
void CFogVolumeRenderNode::UpdateHeightFallOffBasePoint()
{
m_heightFallOffBasePoint = m_pos + m_heightFallOffShift;
}
void CFogVolumeRenderNode::SetFogVolumeProperties(const SFogVolumeProperties& properties)
{
m_globalDensityFader.SetInvalid();
assert(properties.m_size.x > 0 && properties.m_size.y > 0 && properties.m_size.z > 0);
if ((m_size - properties.m_size).GetLengthSquared() > 1e-4)
{
m_size = properties.m_size;
m_localBounds.min = Vec3(-0.5f, -0.5f, -0.5f).CompMul(m_size);
m_localBounds.max = -m_localBounds.min;
UpdateWorldSpaceBBox();
}
m_volumeType = properties.m_volumeType;
assert(m_volumeType >= 0 && m_volumeType <= 1);
m_color = properties.m_color;
assert(properties.m_globalDensity >= 0);
m_useGlobalFogColor = properties.m_useGlobalFogColor;
m_globalDensity = properties.m_globalDensity;
m_densityOffset = properties.m_densityOffset;
m_nearCutoff = properties.m_nearCutoff;
m_fHDRDynamic = properties.m_fHDRDynamic;
assert(properties.m_softEdges >= 0 && properties.m_softEdges <= 1);
m_softEdges = properties.m_softEdges;
// IgnoreVisArea and AffectsThisAreaOnly don't work concurrently.
SetRndFlags(ERF_RENDER_ALWAYS, properties.m_ignoresVisAreas && !properties.m_affectsThisAreaOnly);
m_affectsThisAreaOnly = properties.m_affectsThisAreaOnly;
float latiArc(DEG2RAD(90.0f - properties.m_heightFallOffDirLati));
float longArc(DEG2RAD(properties.m_heightFallOffDirLong));
float sinLati(sinf(latiArc));
float cosLati(cosf(latiArc));
float sinLong(sinf(longArc));
float cosLong(cosf(longArc));
m_heightFallOffDir = Vec3(sinLati * cosLong, sinLati * sinLong, cosLati);
m_heightFallOffShift = m_heightFallOffDir * properties.m_heightFallOffShift;
m_heightFallOffDirScaled = m_heightFallOffDir * properties.m_heightFallOffScale;
UpdateHeightFallOffBasePoint();
m_rampParams = Vec3(properties.m_rampStart, properties.m_rampEnd, properties.m_rampInfluence);
m_windInfluence = properties.m_windInfluence;
m_densityNoiseScale = properties.m_densityNoiseScale;
m_densityNoiseOffset = properties.m_densityNoiseOffset + 1.0f;
m_densityNoiseTimeFrequency = properties.m_densityNoiseTimeFrequency;
m_densityNoiseFrequency = properties.m_densityNoiseFrequency * 0.01f;// scale the value to useful range
}
const Matrix34& CFogVolumeRenderNode::GetMatrix() const
{
return m_matNodeWS;
}
void CFogVolumeRenderNode::GetLocalBounds(AABB& bbox)
{
bbox = m_localBounds;
};
void CFogVolumeRenderNode::SetMatrix(const Matrix34& mat)
{
m_matNodeWS = mat;
// get translation and rotational part of fog volume from entity matrix
// scale is specified explicitly as fog volumes can be non-uniformly scaled
m_pos = m_matNodeWS.GetTranslation();
m_x = m_matNodeWS.GetColumn(0);
m_y = m_matNodeWS.GetColumn(1);
m_z = m_matNodeWS.GetColumn(2);
UpdateFogVolumeMatrices();
UpdateWorldSpaceBBox();
UpdateHeightFallOffBasePoint();
Get3DEngine()->RegisterEntity(this);
ForceTraceableAreaUpdate();
}
void CFogVolumeRenderNode::SetScale(const Vec3& scale)
{
m_scale = scale;
}
void CFogVolumeRenderNode::FadeGlobalDensity(float fadeTime, float newGlobalDensity)
{
if (newGlobalDensity >= 0)
{
if (fadeTime == 0)
{
m_globalDensity = newGlobalDensity;
m_globalDensityFader.SetInvalid();
}
else if (fadeTime > 0)
{
float curFrameTime(gEnv->pTimer->GetCurrTime());
m_globalDensityFader.Set(curFrameTime, curFrameTime + fadeTime, m_globalDensity, newGlobalDensity);
}
}
}
const char* CFogVolumeRenderNode::GetEntityClassName() const
{
return "FogVolume";
}
const char* CFogVolumeRenderNode::GetName() const
{
return "FogVolume";
}
ColorF CFogVolumeRenderNode::GetFogColor() const
{
//FUNCTION_PROFILER_3DENGINE
Vec3 fogColor(m_color.r, m_color.g, m_color.b);
bool bVolFogEnabled = (GetCVars()->e_VolumetricFog != 0);
if (bVolFogEnabled)
{
if (m_useGlobalFogColor)
{
Get3DEngine()->GetGlobalParameter(E3DPARAM_VOLFOG2_COLOR, fogColor);
}
}
else
{
if (m_useGlobalFogColor)
{
fogColor = Get3DEngine()->GetFogColor();
}
bool bHDRModeEnabled = false;
GetRenderer()->EF_Query(EFQ_HDRModeEnabled, bHDRModeEnabled);
if (bHDRModeEnabled)
{
const float HDRDynamicMultiplier = 2.0f;
fogColor *= powf(HDRDynamicMultiplier, m_fHDRDynamic);
}
}
return fogColor;
}
Vec2 CFogVolumeRenderNode::GetSoftEdgeLerp(const Vec3& viewerPosOS) const
{
// Volumetric fog doesn't need special treatment when camera is in the ellipsoid.
if (GetCVars()->e_VolumetricFog != 0)
{
return Vec2(m_softEdges, 1.0f - m_softEdges);
}
//FUNCTION_PROFILER_3DENGINE
// ramp down soft edge factor as soon as camera enters the ellipsoid
float softEdge(m_softEdges * clamp_tpl((viewerPosOS.GetLength() - 0.95f) * 20.0f, 0.0f, 1.0f));
return Vec2(softEdge, 1.0f - softEdge);
}
bool CFogVolumeRenderNode::IsViewerInsideVolume(const SRenderingPassInfo& passInfo) const
{
const CCamera& cam(passInfo.GetCamera());
// check if fog volumes bounding box intersects the near clipping plane
const Plane* pNearPlane(cam.GetFrustumPlane(FR_PLANE_NEAR));
Vec3 pntOnNearPlane(cam.GetPosition() - pNearPlane->DistFromPlane(cam.GetPosition()) * pNearPlane->n);
Vec3 pntOnNearPlaneOS(m_matWSInv.TransformPoint(pntOnNearPlane));
Vec3 nearPlaneOS_n(m_matWSInv.TransformVector(pNearPlane->n) /*.GetNormalized()*/);
f32 nearPlaneOS_d(-nearPlaneOS_n.Dot(pntOnNearPlaneOS));
// get extreme lengths
float t(fabsf(nearPlaneOS_n.x) + fabsf(nearPlaneOS_n.y) + fabsf(nearPlaneOS_n.z));
//float t( 0.0f );
//if( nearPlaneOS_n.x >= 0 ) t += -nearPlaneOS_n.x; else t += nearPlaneOS_n.x;
//if( nearPlaneOS_n.y >= 0 ) t += -nearPlaneOS_n.y; else t += nearPlaneOS_n.y;
//if( nearPlaneOS_n.z >= 0 ) t += -nearPlaneOS_n.z; else t += nearPlaneOS_n.z;
float t0 = t + nearPlaneOS_d;
float t1 = -t + nearPlaneOS_d;
return t0 * t1 < 0.0f;
}
void CFogVolumeRenderNode::Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo)
{
FUNCTION_PROFILER_3DENGINE;
// anything to render?
if (passInfo.IsRecursivePass())
{
return;
}
if (!m_pMatFogVolBox || !m_pMatFogVolEllipsoid || GetCVars()->e_Fog == 0 || GetCVars()->e_FogVolumes == 0)
{
return;
}
const int32 fillThreadID = passInfo.ThreadID();
if (!m_pFogVolumeRenderElement[fillThreadID])
{
return;
}
if (m_globalDensityFader.IsValid())
{
float curFrameTime(gEnv->pTimer->GetCurrTime());
m_globalDensity = m_globalDensityFader.GetValue(curFrameTime);
if (!m_globalDensityFader.IsTimeInRange(curFrameTime))
{
m_globalDensityFader.SetInvalid();
}
}
// transform camera into fog volumes object space (where fog volume is a unit-sphere at (0,0,0))
const CCamera& cam(passInfo.GetCamera());
Vec3 viewerPosWS(cam.GetPosition());
Vec3 viewerPosOS(m_matWSInv * viewerPosWS);
m_cachedFogColor = GetFogColor();
m_cachedSoftEdgesLerp = GetSoftEdgeLerp(viewerPosOS);
bool bVolFog = (GetCVars()->e_VolumetricFog != 0);
// reset elapsed time for noise when FogVolume stayed out of viewport for 30 frames.
// this prevents the time from being too large number.
if ((m_updateFrameID + 30) < passInfo.GetMainFrameID() && m_noiseElapsedTime > 5000.0f)
{
m_noiseElapsedTime = -5000.0f;
}
if (bVolFog && m_densityNoiseScale > 0.0f && m_updateFrameID != passInfo.GetMainFrameID())
{
Vec3 wind = Get3DEngine()->GetGlobalWind(false);
const float elapsedTime = gEnv->pTimer->GetFrameTime();
m_windOffset = ((-m_windInfluence * elapsedTime) * wind) + m_windOffset;
const float windOffsetSpan = 1000.0f;// it should match the constant value in FogVolume.cfx
m_windOffset.x = m_windOffset.x - floor(m_windOffset.x / windOffsetSpan) * windOffsetSpan;
m_windOffset.y = m_windOffset.y - floor(m_windOffset.y / windOffsetSpan) * windOffsetSpan;
m_windOffset.z = m_windOffset.z - floor(m_windOffset.z / windOffsetSpan) * windOffsetSpan;
m_noiseElapsedTime += m_densityNoiseTimeFrequency * elapsedTime;
m_updateFrameID = passInfo.GetMainFrameID();
}
float densityOffset = bVolFog ? (m_densityOffset * 0.001f) : m_densityOffset;// scale the value to useful range
// set render element attributes
m_pFogVolumeRenderElement[fillThreadID]->m_center = m_pos;
m_pFogVolumeRenderElement[fillThreadID]->m_viewerInsideVolume = IsViewerInsideVolume(passInfo) ? 1 : 0;
m_pFogVolumeRenderElement[fillThreadID]->m_affectsThisAreaOnly = m_affectsThisAreaOnly ? 1 : 0;
m_pFogVolumeRenderElement[fillThreadID]->m_stencilRef = rParam.nClipVolumeStencilRef;
m_pFogVolumeRenderElement[fillThreadID]->m_volumeType = (m_volumeType != 0) ? 1 : 0;
m_pFogVolumeRenderElement[fillThreadID]->m_localAABB = m_localBounds;
m_pFogVolumeRenderElement[fillThreadID]->m_matWSInv = m_matWSInv;
m_pFogVolumeRenderElement[fillThreadID]->m_fogColor = m_cachedFogColor;
m_pFogVolumeRenderElement[fillThreadID]->m_globalDensity = m_globalDensity;
m_pFogVolumeRenderElement[fillThreadID]->m_densityOffset = densityOffset;
m_pFogVolumeRenderElement[fillThreadID]->m_nearCutoff = m_nearCutoff;
m_pFogVolumeRenderElement[fillThreadID]->m_softEdgesLerp = m_cachedSoftEdgesLerp;
m_pFogVolumeRenderElement[fillThreadID]->m_heightFallOffDirScaled = m_heightFallOffDirScaled;
m_pFogVolumeRenderElement[fillThreadID]->m_heightFallOffBasePoint = m_heightFallOffBasePoint;
m_pFogVolumeRenderElement[fillThreadID]->m_eyePosInWS = viewerPosWS;
m_pFogVolumeRenderElement[fillThreadID]->m_eyePosInOS = viewerPosOS;
m_pFogVolumeRenderElement[fillThreadID]->m_rampParams = m_rampParams;
m_pFogVolumeRenderElement[fillThreadID]->m_windOffset = m_windOffset;
m_pFogVolumeRenderElement[fillThreadID]->m_noiseScale = m_densityNoiseScale;
m_pFogVolumeRenderElement[fillThreadID]->m_noiseFreq = m_densityNoiseFrequency;
m_pFogVolumeRenderElement[fillThreadID]->m_noiseOffset = m_densityNoiseOffset;
m_pFogVolumeRenderElement[fillThreadID]->m_noiseElapsedTime = m_noiseElapsedTime;
m_pFogVolumeRenderElement[fillThreadID]->m_scale = m_scale;
if (bVolFog && GetCVars()->e_FogVolumesTiledInjection)
{
// add FogVolume to volumetric fog renderer
GetRenderer()->PushFogVolume(m_pFogVolumeRenderElement[fillThreadID], passInfo);
}
else
{
IRenderer* pRenderer = GetRenderer();
CRenderObject* pRenderObject = pRenderer->EF_GetObject_Temp(fillThreadID);
if (!pRenderObject)
{
return;
}
// set basic render object properties
pRenderObject->m_II.m_Matrix = m_matNodeWS;
pRenderObject->m_fSort = 0;
int nAfterWater = GetObjManager()->IsAfterWater(m_pos, passInfo) ? 1 : 0;
// TODO: add constant factor to sortID to make fog volumes render before all other alpha transparent geometry (or have separate render list?)
pRenderObject->m_fSort = WATER_LEVEL_SORTID_OFFSET * 0.5f;
// get shader item
SShaderItem& shaderItem(0 != rParam.pMaterial ? rParam.pMaterial->GetShaderItem(0) :
1 == m_volumeType ? m_pMatFogVolBox->GetShaderItem(0) : m_pMatFogVolEllipsoid->GetShaderItem(0));
// get target render list
int nList = bVolFog ? EFSLIST_FOG_VOLUME : EFSLIST_TRANSP;
// add to renderer
GetRenderer()->EF_AddEf(m_pFogVolumeRenderElement[fillThreadID], shaderItem, pRenderObject, passInfo, nList, nAfterWater, SRendItemSorter(rParam.rendItemSorter));
}
}
void CFogVolumeRenderNode::SetMaterial(_smart_ptr<IMaterial> pMat)
{
}
void CFogVolumeRenderNode::GetMemoryUsage(ICrySizer* pSizer) const
{
SIZER_COMPONENT_NAME(pSizer, "FogVolumeNode");
pSizer->AddObject(this, sizeof(*this));
}
void CFogVolumeRenderNode::OffsetPosition(const Vec3& delta)
{
if (m_pRNTmpData)
{
m_pRNTmpData->OffsetPosition(delta);
}
m_pos += delta;
m_matNodeWS.SetTranslation(m_matNodeWS.GetTranslation() + delta);
m_matWS.SetTranslation(m_matWS.GetTranslation() + delta);
m_matWSInv = m_matWS.GetInverted();
m_heightFallOffBasePoint += delta;
m_WSBBox.Move(delta);
}
@@ -1,217 +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_FOGVOLUMERENDERNODE_H
#define CRYINCLUDE_CRY3DENGINE_FOGVOLUMERENDERNODE_H
#pragma once
class CREFogVolume;
class CFogVolumeRenderNode
: public IFogVolumeRenderNode
, public Cry3DEngineBase
{
public:
static void StaticReset();
static void SetTraceableArea(const AABB& traceableArea, const SRenderingPassInfo& passInfo);
static void TraceFogVolumes(const Vec3& vPos, const AABB& objBBox, SFogVolumeData& fogVolData, const SRenderingPassInfo& passInfo, bool fogVolumeShadingQuality);
static bool OverlapProjectedAABB(const AABB& objBBox0, const AABB& objBBox1, const CCamera& camera);
public:
CFogVolumeRenderNode();
// implements IFogVolumeRenderNode
virtual void SetFogVolumeProperties(const SFogVolumeProperties& properties);
virtual const Matrix34& GetMatrix() const;
virtual void FadeGlobalDensity(float fadeTime, float newGlobalDensity);
// implements IRenderNode
virtual void GetLocalBounds(AABB& bbox);
virtual void SetMatrix(const Matrix34& mat);
virtual void SetScale(const Vec3& scale);
virtual EERType GetRenderNodeType();
virtual const char* GetEntityClassName() const;
virtual const char* GetName() const;
virtual Vec3 GetPos(bool bWorldOnly = true) const;
virtual void Render(const SRendParams& rParam, const SRenderingPassInfo& passInfo);
void SetMaterial(_smart_ptr<IMaterial> pMat) override;
virtual _smart_ptr<IMaterial> GetMaterial(Vec3* pHitPos);
virtual _smart_ptr<IMaterial> GetMaterialOverride() { return NULL; }
virtual float GetMaxViewDist();
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
virtual const AABB GetBBox() const { return m_WSBBox; }
virtual void SetBBox(const AABB& WSBBox) { m_WSBBox = WSBBox; }
virtual void FillBBox(AABB& aabb);
virtual void OffsetPosition(const Vec3& delta);
float GetGlobalDensity() const { return m_globalDensity; }
float GetDensityoffset() const { return m_densityOffset; }
Vec3 GetHeightFallOffBasePoint() const { return m_heightFallOffBasePoint; }
Vec3 GetHeightFallOffDirScaled() const { return m_heightFallOffDirScaled; }
ILINE bool IsAffectsThisAreaOnly() const { return m_affectsThisAreaOnly; }
int GetVolumeType() const { return m_volumeType; }
private:
static void RegisterFogVolume(const CFogVolumeRenderNode* pFogVolume);
static void UnregisterFogVolume(const CFogVolumeRenderNode* pFogVolume);
private:
~CFogVolumeRenderNode();
void UpdateFogVolumeMatrices();
void UpdateWorldSpaceBBox();
void UpdateHeightFallOffBasePoint();
ColorF GetFogColor() const;
Vec2 GetSoftEdgeLerp(const Vec3& viewerPosOS) const;
bool IsViewerInsideVolume(const SRenderingPassInfo& passInfo) const;
void GetVolumetricFogColorEllipsoid(const Vec3& worldPos, const SRenderingPassInfo& passInfo, ColorF& resultColor) const;
void GetVolumetricFogColorBox(const Vec3& worldPos, const SRenderingPassInfo& passInfo, ColorF& resultColor) const;
static void ForceTraceableAreaUpdate();
private:
struct SCachedFogVolume
{
SCachedFogVolume()
: m_pFogVol(0)
, m_distToCenterSq(0) {}
SCachedFogVolume(const CFogVolumeRenderNode* pFogVol, float distToCenterSq)
: m_pFogVol(pFogVol)
, m_distToCenterSq(distToCenterSq)
{
}
bool operator < (const SCachedFogVolume& rhs) const
{
return m_distToCenterSq > rhs.m_distToCenterSq;
}
const CFogVolumeRenderNode* m_pFogVol;
float m_distToCenterSq;
};
typedef std::vector< SCachedFogVolume > CachedFogVolumes;
typedef std::set< const CFogVolumeRenderNode* > GlobalFogVolumeMap;
static AABB s_tracableFogVolumeArea;
static StaticInstance<CachedFogVolumes> s_cachedFogVolumes;
static StaticInstance<GlobalFogVolumeMap> s_globalFogVolumeMap;
static bool s_forceTraceableAreaUpdate;
struct SFader
{
SFader()
: m_startTime(0)
, m_endTime(0)
, m_startValue(0)
, m_endValue(0)
{
}
void Set(float startTime, float endTime, float startValue, float endValue)
{
m_startTime = startTime;
m_endTime = endTime;
m_startValue = startValue;
m_endValue = endValue;
}
void SetInvalid()
{
Set(0, 0, 0, 0);
}
bool IsValid()
{
return m_startTime >= 0 && m_endTime > m_startTime && m_startValue != m_endValue;
}
bool IsTimeInRange(float time)
{
return time >= m_startTime && time <= m_endTime;
}
float GetValue(float time)
{
float t = clamp_tpl((time - m_startTime) / (m_endTime - m_startTime), 0.0f, 1.0f);
return m_startValue + t * (m_endValue - m_startValue);
}
private:
float m_startTime;
float m_endTime;
float m_startValue;
float m_endValue;
};
private:
Matrix34 m_matNodeWS;
Matrix34 m_matWS;
Matrix34 m_matWSInv;
int m_volumeType;
Vec3 m_pos;
Vec3 m_x;
Vec3 m_y;
Vec3 m_z;
// size of fog set by SFogVolumeProperties
Vec3 m_size;
// scale on entity
Vec3 m_scale;
float m_globalDensity;
float m_densityOffset;
float m_nearCutoff;
float m_fHDRDynamic;
float m_softEdges;
ColorF m_color;
bool m_useGlobalFogColor;
bool m_affectsThisAreaOnly;
Vec3 m_rampParams;
uint32 m_updateFrameID;
float m_windInfluence;
Vec3 m_windOffset;
float m_noiseElapsedTime;
float m_densityNoiseScale;
float m_densityNoiseOffset;
float m_densityNoiseTimeFrequency;
Vec3 m_densityNoiseFrequency;
Vec3 m_heightFallOffDir;
Vec3 m_heightFallOffDirScaled;
Vec3 m_heightFallOffShift;
Vec3 m_heightFallOffBasePoint;
AABB m_localBounds;
SFader m_globalDensityFader;
_smart_ptr< IMaterial > m_pMatFogVolEllipsoid;
_smart_ptr< IMaterial > m_pMatFogVolBox;
CREFogVolume* m_pFogVolumeRenderElement[RT_COMMAND_BUF_COUNT];
AABB m_WSBBox;
Vec2 m_cachedSoftEdgesLerp;
ColorF m_cachedFogColor;
};
#endif // CRYINCLUDE_CRY3DENGINE_FOGVOLUMERENDERNODE_H
@@ -1,399 +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 "FogVolumeRenderNode.h"
#include "VisAreas.h"
#include "CREFogVolume.h"
#include "Cry_Geo.h"
#include "ObjMan.h"
///////////////////////////////////////////////////////////////////////////////
inline static float expf_s(float arg)
{
return expf(clamp_tpl(arg, -80.0f, 80.0f));
}
AABB UnprojectAABB2D(const AABB& aabb, const CCamera& camera)
{
Vec3 results[4];
camera.Unproject(Vec3(aabb.min.x, aabb.min.y, 1), results[0]);
camera.Unproject(Vec3(aabb.max.x, aabb.min.y, 1), results[1]);
camera.Unproject(Vec3(aabb.max.x, aabb.max.y, 1), results[2]);
camera.Unproject(Vec3(aabb.min.x, aabb.max.y, 1), results[3]);
AABB newAABB(AABB::RESET);
newAABB.Add(results[0]);
newAABB.Add(results[1]);
newAABB.Add(results[2]);
newAABB.Add(results[3]);
return newAABB;
}
AABB GetProjectedQuadFromAABB(const AABB& aabb, const CCamera& camera)
{
// Get all 8 points of the AABB
Vec3 aabbPoints[] =
{
Vec3(aabb.max.x, aabb.max.y, aabb.max.z),
Vec3(aabb.max.x, aabb.min.y, aabb.max.z),
Vec3(aabb.min.x, aabb.min.y, aabb.max.z),
Vec3(aabb.min.x, aabb.max.y, aabb.max.z),
Vec3(aabb.max.x, aabb.max.y, aabb.min.z),
Vec3(aabb.max.x, aabb.min.y, aabb.min.z),
Vec3(aabb.min.x, aabb.min.y, aabb.min.z),
Vec3(aabb.min.x, aabb.max.y, aabb.min.z),
};
const int numAABBPoints = AZ_ARRAY_SIZE(aabbPoints);
AZ_Assert(numAABBPoints==8,"you should have 8 points in the aabb");
// Project each AABB point and construct another AABB.
AABB quadResult(AABB::RESET);
for (int i = 0; i < numAABBPoints; ++i)
{
Vec3 projectedPoint;
camera.Project(aabbPoints[i], projectedPoint);
quadResult.Add(projectedPoint);
}
return quadResult;
}
// To know if aabb are aligned with camera, we test if projected quads overlap.
bool CFogVolumeRenderNode::OverlapProjectedAABB(const AABB& aabb0, const AABB& aabb1, const CCamera& camera)
{
// quads are AABB2D.
AABB quad0 = GetProjectedQuadFromAABB(aabb0, camera);
AABB quad1 = GetProjectedQuadFromAABB(aabb1, camera);
bool bOverlap = Overlap::AABB_AABB2D(quad0, quad1);
return bOverlap;
}
void AverageFogVolume(SFogVolumeData& fogVolData, const CFogVolumeRenderNode* pFogVol)
{
AABB& avgAABBoxOut = fogVolData.avgAABBox;
avgAABBoxOut.Add(pFogVol->GetBBox());
// ratio is used to approximate fog volumes contribution depending of the importance of their size.
float ratio = pFogVol->GetBBox().GetRadius() / avgAABBoxOut.GetRadius();
fogVolData.m_heightFallOffBasePoint = Lerp(fogVolData.m_heightFallOffBasePoint,pFogVol->GetHeightFallOffBasePoint(), ratio);
fogVolData.m_heightFallOffDirScaled = Lerp(fogVolData.m_heightFallOffDirScaled,pFogVol->GetHeightFallOffDirScaled(), ratio);
fogVolData.m_densityOffset = Lerp(fogVolData.m_densityOffset, pFogVol->GetDensityoffset(), ratio);
fogVolData.m_globalDensity = Lerp(fogVolData.m_globalDensity, pFogVol->GetGlobalDensity(), ratio);
fogVolData.m_volumeType |= pFogVol->GetVolumeType();
}
///////////////////////////////////////////////////////////////////////////////
// TraceFogVolumes :
// if object intersects/is aligned with fog volumes then register these fog volumes,
// check if object is in front of the fog volume and compute average color.
// if highVertexShadingQuality average fog volume box.
///////////////////////////////////////////////////////////////////////////////
void CFogVolumeRenderNode::TraceFogVolumes(const Vec3& objPosition, const AABB& objAABB, SFogVolumeData& fogVolData, const SRenderingPassInfo& passInfo, bool fogVolumeShadingQuality)
{
FUNCTION_PROFILER_3DENGINE;
PrefetchLine(&s_tracableFogVolumeArea, 0);
// init default result
ColorF localFogColor = ColorF(0.0f, 0.0f, 0.0f, 0.0f);
// We will "accumulate" fog volumes contribution the same way that fog color.
// trace is needed when volumetric fog is off.
if (GetCVars()->e_Fog && GetCVars()->e_FogVolumes && (GetCVars()->e_VolumetricFog == 0))
{
const Vec3 worldPos = objPosition;
// init view ray
Vec3 camPos(s_tracableFogVolumeArea.GetCenter());
Lineseg lineseg(camPos, objPosition);
#ifdef _DEBUG
const SCachedFogVolume* prev(0);
#endif
// loop over all traceable fog volumes
CachedFogVolumes::const_iterator itEnd(s_cachedFogVolumes.end());
for (CachedFogVolumes::const_iterator it(s_cachedFogVolumes.begin()); it != itEnd; ++it)
{
// get current fog volume
const CFogVolumeRenderNode* pFogVol((*it).m_pFogVol);
bool isAligned = false;
bool isFrontOfBoxCenter = false;
// only trace visible fog volumes
if (!(pFogVol->GetRndFlags() & ERF_HIDDEN))
{
bool projectedAABBIntersect = false;
bool isInside = Overlap::Point_AABB(objPosition, pFogVol->m_WSBBox);
if (fogVolumeShadingQuality)
{
projectedAABBIntersect = OverlapProjectedAABB(pFogVol->m_WSBBox, objAABB, passInfo.GetCamera());
isInside = isInside || Overlap::AABB_AABB(objAABB, pFogVol->m_WSBBox);
}
// check if view ray intersects with bounding box of current fog volume
isAligned = Overlap::Lineseg_AABB(lineseg, pFogVol->m_WSBBox);
if (projectedAABBIntersect || isAligned)
{
// compute contribution of current fog volume
ColorF color(0,0,0);
// Get distance camera to fog volume.
const CCamera& cam(passInfo.GetCamera());
Vec3 cameraToObject(objPosition - cam.GetPosition());
Vec3 cameraToFogVolume(pFogVol->m_WSBBox.GetCenter() - cam.GetPosition());
isFrontOfBoxCenter = (cameraToFogVolume.GetLengthSquared() > cameraToObject.GetLengthSquared());
// if particle is in front of the box center and not inside the box, then do not accumulate fog color.
if (isFrontOfBoxCenter && !isInside)
{
continue;
}
if (fogVolumeShadingQuality)
{
// Accumulate this fogVolData
AverageFogVolume(fogVolData, pFogVol);
color = pFogVol->GetFogColor();
}
else
{
if (0 == pFogVol->m_volumeType)
{
pFogVol->GetVolumetricFogColorEllipsoid(worldPos, passInfo, color);
}
else
{
pFogVol->GetVolumetricFogColorBox(worldPos, passInfo, color);
}
color.a = 1.0f - color.a; // 0 = transparent, 1 = opaque
}
// blend fog colors
localFogColor.r = Lerp(localFogColor.r, color.r, color.a);
localFogColor.g = Lerp(localFogColor.g, color.g, color.a);
localFogColor.b = Lerp(localFogColor.b, color.b, color.a);
localFogColor.a = Lerp(localFogColor.a, 1.0f, color.a);
}
}
#ifdef _DEBUG
if (prev)
{
assert(prev->m_distToCenterSq >= (*it).m_distToCenterSq);
prev = &(*it);
}
#endif
}
const float fDivisor = (float)fsel(-localFogColor.a, 1.0f, localFogColor.a);
const float fMultiplier = (float)fsel(-localFogColor.a, 0.0f, 1.0f / fDivisor);
localFogColor.r *= fMultiplier;
localFogColor.g *= fMultiplier;
localFogColor.b *= fMultiplier;
}
localFogColor.a = 1.0f - localFogColor.a;
fogVolData.fogColor = localFogColor;
}
///////////////////////////////////////////////////////////////////////////////
void CFogVolumeRenderNode::GetVolumetricFogColorEllipsoid(const Vec3& worldPos, const SRenderingPassInfo& passInfo, ColorF& resultColor) const
{
const CCamera& cam(passInfo.GetCamera());
Vec3 camPos(cam.GetPosition());
Vec3 camDir(cam.GetViewdir());
Vec3 cameraLookDir(worldPos - camPos);
resultColor = ColorF(1.0f, 1.0f, 1.0f, 1.0f);
if (cameraLookDir.GetLengthSquared() > 1e-4f)
{
// setup ray tracing in OS
Vec3 cameraPosInOSx2(m_matWSInv.TransformPoint(camPos) * 2.0f);
Vec3 cameraLookDirInOS(m_matWSInv.TransformVector(cameraLookDir));
float tI(sqrtf(cameraLookDirInOS.Dot(cameraLookDirInOS)));
float invOfScaledCamDirLength(1.0f / tI);
cameraLookDirInOS *= invOfScaledCamDirLength;
// calc coefficients for ellipsoid parametrization (just a simple unit-sphere in its own space)
float B(cameraPosInOSx2.Dot(cameraLookDirInOS));
float Bsq(B * B);
float C(cameraPosInOSx2.Dot(cameraPosInOSx2) - 4.0f);
// solve quadratic equation
float discr(Bsq - C);
if (discr >= 0.0)
{
float discrSqrt = sqrtf(discr);
// ray hit
Vec3 cameraPosInWS(camPos);
Vec3 cameraLookDirInWS((worldPos - camPos) * invOfScaledCamDirLength);
//////////////////////////////////////////////////////////////////////////
float tS(max(0.5f * (-B - discrSqrt), 0.0f)); // clamp to zero so front ray-ellipsoid intersection is NOT behind camera
float tE(max(0.5f * (-B + discrSqrt), 0.0f)); // clamp to zero so back ray-ellipsoid intersection is NOT behind camera
//float tI( ( worldPos - camPos ).Dot( camDir ) / cameraLookDirInWS.Dot( camDir ) );
tI = max(tS, min(tI, tE)); // clamp to range [tS, tE]
Vec3 front(tS * cameraLookDirInWS + cameraPosInWS);
Vec3 dist((tI - tS) * cameraLookDirInWS);
float distLength(dist.GetLength());
float fogInt(distLength * expf_s(-(front - m_heightFallOffBasePoint).Dot(m_heightFallOffDirScaled)));
//////////////////////////////////////////////////////////////////////////
float heightDiff(dist.Dot(m_heightFallOffDirScaled));
if (fabsf(heightDiff) > 0.001f)
{
fogInt *= (1.0f - expf_s(-heightDiff)) / heightDiff;
}
float softArg(clamp_tpl(discr * m_cachedSoftEdgesLerp.x + m_cachedSoftEdgesLerp.y, 0.0f, 1.0f));
fogInt *= softArg * (2.0f - softArg);
float fog(expf_s(-m_globalDensity * fogInt));
resultColor = ColorF(m_cachedFogColor.r, m_cachedFogColor.g, m_cachedFogColor.b, min(fog, 1.0f));
}
}
}
///////////////////////////////////////////////////////////////////////////////
void CFogVolumeRenderNode::GetVolumetricFogColorBox(const Vec3& worldPos, const SRenderingPassInfo& passInfo, ColorF& resultColor) const
{
const CCamera& cam(passInfo.GetCamera());
Vec3 camPos(cam.GetPosition());
Vec3 cameraLookDir(worldPos - camPos);
resultColor = ColorF(1.0f, 1.0f, 1.0f, 1.0f);
if (cameraLookDir.GetLengthSquared() > 1e-4f)
{
// setup ray tracing in OS
Vec3 cameraPosInOS(m_matWSInv.TransformPoint(camPos));
Vec3 cameraLookDirInOS(m_matWSInv.TransformVector(cameraLookDir));
float tI(sqrtf(cameraLookDirInOS.Dot(cameraLookDirInOS)));
float invOfScaledCamDirLength(1.0f / tI);
cameraLookDirInOS *= invOfScaledCamDirLength;
const float fMax = std::numeric_limits<float>::max();
float tS(0), tE(fMax);
//TODO:
// May be worth profiling use of a loop here, iterating over elements of vector;
// might save on i-cache, but suspect we'll lose instruction interleaving and hit
// more register dependency issues.
//These fsels mean that the result is ignored if cameraLookDirInOS.x is 0.0f,
// avoiding a floating point compare. Avoiding the fcmp is ~15% faster
const float fXSelect = -fabsf(cameraLookDirInOS.x);
const float fXDivisor = (float)fsel(fXSelect, 1.0f, cameraLookDirInOS.x);
const float fXMultiplier = (float)fsel(fXSelect, 0.0f, 1.0f);
const float fXInvMultiplier = 1.0f - fXMultiplier;
//Accurate to 255/256ths on console
float invCameraDirInOSx = fres(fXDivisor); //(1.0f / fXDivisor);
float tPosPlane((1 - cameraPosInOS.x) * invCameraDirInOSx);
float tNegPlane((-1 - cameraPosInOS.x) * invCameraDirInOSx);
float tFrontFace = (float)fsel(-cameraLookDirInOS.x, tPosPlane, tNegPlane);
float tBackFace = (float)fsel(-cameraLookDirInOS.x, tNegPlane, tPosPlane);
tS = max(tS, tFrontFace * fXMultiplier);
tE = min(tE, (tBackFace * fXMultiplier) + (fXInvMultiplier * fMax));
const float fYSelect = -fabsf(cameraLookDirInOS.y);
const float fYDivisor = (float)fsel(fYSelect, 1.0f, cameraLookDirInOS.y);
const float fYMultiplier = (float)fsel(fYSelect, 0.0f, 1.0f);
const float fYInvMultiplier = 1.0f - fYMultiplier;
//Accurate to 255/256ths on console
float invCameraDirInOSy = fres(fYDivisor); //(1.0f / fYDivisor);
tPosPlane = ((1 - cameraPosInOS.y) * invCameraDirInOSy);
tNegPlane = ((-1 - cameraPosInOS.y) * invCameraDirInOSy);
tFrontFace = (float)fsel(-cameraLookDirInOS.y, tPosPlane, tNegPlane);
tBackFace = (float)fsel(-cameraLookDirInOS.y, tNegPlane, tPosPlane);
tS = max(tS, tFrontFace * fYMultiplier);
tE = min(tE, (tBackFace * fYMultiplier) + (fYInvMultiplier * fMax));
const float fZSelect = -fabsf(cameraLookDirInOS.z);
const float fZDivisor = (float)fsel(fZSelect, 1.0f, cameraLookDirInOS.z);
const float fZMultiplier = (float)fsel(fZSelect, 0.0f, 1.0f);
const float fZInvMultiplier = 1.0f - fZMultiplier;
//Accurate to 255/256ths on console
float invCameraDirInOSz = fres(fZDivisor); //(1.0f / fZDivisor);
tPosPlane = ((1 - cameraPosInOS.z) * invCameraDirInOSz);
tNegPlane = ((-1 - cameraPosInOS.z) * invCameraDirInOSz);
tFrontFace = (float)fsel(-cameraLookDirInOS.z, tPosPlane, tNegPlane);
tBackFace = (float)fsel(-cameraLookDirInOS.z, tNegPlane, tPosPlane);
tS = max(tS, tFrontFace * fZMultiplier);
tE = min(tE, (tBackFace * fZMultiplier) + (fZInvMultiplier * fMax));
tE = max(tE, 0.0f);
if (tS <= tE)
{
Vec3 cameraPosInWS(camPos);
Vec3 cameraLookDirInWS((worldPos - camPos) * invOfScaledCamDirLength);
//////////////////////////////////////////////////////////////////////////
tI = max(tS, min(tI, tE)); // clamp to range [tS, tE]
Vec3 front(tS * cameraLookDirInWS + cameraPosInWS);
Vec3 dist((tI - tS) * cameraLookDirInWS);
float distLength(dist.GetLength());
float fogInt(distLength * expf_s(-(front - m_heightFallOffBasePoint).Dot(m_heightFallOffDirScaled)));
//////////////////////////////////////////////////////////////////////////
float heightDiff(dist.Dot(m_heightFallOffDirScaled));
//heightDiff = fabsf( heightDiff ) > 0.001f ? heightDiff : 0.001f
heightDiff = (float)fsel((-fabsf(heightDiff) + 0.001f), 0.001f, heightDiff);
fogInt *= (1.0f - expf_s(-heightDiff)) * fres(heightDiff);
float fog(expf_s(-m_globalDensity * fogInt));
resultColor = ColorF(m_cachedFogColor.r, m_cachedFogColor.g, m_cachedFogColor.b, min(fog, 1.0f));
}
}
}
File diff suppressed because it is too large Load Diff
-309
View File
@@ -1,309 +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 : Manages geometry cache data
#ifndef CRYINCLUDE_CRY3DENGINE_GEOMCACHE_H
#define CRYINCLUDE_CRY3DENGINE_GEOMCACHE_H
#pragma once
#if defined(USE_GEOM_CACHES)
#include <IGeomCache.h>
#include "GeomCacheFileFormat.h"
struct SGeomCacheStaticMeshData
{
bool m_bUsePredictor;
uint8 m_positionPrecision[3];
float m_uvMax;
uint32 m_numVertices;
GeomCacheFile::EStreams m_constantStreams;
GeomCacheFile::EStreams m_animatedStreams;
uint64 m_hash;
AABB m_aabb;
string m_name;
std::vector<vtx_idx> m_indices;
std::vector<uint32> m_numIndices;
stl::aligned_vector<Vec3, 16> m_positions;
stl::aligned_vector<UCol, 16> m_colors;
stl::aligned_vector<Vec2, 16> m_texcoords;
stl::aligned_vector<SPipTangents, 16> m_tangents;
std::vector<uint16> m_materialIds;
std::vector<uint16> m_predictorData;
};
struct SGeomCacheStaticNodeData
{
uint32 m_meshOrGeometryIndex;
uint32 m_numChildren;
GeomCacheFile::ENodeType m_type;
GeomCacheFile::ETransformType m_transformType;
QuatTNS m_localTransform;
uint32 m_nameHash;
string m_name;
};
class CGeomCacheStreamReader
{
public:
CGeomCacheStreamReader(const char* pData, const size_t length)
: m_pData(pData)
, m_length(length)
, m_position(0) {}
template<class T>
bool Read(T* pDest, size_t numElements)
{
const size_t numBytes = sizeof(T) * numElements;
if (m_position + numBytes > m_length)
{
return false;
}
memcpy(pDest, &m_pData[m_position], numBytes);
m_position += numBytes;
return true;
}
template<class T>
bool Read(T* pDest)
{
const size_t numBytes = sizeof(T);
if (m_position + numBytes > m_length)
{
return false;
}
memcpy(pDest, &m_pData[m_position], numBytes);
m_position += numBytes;
return true;
}
private:
const char* m_pData;
const size_t m_length;
size_t m_position;
};
struct IGeomCacheListener
{
public:
virtual ~IGeomCacheListener() {}
virtual void OnGeomCacheStaticDataLoaded() = 0;
virtual void OnGeomCacheStaticDataUnloaded() = 0;
};
class CGeomCache
: public IGeomCache
, public IStreamCallback
, public Cry3DEngineBase
{
friend class CGeomCacheManager;
public:
CGeomCache(const char* pFileName);
~CGeomCache();
// Gets number of frames
uint GetNumFrames() const;
// Returns true if cache plays back from memory
bool PlaybackFromMemory() const;
const char* GetFrameData(const uint frameIndex) const;
uint64 GetCompressedAnimationDataSize() const;
// Gets the max extend of the geom cache through the entire animation
const AABB& GetAABB() const override;
void SetProcessedByRenderNode(bool processedByRenderNode) override { m_processedByRenderNode = processedByRenderNode; }
// Returns frame for specific time. Rounds to ceil or floor
uint GetFloorFrameIndex(const float time) const;
uint GetCeilFrameIndex(const float time) const;
// Frame infos
GeomCacheFile::EFrameType GetFrameType(const uint frameIndex) const;
uint64 GetFrameOffset(const uint frameIndex) const;
uint32 GetFrameSize(const uint frameIndex) const;
float GetFrameTime(const uint frameIndex) const;
uint GetPrevIFrame(const uint frameIndex) const;
uint GetNextIFrame(const uint frameIndex) const;
// Returns true if this frame uses motion prediction and needs the last two frames
bool NeedsPrevFrames(const uint frameIndex) const;
// Validates a frame range for reading from disk
void ValidateReadRange(const uint start, uint& end) const;
// Get block compression format
GeomCacheFile::EBlockCompressionFormat GetBlockCompressionFormat() const;
// Access to the mesh and node lists
const std::vector<SGeomCacheStaticMeshData>& GetStaticMeshData() const { return m_staticMeshData; }
const std::vector<SGeomCacheStaticNodeData>& GetStaticNodeData() const { return m_staticNodeData; }
const std::vector<phys_geometry*>& GetPhysicsGeometries() const { return m_physicsGeometries; }
// Listener interface for async loading
void AddListener(IGeomCacheListener* pListener);
void RemoveListener(IGeomCacheListener* pListener);
bool IsLoaded() const { return m_bLoaded; }
void UnloadData();
// Ref count for streams
uint GetNumStreams() const { return m_numStreams; }
void IncreaseNumStreams() { ++m_numStreams; }
void DecreaseNumStreams() { --m_numStreams; }
// IGeomCache
virtual int AddRef();
virtual int Release();
virtual bool IsValid() const { return m_bValid; }
virtual void SetMaterial(_smart_ptr<IMaterial> pMaterial);
virtual _smart_ptr<IMaterial> GetMaterial();
virtual const _smart_ptr<IMaterial> GetMaterial() const;
virtual const char* GetFilePath() const;
virtual float GetDuration() const;
virtual IGeomCache::SStatistics GetStatistics() const;
virtual void Reload();
// Static data streaming
void UpdateStreamableComponents(float importance, const Matrix34A& objMatrix, IRenderNode* pRenderNode, bool bFullUpdate);
void SetLastDrawMainFrameId(const uint32 id) { m_lastDrawMainFrameId = id; }
// IStreamable
virtual void StartStreaming(bool bFinishNow, IReadStream_AutoPtr* ppStream);
virtual int GetStreamableContentMemoryUsage(bool bJustForDebug);
virtual void ReleaseStreamableContent();
virtual void GetStreamableName(string& sName);
virtual uint32 GetLastDrawMainFrameId();
virtual bool IsUnloadable() const;
// IStreamCallback
virtual void StreamOnComplete(IReadStream* pStream, unsigned nError);
virtual void StreamAsyncOnComplete(IReadStream* pStream, unsigned nError);
private:
struct SFrameInfo
{
float m_frameTime;
uint32 m_frameType;
uint32 m_frameSize;
uint32 m_prevIFrame;
uint32 m_nextIFrame;
uint64 m_frameOffset;
};
void Shutdown();
bool LoadGeomCache();
bool ReadFrameInfos(AZ::IO::HandleType fileHandle, const uint32 numFrames);
bool ReadStaticBlock(AZ::IO::HandleType fileHandle, GeomCacheFile::EBlockCompressionFormat compressionFormat, std::vector<char>& compressedData);
bool DecompressStaticBlock(GeomCacheFile::EBlockCompressionFormat compressionFormat, const char* pCompressedData, std::vector<char>& decompressedData);
bool ReadMeshesStaticData(CGeomCacheStreamReader& reader, const char* pFileName);
bool ReadMeshStaticData(CGeomCacheStreamReader& reader, const GeomCacheFile::SMeshInfo& meshInfo,
SGeomCacheStaticMeshData& mesh, const char* pFileName);
bool LoadAnimatedData(const char* pData, const size_t bufferOffset);
bool ReadNodesStaticDataRec(CGeomCacheStreamReader& reader);
static bool CompareFrameTimes(const SFrameInfo& a, const SFrameInfo& b)
{
return a.m_frameTime < b.m_frameTime;
}
char* GetFrameData(const uint frameIndex);
bool m_bValid;
bool m_bLoaded;
int m_refCount;
_smart_ptr<IMaterial> m_pMaterial;
string m_fileName;
string m_lastError;
// Static data streaming state
bool m_bUseStreaming;
uint32 m_lastDrawMainFrameId;
IReadStreamPtr m_pStaticDataReadStream;
// Cache block compression format
GeomCacheFile::EBlockCompressionFormat m_blockCompressionFormat;
// Playback from memory flag
bool m_bPlaybackFromMemory;
// Number of frames
uint m_numFrames;
// Number of streams reading from this cache
uint m_numStreams;
// Offset of static mesh data
uint64 m_staticMeshDataOffset;
// Total size of animated data
uint64 m_compressedAnimationDataSize;
// Total size of uncompressed animation data
uint64 m_totalUncompressedAnimationSize;
// AABB of entire animation
AABB m_aabb;
// Static data size;
GeomCacheFile::SCompressedBlockHeader m_staticDataHeader;
// Frame infos
std::vector<SFrameInfo> m_frameInfos;
std::vector<SGeomCacheStaticMeshData> m_staticMeshData;
std::vector<SGeomCacheStaticNodeData> m_staticNodeData;
// Physics
std::vector<phys_geometry*> m_physicsGeometries;
// Holds references of static render meshes until cache object dies
std::vector<_smart_ptr<IRenderMesh> > m_staticRenderMeshes;
// Listeners
std::vector<IGeomCacheListener*> m_listeners;
// Animation data (memory playback)
std::vector<char> m_animationData;
// Only matters when e_streamCGF is 0
bool m_processedByRenderNode = true;
};
#endif
#endif // CRYINCLUDE_CRY3DENGINE_GEOMCACHE_H

Some files were not shown because too many files have changed in this diff Show More