diff --git a/Assets/Editor/MapScreenshotSettings.xml b/Assets/Editor/MapScreenshotSettings.xml
index 01f90db4b3..88a8a49aef 100644
--- a/Assets/Editor/MapScreenshotSettings.xml
+++ b/Assets/Editor/MapScreenshotSettings.xml
@@ -1,18 +1,5 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Assets/Editor/UserTools.xml b/Assets/Editor/UserTools.xml
index 8f971cbd5c..4cc197afbe 100644
--- a/Assets/Editor/UserTools.xml
+++ b/Assets/Editor/UserTools.xml
@@ -7,8 +7,6 @@
-
-
diff --git a/Assets/Engine/Config/AutoTestChain.cfg b/Assets/Engine/Config/AutoTestChain.cfg
index 8c6fae9020..4164acb271 100644
--- a/Assets/Engine/Config/AutoTestChain.cfg
+++ b/Assets/Engine/Config/AutoTestChain.cfg
@@ -1,16 +1,5 @@
ConsoleHide
-g_godMode=1
sys_warnings=0
con_showonload=1
-i_forcefeedback=0
-g_infiniteammo=1
-e_ObjectLayersActivation=0
-e_ObjectLayersActivationPhysics=0
-g_flashrenderingduringloading=0
sys_maxfps=0
r_vsync=0
-p_max_substeps=1
-demo_file=autotest
-demo_num_runs=0
-demo_quit=1
-demo_ai=1
diff --git a/Assets/Engine/Config/AutoTestTimeDemo.cfg b/Assets/Engine/Config/AutoTestTimeDemo.cfg
index 687158eda9..664ea94939 100644
--- a/Assets/Engine/Config/AutoTestTimeDemo.cfg
+++ b/Assets/Engine/Config/AutoTestTimeDemo.cfg
@@ -1,15 +1,5 @@
ConsoleHide
-g_godMode=1
-g_infiniteammo=1
r_displayinfo=1
s_profiling=1
sys_maxfps=0
-e_ObjectLayersActivation=0
-e_ObjectLayersActivationPhysics=0
-
-demo_file=autotest
-demo_num_runs=2
-demo_quit=1
-demo_savestats=1
-demo_profile=-1
demo
diff --git a/Assets/Engine/Config/AutotestPlaythrough.cfg b/Assets/Engine/Config/AutotestPlaythrough.cfg
index f453097972..664ea94939 100644
--- a/Assets/Engine/Config/AutotestPlaythrough.cfg
+++ b/Assets/Engine/Config/AutotestPlaythrough.cfg
@@ -1,12 +1,5 @@
ConsoleHide
-g_godMode=1
-g_infiniteammo=1
r_displayinfo=1
s_profiling=1
sys_maxfps=0
-demo_file=playthru
-demo_num_runs=2
-demo_quit=1
-demo_savestats=1
-demo_profile=-1
-demo
\ No newline at end of file
+demo
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg
index 626dce3ee4..04fb56f3ca 100644
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg
+++ b/Assets/Engine/Config/CVarGroups/sys_spec_Full.cfg
@@ -11,113 +11,16 @@
; default of this CVarGroup
= 7
-sys_spec_ObjectDetail=7
-sys_spec_Shading=7
-sys_spec_VolumetricEffects=7
-sys_spec_Shadows=7
-sys_spec_Texture=7
-sys_spec_Physics=7
-sys_spec_PostProcessing=7
-sys_spec_Particles=7
-sys_spec_Sound=7
-sys_spec_Water=7
-sys_spec_GameEffects=7
-sys_spec_light=7
-
[1]
-sys_spec_ObjectDetail=1
-sys_spec_Shading=1
-sys_spec_VolumetricEffects=1
-sys_spec_Shadows=1
-sys_spec_Texture=1
-sys_spec_Physics=1
-sys_spec_PostProcessing=1
-sys_spec_Particles=1
-sys_spec_Sound=1
-sys_spec_Water=1
-sys_spec_GameEffects=1
-sys_spec_light=1
[2]
-sys_spec_ObjectDetail=2
-sys_spec_Shading=2
-sys_spec_VolumetricEffects=2
-sys_spec_Shadows=2
-sys_spec_Texture=2
-sys_spec_Physics=2
-sys_spec_PostProcessing=2
-sys_spec_Particles=2
-sys_spec_Sound=2
-sys_spec_Water=2
-sys_spec_GameEffects=2
-sys_spec_light=2
[3]
-sys_spec_ObjectDetail=3
-sys_spec_Shading=3
-sys_spec_VolumetricEffects=3
-sys_spec_Shadows=3
-sys_spec_Texture=3
-sys_spec_Physics=3
-sys_spec_PostProcessing=3
-sys_spec_Particles=3
-sys_spec_Sound=3
-sys_spec_Water=3
-sys_spec_GameEffects=3
-sys_spec_light=3
[4]
-sys_spec_ObjectDetail=4
-sys_spec_Shading=4
-sys_spec_VolumetricEffects=4
-sys_spec_Shadows=4
-sys_spec_Texture=4
-sys_spec_Physics=4
-sys_spec_PostProcessing=4
-sys_spec_Particles=4
-sys_spec_Sound=4
-sys_spec_Water=4
-sys_spec_GameEffects=4
-sys_spec_light=4
[5]
-sys_spec_ObjectDetail=5
-sys_spec_Shading=5
-sys_spec_VolumetricEffects=5
-sys_spec_Shadows=5
-sys_spec_Texture=5
-sys_spec_Physics=5
-sys_spec_PostProcessing=5
-sys_spec_Particles=5
-sys_spec_Sound=5
-sys_spec_Water=5
-sys_spec_GameEffects=5
-sys_spec_light=5
[6]
-sys_spec_ObjectDetail=6
-sys_spec_Shading=6
-sys_spec_VolumetricEffects=6
-sys_spec_Shadows=6
-sys_spec_Texture=6
-sys_spec_Physics=6
-sys_spec_PostProcessing=6
-sys_spec_Particles=6
-sys_spec_Sound=6
-sys_spec_Water=6
-sys_spec_GameEffects=6
-sys_spec_light=6
[8]
-sys_spec_ObjectDetail=8
-sys_spec_Shading=8
-sys_spec_VolumetricEffects=8
-sys_spec_Shadows=8
-sys_spec_Texture=8
-sys_spec_Physics=8
-sys_spec_PostProcessing=8
-sys_spec_Particles=8
-sys_spec_Sound=8
-sys_spec_Water=8
-sys_spec_GameEffects=8
-sys_spec_light=8
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg
deleted file mode 100644
index 34e058d47d..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_GameEffects.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-mfx_Timeout = 0.01
-
-
-
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg
deleted file mode 100644
index a2996f7ded..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_ObjectDetail.cfg
+++ /dev/null
@@ -1,160 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-ca_AttachmentCullingRation=360
-es_DebrisLifetimeScale=1
-e_CoverageBufferReproj=6
-e_DecalsAllowGameDecals=1
-e_DecalsLifeTimeScale=2
-e_DecalsOverlapping=1
-e_Dissolve=2
-e_LightQuality=3
-e_LodMin=0
-e_LodRatio=20
-e_MaxViewDistSpecLerp=1
-e_MergedMeshesInstanceDist=1.0
-e_MergedMeshesPool=8192
-e_ObjQuality=3
-e_OcclusionCullingViewDistRatio=1
-e_ProcVegetation=1
-e_StatObjBufferRenderTasks=1
-e_StreamCgf=0
-e_TerrainLodRatio=1
-e_TerrainOcclusionCullingMaxDist=200
-e_Tessellation=0
-e_VegetationMinSize=0
-e_ViewDistMin=10
-e_ViewDistRatio=100
-e_ViewDistRatioCustom=100
-e_ViewDistRatioDetail=100
-e_ViewDistRatioLights=50
-e_ViewDistRatioVegetation=100
-r_DrawNearZRange=0.12
-r_FlaresTessellationRatio=1
-r_SilhouettePOM=0
-r_usezpass=2
-
-[1]
-ca_AttachmentCullingRation=145
-es_DebrisLifetimeScale=0.6
-e_DecalsLifeTimeScale=1
-e_Dissolve=0
-e_LightQuality=1
-e_LodRatio=10
-e_MaxViewDistSpecLerp=0.5
-e_ObjQuality=1
-e_TerrainOcclusionCullingMaxDist=130
-e_VegetationMinSize=0.5
-e_ViewDistRatioCustom=60
-e_ViewDistRatioDetail=25
-e_ViewDistRatioLights=25
-e_ViewDistRatioVegetation=21
-r_FlaresTessellationRatio=0.25
-r_usezpass=1
-e_ProcVegetation=0
-e_ViewDistRatio=50
-
-[2]
-ca_AttachmentCullingRation=145
-es_DebrisLifetimeScale=0.6
-e_DecalsLifeTimeScale=1
-e_Dissolve=0
-e_LightQuality=2
-e_LodRatio=10
-e_MaxViewDistSpecLerp=0.5
-e_ObjQuality=2
-e_TerrainOcclusionCullingMaxDist=130
-e_VegetationMinSize=0.5
-e_ViewDistRatioCustom=60
-e_ViewDistRatioDetail=25
-e_ViewDistRatioLights=25
-e_ViewDistRatioVegetation=50
-r_FlaresTessellationRatio=0.25
-r_usezpass=1
-e_ProcVegetation=1
-e_ViewDistRatio=50
-
-[3]
-ca_AttachmentCullingRation=145
-es_DebrisLifetimeScale=0.6
-e_DecalsLifeTimeScale=1
-e_Dissolve=0
-e_LightQuality=3
-e_LodRatio=10
-e_MaxViewDistSpecLerp=0.5
-e_ObjQuality=3
-e_TerrainOcclusionCullingMaxDist=130
-e_VegetationMinSize=0.5
-e_ViewDistRatioCustom=60
-e_ViewDistRatioDetail=25
-e_ViewDistRatioLights=25
-e_ViewDistRatioVegetation=50
-r_FlaresTessellationRatio=0.25
-r_usezpass=1
-e_ProcVegetation=1
-e_ViewDistRatio=75
-
-[4]
-ca_AttachmentCullingRation=145
-es_DebrisLifetimeScale=0.6
-e_DecalsLifeTimeScale=1
-e_Dissolve=0
-e_LightQuality=4
-e_LodRatio=10
-e_MaxViewDistSpecLerp=0.5
-e_ObjQuality=4
-e_TerrainOcclusionCullingMaxDist=130
-e_VegetationMinSize=0.5
-e_ViewDistRatioCustom=60
-e_ViewDistRatioDetail=25
-e_ViewDistRatioLights=25
-e_ViewDistRatioVegetation=50
-r_FlaresTessellationRatio=0.25
-r_usezpass=1
-e_ProcVegetation=1
-e_ViewDistRatio=75
-
-[5]
-ca_AttachmentCullingRation=145
-es_DebrisLifetimeScale=0.6
-e_DecalsLifeTimeScale=1
-e_LightQuality=1
-e_LodRatio=10
-e_MaxViewDistSpecLerp=0.5
-e_ObjQuality=1
-e_TerrainOcclusionCullingMaxDist=130
-e_VegetationMinSize=0.5
-e_ViewDistRatio=50
-e_ViewDistRatioCustom=60
-e_ViewDistRatioDetail=25
-e_ViewDistRatioLights=25
-e_ViewDistRatioVegetation=50
-r_FlaresTessellationRatio=0.25
-
-[6]
-ca_AttachmentCullingRation=300
-es_DebrisLifetimeScale=0.8
-e_LightQuality=2
-e_LodRatio=15
-e_ObjQuality=2
-e_ViewDistRatio=75
-e_ViewDistRatioDetail=35
-e_ViewDistRatioVegetation=75
-
-[8]
-ca_AttachmentCullingRation=400
-e_LightQuality=4
-e_LodRatio=40
-e_MergedMeshesInstanceDist=2.0
-e_MergedMeshesPool=16384
-e_ObjQuality=4
-e_TerrainLodRatio=0.5
-e_Tessellation=1
-e_ViewDistRatio=125
-e_ViewDistRatioCustom=125
-e_ViewDistRatioDetail=125
-e_ViewDistRatioLights=75
-e_ViewDistRatioVegetation=125
-r_DrawNearZRange = 0.08
-r_SilhouettePOM=1
\ No newline at end of file
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg
deleted file mode 100644
index 0a02170b97..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Particles.cfg
+++ /dev/null
@@ -1,94 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-e_ParticlesGI=1
-e_ParticlesPreload=0
-e_ParticlesMaxScreenFill=128
-e_ParticlesMinDrawPixels=1
-e_ParticlesMotionBlur=0
-e_ParticlesObjectCollisions=2
-e_ParticlesQuality=3
-e_ParticlesSortQuality=0
-e_ParticlesPoolSize=16384
-r_ParticlesHalfRes=0
-r_ParticlesTessellation=1
-r_ParticlesInstanceVertices=1
-r_ParticlesGpuMaxEmitCount=10000
-
-[1]
-e_ParticlesGI=0
-e_ParticlesPreload=1
-e_ParticlesMaxScreenFill=16
-e_ParticlesMinDrawPixels=2
-e_ParticlesObjectCollisions=1
-e_ParticlesQuality=2
-e_ParticlesPoolSize=4096
-r_ParticlesHalfRes=1
-r_ParticlesTessellation=0
-r_ParticlesInstanceVertices=0
-r_ParticlesGpuMaxEmitCount=10
-
-
-[2]
-e_ParticlesGI=0
-e_ParticlesPreload=1
-e_ParticlesMaxScreenFill=16
-e_ParticlesMinDrawPixels=2
-e_ParticlesObjectCollisions=1
-e_ParticlesQuality=2
-e_ParticlesPoolSize=4096
-r_ParticlesHalfRes=1
-r_ParticlesTessellation=0
-r_ParticlesInstanceVertices=0
-r_ParticlesGpuMaxEmitCount=100
-
-
-[3]
-e_ParticlesGI=0
-e_ParticlesPreload=1
-e_ParticlesMaxScreenFill=16
-e_ParticlesMinDrawPixels=2
-e_ParticlesObjectCollisions=1
-e_ParticlesQuality=2
-e_ParticlesPoolSize=4096
-r_ParticlesHalfRes=1
-r_ParticlesTessellation=0
-r_ParticlesInstanceVertices=0
-r_ParticlesGpuMaxEmitCount=500
-
-
-[4]
-e_ParticlesGI=0
-e_ParticlesPreload=1
-e_ParticlesMaxScreenFill=16
-e_ParticlesMinDrawPixels=2
-e_ParticlesObjectCollisions=1
-e_ParticlesQuality=2
-e_ParticlesPoolSize=4096
-r_ParticlesHalfRes=1
-r_ParticlesTessellation=0
-r_ParticlesInstanceVertices=0
-r_ParticlesGpuMaxEmitCount=1000
-
-
-[5]
-e_ParticlesMaxScreenFill=32
-e_ParticlesMinDrawPixels=1.5
-e_ParticlesObjectCollisions=1
-e_ParticlesQuality=1
-r_ParticlesHalfRes=1
-r_ParticlesTessellation=0
-r_ParticlesGpuMaxEmitCount=3000
-
-[6]
-e_ParticlesMaxScreenFill=64
-e_ParticlesObjectCollisions=1
-e_ParticlesQuality=2
-r_ParticlesGpuMaxEmitCount=5000
-
-[8]
-e_ParticlesMaxScreenFill=160
-e_ParticlesMotionBlur=1
-e_ParticlesQuality=4
-r_ParticlesGpuMaxEmitCount=1048576
\ No newline at end of file
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg
deleted file mode 100644
index 15d9fc61e3..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Physics.cfg
+++ /dev/null
@@ -1,100 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-es_MaxPhysDist=100
-es_MaxPhysDistInvisible=25
-e_CullVegActivation=50
-e_FoliageWindActivationDist=25
-e_PhysMinCellSize=4
-e_PhysOceanCell=0.5
-e_PhysProxyTriLimit=10000
-g_breakage_mem_limit=0
-g_breakage_particles_limit=160
-g_no_secondary_breaking=0
-g_tree_cut_reuse_dist=0
-p_gravity_z=-13
-p_max_entity_cells=300000
-p_max_MC_iters=6000
-p_max_object_splashes=3
-p_max_substeps=5
-p_max_substeps_large_group=5
-p_num_bodies_large_group=100
-p_splash_dist0=7
-p_splash_dist1=30
-p_splash_force0=10
-p_splash_force1=100
-p_splash_vel0=4.5
-p_splash_vel1=10
-v_vehicle_quality=4
-
-[1]
-es_MaxPhysDistInvisible=15
-e_CullVegActivation=30
-e_FoliageWindActivationDist=10
-e_PhysMinCellSize=16
-e_PhysOceanCell=1
-g_breakage_mem_limit=2000
-g_breakage_particles_limit=40
-g_no_secondary_breaking=1
-g_tree_cut_reuse_dist=1
-p_max_entity_cells=75000
-p_max_MC_iters=2000
-p_max_substeps=2
-
-[2]
-es_MaxPhysDistInvisible=15
-e_CullVegActivation=30
-e_FoliageWindActivationDist=10
-e_PhysMinCellSize=16
-e_PhysOceanCell=1
-g_breakage_mem_limit=2000
-g_breakage_particles_limit=40
-g_no_secondary_breaking=1
-g_tree_cut_reuse_dist=1
-p_max_entity_cells=75000
-p_max_MC_iters=2000
-p_max_substeps=2
-
-[3]
-es_MaxPhysDistInvisible=15
-e_CullVegActivation=30
-e_FoliageWindActivationDist=10
-e_PhysMinCellSize=16
-e_PhysOceanCell=1
-g_breakage_mem_limit=2000
-g_breakage_particles_limit=40
-g_no_secondary_breaking=1
-g_tree_cut_reuse_dist=1
-p_max_entity_cells=75000
-p_max_MC_iters=2000
-p_max_substeps=2
-
-[4]
-es_MaxPhysDistInvisible=15
-e_CullVegActivation=30
-e_FoliageWindActivationDist=10
-e_PhysMinCellSize=16
-e_PhysOceanCell=1
-g_breakage_mem_limit=2000
-g_breakage_particles_limit=40
-g_no_secondary_breaking=1
-g_tree_cut_reuse_dist=1
-p_max_entity_cells=75000
-p_max_MC_iters=2000
-p_max_substeps=2
-
-[5]
-es_MaxPhysDist=50
-es_MaxPhysDistInvisible=15
-e_CullVegActivation=30
-e_FoliageWindActivationDist=10
-e_PhysOceanCell=1
-g_breakage_particles_limit=80
-g_tree_cut_reuse_dist=0.35
-p_max_MC_iters=4000
-p_max_substeps=2
-
-[6]
-
-[8]
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg
deleted file mode 100644
index 9d2cd3754d..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_PostProcessing.cfg
+++ /dev/null
@@ -1,114 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-r_PostProcessEffects=1
-q_ShaderHDR=2
-q_ShaderPostProcess=2
-r_ChromaticAberration=0
-r_ColorGradingChartsCache=0
-r_DepthOfField=2
-r_Flares=1
-r_HDRBloomQuality=2
-r_MotionBlur=2
-r_MotionBlurMaxViewDist=100000
-r_MotionBlurQuality=1
-r_MotionBlurShutterSpeed=125
-r_Rain=2
-r_RainMaxViewDist_Deferred=150
-r_Sharpening=0
-r_Snow=2
-r_SunShafts=2
-r_TranspDepthFixup=1
-r_ToneMapTechnique=0
-r_ToneMapExposureType=0
-r_HDRBloom=1
-r_ColorGrading=1
-r_ColorSpace=0
-
-[1]
-q_ShaderHDR=1
-q_ShaderPostProcess=1
-r_ColorGrading=0
-r_DepthOfField=0
-r_Flares=0
-r_HDRBloom=0
-r_HDRBloomQuality=0
-r_MotionBlur=0
-r_MotionBlurMaxViewDist=16
-r_MotionBlurQuality=0
-r_Rain=1
-r_RainMaxViewDist_Deferred=40
-r_Snow=1
-r_SunShafts=0
-r_TranspDepthFixup=0
-r_ToneMapTechnique=3
-r_ToneMapExposureType=1
-r_ColorSpace=2
-
-
-[2]
-q_ShaderHDR=1
-q_ShaderPostProcess=1
-r_ColorGradingChartsCache=4
-r_DepthOfField=1
-r_Flares=0
-r_HDRBloomQuality=0
-r_MotionBlur=0
-r_MotionBlurMaxViewDist=16
-r_MotionBlurQuality=0
-r_Rain=1
-r_RainMaxViewDist_Deferred=40
-r_Snow=1
-r_SunShafts=1
-r_TranspDepthFixup=0
-
-
-[3]
-q_ShaderHDR=1
-q_ShaderPostProcess=2
-r_ColorGradingChartsCache=4
-r_DepthOfField=1
-r_HDRBloomQuality=1
-r_MotionBlur=0
-r_MotionBlurMaxViewDist=16
-r_MotionBlurQuality=0
-r_Rain=1
-r_RainMaxViewDist_Deferred=40
-r_Snow=1
-r_SunShafts=1
-r_TranspDepthFixup=0
-
-[4]
-q_ShaderHDR=1
-q_ShaderPostProcess=2
-r_ColorGradingChartsCache=4
-r_DepthOfField=1
-r_HDRBloomQuality=1
-r_MotionBlur=0
-r_MotionBlurMaxViewDist=16
-r_MotionBlurQuality=0
-r_Rain=1
-r_RainMaxViewDist_Deferred=40
-r_Snow=1
-r_SunShafts=1
-r_TranspDepthFixup=0
-
-[5]
-q_ShaderHDR=1
-q_ShaderPostProcess=1
-r_ColorGradingChartsCache=4
-r_MotionBlurMaxViewDist=16
-r_MotionBlurQuality=0
-r_RainMaxViewDist_Deferred=40
-r_TranspDepthFixup=0
-
-[6]
-q_ShaderHDR=1
-q_ShaderPostProcess=1
-r_RainMaxViewDist_Deferred=100
-
-[8]
-q_ShaderHDR=3
-q_ShaderPostProcess=3
-r_MotionBlurQuality=2
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg
deleted file mode 100644
index cf1bdf5184..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Quality.cfg
+++ /dev/null
@@ -1,98 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-q_ShaderGeneral=2
-q_ShaderMetal=2
-q_ShaderGlass=2
-q_ShaderVegetation=2
-q_ShaderIce=2
-q_ShaderTerrain=2
-q_ShaderShadow=2
-q_ShaderFX=2
-q_ShaderSky=2
-q_Renderer=2
-
-[1]
-q_ShaderGeneral=1
-q_ShaderMetal=1
-q_ShaderGlass=1
-q_ShaderVegetation=1
-q_ShaderIce=1
-q_ShaderTerrain=1
-q_ShaderShadow=1
-q_ShaderFX=1
-q_ShaderSky=1
-q_Renderer=1
-
-[2]
-q_ShaderGeneral=1
-q_ShaderMetal=1
-q_ShaderGlass=1
-q_ShaderVegetation=1
-q_ShaderIce=1
-q_ShaderTerrain=1
-q_ShaderShadow=1
-q_ShaderFX=1
-q_ShaderSky=1
-q_Renderer=1
-
-[3]
-q_ShaderGeneral=1
-q_ShaderMetal=1
-q_ShaderGlass=1
-q_ShaderVegetation=1
-q_ShaderIce=1
-q_ShaderTerrain=1
-q_ShaderShadow=1
-q_ShaderFX=1
-q_ShaderSky=1
-q_Renderer=2
-
-[4]
-q_ShaderGeneral=1
-q_ShaderMetal=1
-q_ShaderGlass=1
-q_ShaderVegetation=1
-q_ShaderIce=1
-q_ShaderTerrain=1
-q_ShaderShadow=1
-q_ShaderFX=1
-q_ShaderSky=1
-q_Renderer=2
-
-[5]
-q_ShaderGeneral=1
-q_ShaderMetal=1
-q_ShaderGlass=1
-q_ShaderVegetation=1
-q_ShaderIce=1
-q_ShaderTerrain=1
-q_ShaderShadow=1
-q_ShaderFX=1
-q_ShaderSky=1
-q_Renderer=1
-
-[6]
-q_ShaderGeneral=1
-q_ShaderMetal=1
-q_ShaderGlass=1
-q_ShaderVegetation=1
-q_ShaderIce=1
-q_ShaderTerrain=1
-q_ShaderShadow=1
-q_ShaderFX=1
-q_ShaderSky=1
-q_Renderer=1
-
-[8]
-q_ShaderGeneral=3
-q_ShaderMetal=3
-q_ShaderGlass=3
-q_ShaderVegetation=3
-q_ShaderIce=3
-q_ShaderTerrain=3
-q_ShaderShadow=3
-q_ShaderFX=3
-q_ShaderSky=3
-q_Renderer=3
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg
deleted file mode 100644
index eb379a8583..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Shading.cfg
+++ /dev/null
@@ -1,120 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-e_CacheNearestCubePicking=1
-e_DynamicLightsMaxEntityLights=16
-e_GI=1
-e_LightVolumes=1
-e_SkyUpdateRate=1
-e_TerrainAo=0
-e_VegetationUseTerrainColor=1
-r_DeferredShadingDepthBoundsTest=1
-r_DeferredShadingTiled=2
-r_DeferredShadingTiledHairQuality=1
-r_deferredShadingFilterGBuffer=0
-r_DeferredShadingSSS=1
-r_AntialiasingMode=3
-r_DetailDistance=8
-r_EnvTexUpdateInterval=0.05
-r_Refraction=1
-r_RefractionPartialResolves=2
-r_ssdo=1
-r_ssdoHalfRes=2
-r_ssdoColorBleeding=1
-r_SSReflections=1
-r_SSReflHalfRes=1
-r_VisAreaClipLightsPerPixel=1
-sys_spec_Quality=7
-
-[1]
-e_DynamicLightsMaxEntityLights=2
-e_GI=0
-e_SkyUpdateRate=0.5
-e_VegetationUseTerrainColor=0
-r_DeferredShadingTiled=0
-r_DeferredShadingTiledHairQuality=0
-r_DeferredShadingSSS=0
-r_AntialiasingMode=0
-r_DetailDistance=4
-r_EnvTexUpdateInterval=0.075
-r_Refraction=0
-r_RefractionPartialResolves=0
-r_ssdo=0
-r_ssdoHalfRes=1
-r_ssdoColorBleeding=0
-r_SSReflections=0
-sys_spec_Quality=1
-
-[2]
-e_DynamicLightsMaxEntityLights=2
-e_GI=0
-e_SkyUpdateRate=0.5
-e_VegetationUseTerrainColor=0
-r_DeferredShadingTiled=0
-r_DeferredShadingTiledHairQuality=0
-r_DeferredShadingSSS=0
-r_AntialiasingMode=0
-r_DetailDistance=4
-r_EnvTexUpdateInterval=0.075
-r_RefractionPartialResolves=0
-r_ssdo=0
-r_ssdoHalfRes=1
-r_ssdoColorBleeding=0
-r_SSReflections=0
-sys_spec_Quality=2
-
-[3]
-e_DynamicLightsMaxEntityLights=2
-e_GI=0
-e_SkyUpdateRate=0.5
-e_VegetationUseTerrainColor=0
-r_DeferredShadingTiled=0
-r_DeferredShadingTiledHairQuality=0
-r_DeferredShadingSSS=0
-r_AntialiasingMode=0
-r_DetailDistance=4
-r_EnvTexUpdateInterval=0.075
-r_RefractionPartialResolves=0
-r_ssdo=0
-r_ssdoColorBleeding=0
-r_SSReflections=0
-sys_spec_Quality=3
-
-[4]
-e_DynamicLightsMaxEntityLights=2
-e_GI=0
-e_SkyUpdateRate=0.5
-e_VegetationUseTerrainColor=0
-r_DeferredShadingTiled=0
-r_DeferredShadingTiledHairQuality=0
-r_DeferredShadingSSS=0
-r_AntialiasingMode=0
-r_DetailDistance=4
-r_EnvTexUpdateInterval=0.075
-r_RefractionPartialResolves=0
-r_ssdo=1
-r_ssdoHalfRes=1
-r_ssdoColorBleeding=0
-r_SSReflections=0
-sys_spec_Quality=4
-
-[5]
-e_DynamicLightsMaxEntityLights=7
-e_GI=0
-e_SkyUpdateRate=0.5
-r_DetailDistance=4
-r_EnvTexUpdateInterval=0.075
-r_SSReflections=0
-r_DeferredShadingTiledHairQuality=0
-r_DeferredShadingSSS=0
-sys_spec_Quality=5
-
-[6]
-e_DynamicLightsMaxEntityLights=11
-sys_spec_Quality=6
-
-[8]
-r_DeferredShadingTiledHairQuality=2
-r_SSReflHalfRes=0
-sys_spec_Quality=8
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg
deleted file mode 100644
index d43c28c09d..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Shadows.cfg
+++ /dev/null
@@ -1,116 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-e_GsmLodsNum=5
-e_GsmRange=3
-e_ParticlesShadows=1
-e_Shadows=1
-e_ShadowsBlendCascades=1
-e_ShadowsClouds=1
-e_ShadowsCastViewDistRatio=1
-e_ShadowsLodBiasFixed=0
-e_ShadowsMaxTexRes=1024
-e_ShadowsOnAlphaBlend=0
-e_ShadowsPoolSize=4096
-e_ShadowsResScale=4
-e_ShadowsTessellateCascades=1
-e_ShadowsTessellateDLights=0
-e_ShadowsUpdateViewDistRatio=256
-r_DrawNearShadows=1
-r_FogShadows=2
-r_FogShadowsWater=0
-r_ShadowJittering=2.5
-r_ShadowPoolMaxFrames=30
-r_ShadowPoolMaxTimeslicedUpdatesPerFrame=100
-r_ShadowsPCFiltering=1
-r_ShadowsCache=4
-r_ShadowsCacheFormat=1
-r_ShadowsCacheResolutions=6324,4214
-r_ShadowsUseClipVolume=1
-e_ObjShadowCastSpec=3
-
-[1]
-e_GsmLodsNum=3
-e_ParticlesShadows=0
-e_ShadowsBlendCascades=0
-e_ShadowsCastViewDistRatio=0.8
-e_ShadowsLodBiasFixed=1
-e_ShadowsMaxTexRes=512
-r_DrawNearShadows=0
-r_FogShadows=0
-r_ShadowJittering=0
-r_ShadowsCacheFormat=0
-r_ShadowsCacheResolutions=3162,2107
-e_ObjShadowCastSpec=1
-e_ShadowsPoolSize=1024
-
-[2]
-e_GsmLodsNum=4
-e_ParticlesShadows=0
-e_ShadowsBlendCascades=0
-e_ShadowsCastViewDistRatio=0.8
-e_ShadowsLodBiasFixed=1
-e_ShadowsMaxTexRes=512
-r_DrawNearShadows=0
-r_FogShadows=0
-r_ShadowJittering=0
-r_ShadowsCacheFormat=0
-r_ShadowsCacheResolutions=3162,2107
-e_ObjShadowCastSpec=1
-e_ShadowsPoolSize=1024
-
-[3]
-e_GsmLodsNum=4
-e_ParticlesShadows=0
-e_ShadowsBlendCascades=0
-e_ShadowsCastViewDistRatio=0.8
-e_ShadowsLodBiasFixed=1
-e_ShadowsMaxTexRes=512
-r_DrawNearShadows=0
-r_FogShadows=0
-r_ShadowJittering=0
-r_ShadowsCacheFormat=0
-r_ShadowsCacheResolutions=3162,2107
-e_ObjShadowCastSpec=1
-e_ShadowsPoolSize=1024
-
-[4]
-e_GsmLodsNum=4
-e_ParticlesShadows=0
-e_ShadowsBlendCascades=0
-e_ShadowsCastViewDistRatio=0.8
-e_ShadowsLodBiasFixed=1
-e_ShadowsMaxTexRes=512
-r_DrawNearShadows=0
-r_FogShadows=0
-r_ShadowJittering=0
-r_ShadowsCacheFormat=0
-r_ShadowsCacheResolutions=3162,2107
-e_ObjShadowCastSpec=1
-e_ShadowsPoolSize=1024
-
-[5]
-e_GsmLodsNum=4
-e_ParticlesShadows=0
-e_ShadowsBlendCascades=0
-e_ShadowsCastViewDistRatio=0.8
-e_ShadowsLodBiasFixed=1
-e_ShadowsMaxTexRes=512
-r_FogShadows=0
-r_ShadowJittering=1
-e_ObjShadowCastSpec=1
-r_ShadowsCacheResolutions=3162,2107
-
-[6]
-r_ShadowJittering=1
-e_ObjShadowCastSpec=2
-
-[8]
-r_FogShadows=1
-r_FogShadowsWater=1
-r_ShadowPoolMaxFrames=0
-r_ShadowPoolMaxTimeslicedUpdatesPerFrame=100
-e_ObjShadowCastSpec=4
-r_ShadowsCache=5
-r_ShadowsCacheResolutions=4214
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg
deleted file mode 100644
index 42bd4c7f02..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Sound.cfg
+++ /dev/null
@@ -1,17 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-[1]
-
-[2]
-
-[3]
-
-[4]
-
-[5]
-
-[6]
-
-[8]
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg
deleted file mode 100644
index 0e02c41ab2..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Texture.cfg
+++ /dev/null
@@ -1,94 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-e_TerrainTextureStreamingPoolItemsNum=64
-r_DynTexAtlasCloudsMaxSize=32
-r_DynTexAtlasSpritesMaxSize=32
-r_DynTexMaxSize=80
-r_EnvCMResolution=2
-r_EnvTexResolution=3
-r_ImposterRatio=1
-r_TexAtlasSize=2048
-r_TexMaxAnisotropy=4
-r_TexMinAnisotropy=4
-r_TexNoAnisoAlphaTest=0
-
-[1]
-e_TerrainTextureStreamingPoolItemsNum=16
-r_DynTexAtlasCloudsMaxSize=8
-r_DynTexAtlasSpritesMaxSize=8
-r_DynTexMaxSize=20
-r_EnvCMResolution=0
-r_EnvTexResolution=1
-r_ImposterRatio=2
-r_TexAtlasSize=512
-r_TexMaxAnisotropy=2
-r_TexMinAnisotropy=2
-r_TexNoAnisoAlphaTest=1
-
-[2]
-e_TerrainTextureStreamingPoolItemsNum=16
-r_DynTexAtlasCloudsMaxSize=8
-r_DynTexAtlasSpritesMaxSize=8
-r_DynTexMaxSize=20
-r_EnvCMResolution=0
-r_EnvTexResolution=1
-r_ImposterRatio=2
-r_TexAtlasSize=512
-r_TexMaxAnisotropy=2
-r_TexMinAnisotropy=2
-r_TexNoAnisoAlphaTest=1
-
-[3]
-e_TerrainTextureStreamingPoolItemsNum=16
-r_DynTexAtlasCloudsMaxSize=8
-r_DynTexAtlasSpritesMaxSize=8
-r_DynTexMaxSize=20
-r_EnvCMResolution=0
-r_EnvTexResolution=1
-r_ImposterRatio=2
-r_TexAtlasSize=512
-r_TexMaxAnisotropy=2
-r_TexMinAnisotropy=2
-r_TexNoAnisoAlphaTest=1
-
-[4]
-e_TerrainTextureStreamingPoolItemsNum=16
-r_DynTexAtlasCloudsMaxSize=8
-r_DynTexAtlasSpritesMaxSize=8
-r_DynTexMaxSize=20
-r_EnvCMResolution=0
-r_EnvTexResolution=1
-r_ImposterRatio=2
-r_TexAtlasSize=512
-r_TexMaxAnisotropy=2
-r_TexMinAnisotropy=2
-r_TexNoAnisoAlphaTest=1
-
-[5]
-r_DynTexAtlasCloudsMaxSize=24
-r_DynTexAtlasSpritesMaxSize=16
-r_DynTexMaxSize=50
-r_EnvCMResolution=0
-r_EnvTexResolution=1
-r_ImposterRatio=2
-r_TexAtlasSize=512
-r_TexMaxAnisotropy=2
-r_TexMinAnisotropy=2
-r_TexNoAnisoAlphaTest=1
-
-[6]
-r_DynTexAtlasCloudsMaxSize=24
-r_DynTexAtlasSpritesMaxSize=16
-r_DynTexMaxSize=60
-r_EnvCMResolution=1
-r_EnvTexResolution=2
-r_ImposterRatio=1.5
-r_TexMaxAnisotropy=8
-r_TexMinAnisotropy=8
-r_TexNoAnisoAlphaTest=1
-
-[8]
-r_TexMaxAnisotropy=16
-r_TexMinAnisotropy=16
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg
deleted file mode 100644
index 6b6c11ddf6..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_TextureResolution.cfg
+++ /dev/null
@@ -1,52 +0,0 @@
-[default]
-; dummy default for this CVarGroup (will be auto initialized during streaming system init or overridden by user via system.cfg)
-= 0
-
-; VRAM 1.0 GB
-r_TexturesStreaming=1
-r_TexturesStreamingMipBias=0
-r_TexturesstreamingMinUsableMips=8
-r_TexturesStreamingSkipMips=2
-r_TexturesStreamPoolSize=256
-
-[1]
-; VRAM 1.0 GB
-r_TexturesStreaming=0
-r_TexturesStreamingSkipMips=0
-r_TexturesStreamPoolSize=384
-
-[2]
-; VRAM 1.0 GB
-r_TexturesStreaming=0
-r_TexturesStreamingSkipMips=0
-r_TexturesStreamPoolSize=384
-
-[3]
-; VRAM 1.0 GB
-r_TexturesStreaming=0
-r_TexturesStreamingSkipMips=0
-r_TexturesStreamPoolSize=384
-
-[4]
-; VRAM 1.0 GB
-r_TexturesStreaming=0
-r_TexturesStreamingSkipMips=0
-r_TexturesStreamPoolSize=384
-
-[5]
-; VRAM 1.0 GB
-
-[6]
-; VRAM 1.5 GB
-r_TexturesStreamingSkipMips=1
-r_TexturesStreamPoolSize=512
-
-[7]
-; VRAM 2.0 GB
-r_TexturesStreamingSkipMips=0
-r_TexturesStreamPoolSize=640
-
-[8]
-; VRAM 3.0 GB
-r_TexturesStreamingSkipMips=0
-r_TexturesStreamPoolSize=1536
\ No newline at end of file
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg
deleted file mode 100644
index b6fdfec33c..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_VolumetricEffects.cfg
+++ /dev/null
@@ -1,26 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-e_Clouds=1
-r_Beams=1
-
-[1]
-r_Beams=0
-
-[2]
-r_Beams=0
-
-[3]
-r_Beams=0
-
-[4]
-r_Beams=0
-
-[5]
-r_Beams=0
-
-[6]
-r_Beams=0
-
-[8]
diff --git a/Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg b/Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg
deleted file mode 100644
index 720339dc98..0000000000
--- a/Assets/Engine/Config/CVarGroups/sys_spec_Water.cfg
+++ /dev/null
@@ -1,81 +0,0 @@
-[default]
-; default of this CVarGroup
-= 7
-
-e_WaterOceanFFT=1
-e_WaterTessellationAmount=10
-e_WaterTessellationSwathWidth=10
-q_ShaderWater=2
-r_WaterCaustics=1
-r_WaterReflections=1
-r_WaterReflectionsQuality=4
-r_WaterReflectionsMinVisiblePixelsUpdate=0.05
-r_WaterTessellationHW=0
-r_WaterUpdateDistance=0.2
-r_WaterUpdateFactor=0.0
-r_WaterVolumeCaustics=0
-r_WaterVolumeCausticsDensity=256
-r_WaterVolumeCausticsMaxDist=35
-r_WaterVolumeCausticsRes=1024
-r_WaterVolumeCausticsSnapFactor=1
-
-[1]
-e_WaterTessellationAmount=20
-q_ShaderWater=1
-r_WaterReflectionsQuality=0
-r_WaterUpdateDistance=1
-r_WaterUpdateFactor=0.1
-r_WaterVolumeCausticsDensity=64
-r_WaterVolumeCausticsMaxDist=20
-r_WaterVolumeCausticsRes=384
-
-[2]
-e_WaterTessellationAmount=20
-q_ShaderWater=1
-r_WaterReflectionsQuality=0
-r_WaterUpdateDistance=1
-r_WaterUpdateFactor=0.1
-r_WaterVolumeCausticsDensity=64
-r_WaterVolumeCausticsMaxDist=20
-r_WaterVolumeCausticsRes=384
-
-[3]
-e_WaterTessellationAmount=20
-q_ShaderWater=1
-r_WaterReflectionsQuality=0
-r_WaterUpdateDistance=1
-r_WaterUpdateFactor=0.05
-r_WaterVolumeCausticsDensity=64
-r_WaterVolumeCausticsMaxDist=20
-r_WaterVolumeCausticsRes=384
-
-[4]
-e_WaterTessellationAmount=20
-q_ShaderWater=1
-r_WaterReflectionsQuality=4
-r_WaterUpdateDistance=1
-r_WaterUpdateFactor=0.01
-r_WaterVolumeCausticsDensity=64
-r_WaterVolumeCausticsMaxDist=20
-r_WaterVolumeCausticsRes=384
-
-[5]
-e_WaterTessellationAmount=20
-q_ShaderWater=1
-r_WaterUpdateDistance=1
-r_WaterUpdateFactor=0.1
-r_WaterVolumeCausticsDensity=64
-r_WaterVolumeCausticsMaxDist=20
-r_WaterVolumeCausticsRes=384
-
-[6]
-r_WaterUpdateDistance=1
-r_WaterUpdateFactor=0.05
-r_WaterVolumeCausticsDensity=128
-r_WaterVolumeCausticsMaxDist=25
-r_WaterVolumeCausticsRes=512
-
-[8]
-e_WaterTessellationAmount=85
-r_WaterTessellationHW=1
-r_WaterVolumeCaustics=1
diff --git a/Assets/Engine/Config/aidebug.cfg b/Assets/Engine/Config/aidebug.cfg
index f8134c7461..b0eafaaa45 100644
--- a/Assets/Engine/Config/aidebug.cfg
+++ b/Assets/Engine/Config/aidebug.cfg
@@ -1,4 +1 @@
ai_DebugDraw = 1
-ai_DebugDrawNavigation = 1
-ai_DrawPath all
-ai_debugMNMAgentType MediumSizedCharacters
\ No newline at end of file
diff --git a/Assets/Engine/Config/artprof.cfg b/Assets/Engine/Config/artprof.cfg
index 2e1cf55a54..92b91623bf 100644
--- a/Assets/Engine/Config/artprof.cfg
+++ b/Assets/Engine/Config/artprof.cfg
@@ -1,7 +1,6 @@
; Setup useful cvars for artists profiling GPU cost
; Once in level (e.g. map c3mp_rooftop_gardens from the frontend/cmdline), in the console:
; exec artprof.cfg
-; Be sure also to set r_shadersAsyncActivation=0 in your user.cfg (or copy artprof_user.cfg -> user.cfg)
; used to allow loading of loose shaders
sys_pakPriority=0
@@ -9,19 +8,8 @@ sys_pakPriority=0
; because it's annoying and not relevant for artists
sys_pakLogInvalidFileAccess=0
-; disable fog volumes and particles as they can be misleading with r_measureOverdraw 4
-e_fogVolumes=0
-e_particles=0
-
; for convenience
-g_infiniteSuitEnergy=1
-g_infiniteAmmo=1
-g_timelimit=0
+
bind o "r_measureOverdraw 0"
bind p "r_measureOverdraw 4"
-bind k "r_artProfile 0"
-bind l "r_artProfile 1"
-
-; loading into an MP level with the map command stops you looking up and down unless you have a weapon
-i_giveitem scar
diff --git a/Assets/Engine/Config/artprof_user.cfg b/Assets/Engine/Config/artprof_user.cfg
index 673436f6f3..265021e120 100644
--- a/Assets/Engine/Config/artprof_user.cfg
+++ b/Assets/Engine/Config/artprof_user.cfg
@@ -1,6 +1,3 @@
-; disable async shader activation as it crashes when r_shadersAllowCompilation=1
-r_shadersAsyncActivation=0
-
; enable shader compiliation for r_measureOverdraw 4
r_shadersAllowCompilation=1
diff --git a/Assets/Engine/Config/benchmark_cpu.cfg b/Assets/Engine/Config/benchmark_cpu.cfg
index c75619107f..bbb3c9db95 100644
--- a/Assets/Engine/Config/benchmark_cpu.cfg
+++ b/Assets/Engine/Config/benchmark_cpu.cfg
@@ -1,13 +1,3 @@
-demo_restart_level = 2
-g_godMode=1
-g_infiniteammo=1
r_displayinfo=1
-demo_file = autotest
-demo_ai = 1
-demo_num_runs = 4
-demo_quit = 1
-hud_startPaused=0
sys_maxfps=0
-e_ObjectLayersActivation=0
-sys_flash = 0
r_vsync = 0
diff --git a/Assets/Engine/Config/benchmark_gpu.cfg b/Assets/Engine/Config/benchmark_gpu.cfg
index 7653b32d86..f0242d64d1 100644
--- a/Assets/Engine/Config/benchmark_gpu.cfg
+++ b/Assets/Engine/Config/benchmark_gpu.cfg
@@ -1,13 +1,3 @@
-demo_restart_level = 1
-g_godMode = 1
-g_infiniteammo = 1
r_displayinfo = 2
-demo_file = timedemo_short
-demo_ai = 0
-demo_num_runs = 2
-demo_quit = 1
--- hud_startPaused = 0
sys_maxfps = -1
--- e_ObjectLayersActivation = 0
--- sys_flash = 0
-r_vsync = 0
\ No newline at end of file
+r_vsync = 0
diff --git a/Assets/Engine/Config/mgpu.cfg b/Assets/Engine/Config/mgpu.cfg
index 93da7fdfd0..e69de29bb2 100644
--- a/Assets/Engine/Config/mgpu.cfg
+++ b/Assets/Engine/Config/mgpu.cfg
@@ -1,6 +0,0 @@
-r_ColorGradingChartsCache = 0
-r_waterupdateFactor = 0
-r_PostProcessHUD3DCache = 0
-e_gsmcache = 0
-r_ConditionalRendering = 0
-e_gicache = 0
\ No newline at end of file
diff --git a/Assets/Engine/Config/multiplayer.cfg b/Assets/Engine/Config/multiplayer.cfg
index eafa434f8e..e69de29bb2 100644
--- a/Assets/Engine/Config/multiplayer.cfg
+++ b/Assets/Engine/Config/multiplayer.cfg
@@ -1,77 +0,0 @@
-ag_turnSpeedParamScale=0.0
-aim_assistFalloffDistance=200
-aim_assistInputForFullFollow_Ironsight=0.20
-aim_assistMaxDistance=255
-aim_assistMaxDistance_ironsight=255
-aim_assistMinTurnScale=0.5
-aim_assistMinTurnScale_ironsight=0.5
-aim_assistSlowDisableDistance=255
-aim_assistSlowFalloffStartDistance=200
-aim_assistSlowThresholdOuter=2.5
-aim_assiststrength=0.7
-aim_assiststrength_ironsight=0.75
-br_breakmaxworldsize=511
-cl_sensitivityControllerMP=0.6
-cl_shallowWaterSpeedMulPlayer=1.0
-controller_multiplier_x=3
-controller_multiplier_z=4
-g_actorViewDistRatio=255
-
--- This forces broken trees to have spherical inertia, which makes them harder to rotate around their vertical axis.
-g_breakageMinAxisInertia=1.0
-g_glassAutoShatterMinArea=0.5
-
-g_distanceForceNoIk=35
-g_fpDbaManagementEnable=0
-g_godMode=0
-g_highlightingMaxDistanceToHighlightSquared=625
-g_hitDeathReactions_streaming=2
-g_mp_as_DefendersMaxHealth=150
-g_multiplayerDefault=1
-
--- Overriden in GameSDK\Difficulty\*.cfg
-g_playerLowHealthThreshold=20
-g_playerMidHealthThreshold=60
-
-g_spawn_vistable_numLineTestsPerFrame=3
-g_telemetryConfig="MP"
-g_telemetrySampleRateBandwidth=3
-g_telemetrySampleRateMemory=2
-g_telemetrySampleRatePerformance=1
-g_VTOLInsideBoundsScaleX=0.6
-g_VTOLInsideBoundsScaleY=1
-net_breakage_sync_entities=0
-net_enable_tfrc=0
-net_log=1
-
--- Make consoles match the PC gravity
-p_gravity_z="-13"
-
--- Sanity check for physics RepositionEntity
-p_max_entity_cells=10000
-
-pl_impulseEnabled=1
-pl_jump_maxTimerValue=0.0
-pl_jump_quickPressThresh=0.12
-pl_melee.angle_limit_from_behind=70
-pl_melee.impulses_enable=1
-pl_melee.melee_snap_angle_limit=45
-pl_melee.melee_snap_end_position_range=1.5
-pl_melee.melee_snap_move_speed_multiplier=10
-pl_melee.melee_snap_target_select_range=3.5
-pl_melee.mp_knockback_strength_hor=2
-pl_melee.mp_melee_system=1
-pl_melee.mp_victim_screenfx_blendout_duration=0.25
-pl_melee.mp_victim_screenfx_duration=0.1
-pl_nanovision_timetodrain=8
-pl_nanovision_timetorecharge=16
-pl_pickAndThrow.chargedThrowAutoAimConeSize=10
-pl_pickAndThrow.complexMelee_snap_angle_limit=25
-pl_sliding_control_mp.deceleration_speed=4
-pl_sliding_control_mp.max_downhill_acceleration=15
-pl_sliding_control_mp.min_speed=4
-pl_sliding_control_mp.min_speed_threshold=5
-pl_stealthKill_aimVsSpineLerp=0.65
-pl_stealthKill_useExtendedRange=1
-p_splash_vel0=0.5
-sv_bandwidth=2147483647
\ No newline at end of file
diff --git a/Assets/Engine/Config/multiplayer_console.cfg b/Assets/Engine/Config/multiplayer_console.cfg
index 0bed002497..e69de29bb2 100644
--- a/Assets/Engine/Config/multiplayer_console.cfg
+++ b/Assets/Engine/Config/multiplayer_console.cfg
@@ -1,29 +0,0 @@
-e_GI=0
-r_DeferredShadingIndexedAmbient=0
-e_ParticlesObjectCollisions=0
-g_distanceForceNoLegRaycasts=0.00001
-g_telemetryDisplaySessionId=1
-g_breakageNoDebrisCollisions=1
-
-; Breakage throttling
-; These are explained in ActionGame.cpp
-;
-g_glassAutoShatterOnExplosions=1
-g_glassNoDecals=1
-g_glassMaxPanesToBreakPerFrame=2
-g_breakageTreeMax=100
-g_breakageTreeInc=101
-g_breakageTreeDec=25
-g_breakageTreeIncGlass=51
-
-sys_PakInMemoryPakSizeLimit=25
-
-r_TexturesStreamPoolSecondarySize=35
-r_MotionBlur=1
-
-e_CoverageBufferReproj=2
-
-osm_enabled = 1
-
-g_waterHitOnly = 1
-p_max_object_splashes=1
diff --git a/Assets/Engine/Config/recording.cfg b/Assets/Engine/Config/recording.cfg
index 42a0dfd9bd..931dbf0858 100644
--- a/Assets/Engine/Config/recording.cfg
+++ b/Assets/Engine/Config/recording.cfg
@@ -1,63 +1,3 @@
--- added this lines for proper 360 deg panorama renderings
-
-e_ScreenShotFileFormat = jpg
-demo_fixed_timestep = 60
-s_SoundEnable = 0
r_DisplayInfo = 0
-e_PanoramaScreenShotHeight = 720
-e_PanoramaScreenShotWidth = 10053
c_shakeMult = 0
-demo_ai = 1
-r_MotionBlur = 0
-
--- enables full water reflection
--- e_DebugMask = 2 -- e_DebugMask not allowed here
-
--- set weapong lighting effect to 0 to prevent flickering bug because of too much dynamic lights in the scene
-
-
sys_spec = 2
-r_WaterRefractions = 1
-r_WaterReflections = 1
-r_WaterUpdateFactor = 0.01
-r_WaterReflections_ForceParticles = 0
-
-r_EnvCMResolution = 2
-r_EnvTexResolution = 3
-r_EnvTexUpdateInterval = 0.05
-e_Decals = 1
-e_DecalsLifeTimeScale = 2
-ca_EnableDecals = 1
-e_LodRatio = 10
-e_ViewDistRatio = 55
-e_Lods = 1
-e_VegetationMinSize = 0
-r_CloudsUpdateAlways = 0
-
-e_DynamicLightsMaxEntityLights = 3
-r_DepthOfField = 1
---r_MotionBlur = 1
-r_Flares = 1
-r_checkSunVis = 1
-r_Coronas = 1
-r_CoronaFade = 0.1625
-r_UseEdgeAA = 1
-e_Clouds = 1
-
-r_TexResolution = 0
-r_TexBumpResolution = 0
-r_DetailTextures = 1
-r_DetailNumLayers = 1
-r_DetailDistance = 8
-
-e_ParticlesLod = 0.9
-
-r_ShadowBlur = 3
-e_ShadowsMaxTexRes = 1024
-r_ShadowJittering = 1
-e_Shadows = 1
-e_VegetationBending = 1
-ai_UpdateAllAlways = 1
-r_refraction = 1
-r_sunshafts = 1
-r_ImposterRatio = 1
diff --git a/Assets/Engine/Config/singleplayer.cfg b/Assets/Engine/Config/singleplayer.cfg
index fc7a4f4c05..e69de29bb2 100644
--- a/Assets/Engine/Config/singleplayer.cfg
+++ b/Assets/Engine/Config/singleplayer.cfg
@@ -1,15 +0,0 @@
-ai_CompatibilityMode=crysis2
-ai_BurstWhileMovingDestinationRange=9999.0
-
-g_telemetryConfig=SP
-
-net_inactivitytimeout=3600
-net_inactivitytimeoutDevmode=3600
-
-pl_movement.nonCombat_heavy_weapon_speed_scale=1.0
-
--- BLM - Don't override game rules. The template project only has DummyRules.
--- Furthermore, multiplayer.cfg doesn't set sv_gamerules, so the inconsistency
--- is likely to create bugs.
---sv_gamerules=SinglePlayer
-ca_StreamCHR=1
\ No newline at end of file
diff --git a/Assets/Engine/Config/sketch_off.cfg b/Assets/Engine/Config/sketch_off.cfg
deleted file mode 100644
index 6b0562daab..0000000000
--- a/Assets/Engine/Config/sketch_off.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-r_UseZPass = 1
-r_GeomInstancing = 1
-
-e_Fog = 1
-e_Clouds = 1
-e_Decals = 1
-e_TerrainDetailMaterials = 1
-e_Dissolve = 1
-e_TerrainAo = 1
-
-r_WaterReflections = 1
-
-e_Shadows = 1
-e_VegetationBending = 1
-
-r_PostProcessEffects = 1
-r_Flares = 1
-r_Beams = 1
-r_Glow = 1
-
-r_DetailTextures = 1
-
-r_refraction = 1
-r_sunshafts = 1
\ No newline at end of file
diff --git a/Assets/Engine/Config/sketch_on.cfg b/Assets/Engine/Config/sketch_on.cfg
deleted file mode 100644
index 6759b5d4c8..0000000000
--- a/Assets/Engine/Config/sketch_on.cfg
+++ /dev/null
@@ -1,24 +0,0 @@
-r_UseZPass = 0
-r_GeomInstancing = 0
-
-e_Fog = 0
-e_Clouds = 0
-e_Decals = 0
-e_TerrainDetailMaterials = 0
-e_Dissolve = 0
-e_TerrainAo = 0
-
-r_WaterReflections = 0
-
-e_Shadows = 0
-e_VegetationBending = 0
-
-r_PostProcessEffects = 0
-r_Flares = 0
-r_Beams = 0
-r_Glow = 0
-
-r_DetailTextures = 0
-
-r_refraction = 0
-r_sunshafts = 0
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/android_MaliT760.cfg b/Assets/Engine/Config/spec/android_MaliT760.cfg
index f951e61eef..fd7c0a349d 100644
--- a/Assets/Engine/Config/spec/android_MaliT760.cfg
+++ b/Assets/Engine/Config/spec/android_MaliT760.cfg
@@ -1,76 +1,8 @@
-sys_spec_Full=2
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=0
--- Disable gmem for this device because it causes a crash
-r_EnableGMEMPath=0
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-sys_job_system_max_worker=2
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
--- This allows the generation of reflections for the ocean water. Without it, the water looks really dark.
-e_recursion=1
-e_CheckOcclusion=1
-
-r_Fur=0
-az_Asset_EnableAsyncMeshLoading=0
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=33554432
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_objectdetail
-------------------------
-e_Dissolve=2
-e_LodRatio=5
-e_ViewDistRatioDetail=19
-e_ViewDistRatioVegetation=21
-
-
-------------------------
--- sys_spec_postprocessing
-------------------------
-r_HDRBloom=0
-r_SunShafts=0
-r_ToneMapTechnique=3
-r_ToneMapExposureType=1
-r_ColorSpace=2
-
-------------------------
--- sys_spec_shading
-------------------------
-r_VisAreaClipLightsPerPixel=0
-
-------------------------
--- sys_spec_textureresolution
-------------------------
-r_TexturesstreamingMinUsableMips=7
-
-
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/android_high.cfg b/Assets/Engine/Config/spec/android_high.cfg
index fc46adc491..0ab8ebc37b 100644
--- a/Assets/Engine/Config/spec/android_high.cfg
+++ b/Assets/Engine/Config/spec/android_high.cfg
@@ -1,65 +1,7 @@
-sys_spec_Full=3
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=0
--- Enable framebufferfetch(256bpp) or pls if applicable
-r_EnableGMEMPath=2
-
--- Skip the native upscale as a second upscale already occurs
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-sys_job_system_max_worker=2
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-
-e_CheckOcclusion=1
-
-r_Fur=0
-az_Asset_EnableAsyncMeshLoading=0
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=33554432
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_objectdetail
-------------------------
-e_Dissolve=2
-e_LodRatio=5
-e_ViewDistRatioDetail=19
-
-
-------------------------
--- sys_spec_shading
-------------------------
-r_VisAreaClipLightsPerPixel=0
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
-r_ClearGMEMGBuffer=1
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/android_high_nogmem.cfg b/Assets/Engine/Config/spec/android_high_nogmem.cfg
index ac718a57ee..fd7c0a349d 100644
--- a/Assets/Engine/Config/spec/android_high_nogmem.cfg
+++ b/Assets/Engine/Config/spec/android_high_nogmem.cfg
@@ -1,61 +1,8 @@
-sys_spec_Full=3
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=0
--- Disabling gmem for this configuration
-r_EnableGMEMPath=0
-
--- Skip the native upscale as a second upscale already occurs
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-sys_job_system_max_worker=2
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-e_CheckOcclusion=1
-
-r_Fur=0
-az_Asset_EnableAsyncMeshLoading=0
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=33554432
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_objectdetail
-------------------------
-e_Dissolve=2
-e_LodRatio=5
-e_ViewDistRatioDetail=19
-
-
-------------------------
--- sys_spec_shading
-------------------------
-r_VisAreaClipLightsPerPixel=0
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
-
diff --git a/Assets/Engine/Config/spec/android_low.cfg b/Assets/Engine/Config/spec/android_low.cfg
index 6f2a876877..0ab8ebc37b 100644
--- a/Assets/Engine/Config/spec/android_low.cfg
+++ b/Assets/Engine/Config/spec/android_low.cfg
@@ -1,76 +1,7 @@
-sys_spec_Full=1
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=0
--- Enable framebufferfetch(256bpp) or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale already occurs
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-sys_job_system_max_worker=2
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-
--- This allows the generation of reflections for the ocean water. Without it, the water looks really dark.
-e_recursion=0
-e_CheckOcclusion=1
-
-r_Fur=0
-
--- Water occlusion queries crash in some OpenGL ES 3.0 devices
-e_HwOcclusionCullingWater = 0
-az_Asset_EnableAsyncMeshLoading=0
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=33554432
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_objectdetail
-------------------------
-e_Dissolve=2
-e_LodRatio=5
-e_ViewDistRatioDetail=19
-
-
-------------------------
--- sys_spec_shading
-------------------------
-r_VisAreaClipLightsPerPixel=0
-
-
-------------------------
--- sys_spec_textureresolution
-------------------------
-r_TexturesstreamingMinUsableMips=6
-
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-r_ClearGMEMGBuffer=1
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/android_medium.cfg b/Assets/Engine/Config/spec/android_medium.cfg
index f9d776efa7..0ab8ebc37b 100644
--- a/Assets/Engine/Config/spec/android_medium.cfg
+++ b/Assets/Engine/Config/spec/android_medium.cfg
@@ -1,81 +1,7 @@
-sys_spec_Full=2
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=0
--- Enable framebufferfetch(256bpp) or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale already occurs
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-sys_job_system_max_worker=2
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-
--- This allows the generation of reflections for the ocean water. Without it, the water looks really dark.
-e_recursion=1
-e_CheckOcclusion=1
-
-r_Fur=0
-az_Asset_EnableAsyncMeshLoading=0
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=33554432
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_objectdetail
-------------------------
-e_Dissolve=2
-e_LodRatio=5
-e_ViewDistRatioDetail=19
-e_ViewDistRatioVegetation=21
-
-
-------------------------
--- sys_spec_postprocessing
-------------------------
-r_HDRBloom=0
-r_SunShafts=0
-r_ToneMapExposureType=1
-r_ColorSpace=2
-
-------------------------
--- sys_spec_shading
-------------------------
-r_VisAreaClipLightsPerPixel=0
-
-------------------------
--- sys_spec_textureresolution
-------------------------
-r_TexturesstreamingMinUsableMips=7
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
-r_ClearGMEMGBuffer=1
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/android_veryhigh.cfg b/Assets/Engine/Config/spec/android_veryhigh.cfg
index d4f8e9cd47..d58e319706 100644
--- a/Assets/Engine/Config/spec/android_veryhigh.cfg
+++ b/Assets/Engine/Config/spec/android_veryhigh.cfg
@@ -1,60 +1,5 @@
-sys_spec_Full=4
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=0
-
--- Enable framebufferfetch(256bpp) or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale already occurs
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-sys_job_system_max_worker=2
sys_streaming_in_blocks=1
-
sys_streaming_memory_budget=512
-
-e_CheckOcclusion=1
-
-r_Fur=0
-az_Asset_EnableAsyncMeshLoading=0
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=33554432
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_objectdetail
-------------------------
-e_Dissolve=2
-e_LodRatio=5
-e_ViewDistRatioDetail=19
-
-
-------------------------
--- sys_spec_shading
-------------------------
-r_VisAreaClipLightsPerPixel=0
-
-r_ClearGMEMGBuffer=1
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/ios_high.cfg b/Assets/Engine/Config/spec/ios_high.cfg
index 67fa99ca04..d0cf5b3bc5 100644
--- a/Assets/Engine/Config/spec/ios_high.cfg
+++ b/Assets/Engine/Config/spec/ios_high.cfg
@@ -1,100 +1,10 @@
-sys_spec_Full=3
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=1
--- Enable framebufferfetch or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-
-------------------------
--- Job System
-------------------------
-sys_job_system_enable=0
-sys_job_system_max_worker=1
-
------------------------
-- Streaming
------------------------
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-------------------------
--- General Rendering
-------------------------
-r_Flush=0
--- Enabling this will clear the GMEM buffer before the z-pass
-r_ClearGMEMGBuffer=2
-r_Fur=0
-
-------------------------
--- VisArea / Portals
-------------------------
-e_PortalsBlend=0
-r_GMEMVisAreasBlendWeight=0.5
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_AutoPrecacheCgf=2
-e_AutoPrecacheTerrainAndProcVeget=1
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=2048
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=32
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_water
-------------------------
-e_WaterOcean=2
-e_WaterVolumes=2
-e_WaterOceanBottom=0
-
-------------------------
--- batching
-------------------------
-r_Batching = 1
-r_BatchType = 0
-
-------------------------
--- geom instancing
-------------------------
-r_GeomInstancing=1
-r_GeomInstancingThreshold=5
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
-------------------------
--- Geometry Cache
-------------------------
-e_GeomCaches=0
-
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/ios_low.cfg b/Assets/Engine/Config/spec/ios_low.cfg
index 7870d65bd5..d0cf5b3bc5 100644
--- a/Assets/Engine/Config/spec/ios_low.cfg
+++ b/Assets/Engine/Config/spec/ios_low.cfg
@@ -1,103 +1,10 @@
-sys_spec_Full=1
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=1
--- Enable framebufferfetch or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-
-------------------------
--- Job System
-------------------------
-sys_job_system_enable=0
-sys_job_system_max_worker=1
-
------------------------
-- Streaming
------------------------
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-------------------------
--- General Rendering
-------------------------
-r_Flush=0
--- Enabling this will clear the GMEM buffer before the z-pass
-r_ClearGMEMGBuffer=2
-r_Fur=0
-
-------------------------
--- VisArea / Portals
-------------------------
-e_PortalsBlend=0
-r_GMEMVisAreasBlendWeight=0.5
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_AutoPrecacheCgf=2
-e_AutoPrecacheTerrainAndProcVeget=1
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=32
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_water
-------------------------
-e_WaterOcean=2
-e_WaterVolumes=2
-e_WaterOceanBottom=0
-
-
-------------------------
--- batching
-------------------------
-r_Batching = 1
-r_BatchType = 0
-
-------------------------
--- geom instancing
-------------------------
-r_GeomInstancing=1
-r_GeomInstancingThreshold=5
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
-------------------------
--- Geometry Cache
-------------------------
-e_GeomCaches=0
-
-
-
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/ios_medium.cfg b/Assets/Engine/Config/spec/ios_medium.cfg
index 2eaecdef16..d0cf5b3bc5 100644
--- a/Assets/Engine/Config/spec/ios_medium.cfg
+++ b/Assets/Engine/Config/spec/ios_medium.cfg
@@ -1,101 +1,10 @@
-sys_spec_Full=2
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=1
--- Enable framebufferfetch or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-
-------------------------
--- Job System
-------------------------
-sys_job_system_enable=0
-sys_job_system_max_worker=1
-
------------------------
-- Streaming
------------------------
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-------------------------
--- General Rendering
-------------------------
-r_Flush=0
--- Enabling this will clear the GMEM buffer before the z-pass
-r_ClearGMEMGBuffer=2
-r_Fur=0
-
-------------------------
--- VisArea / Portals
-------------------------
-e_PortalsBlend=0
-r_GMEMVisAreasBlendWeight=0.5
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_AutoPrecacheCgf=2
-e_AutoPrecacheTerrainAndProcVeget=1
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=1024
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=32
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_water
-------------------------
-e_WaterOcean=2
-e_WaterVolumes=2
-e_WaterOceanBottom=0
-
-
-------------------------
--- batching
-------------------------
-r_Batching = 1
-r_BatchType = 0
-
-------------------------
--- geom instancing
-------------------------
-r_GeomInstancing=1
-r_GeomInstancingThreshold=5
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
-------------------------
--- Geometry Cache
-------------------------
-e_GeomCaches=0
-
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/ios_veryhigh.cfg b/Assets/Engine/Config/spec/ios_veryhigh.cfg
index 53937a77bf..d0cf5b3bc5 100644
--- a/Assets/Engine/Config/spec/ios_veryhigh.cfg
+++ b/Assets/Engine/Config/spec/ios_veryhigh.cfg
@@ -1,102 +1,10 @@
-sys_spec_Full=4
-
-- Cap frame rate at 30fps
sys_maxfps=30
r_vsync=1
--- Enable framebufferfetch or pls if applicable
-r_EnableGMEMPath=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
-
-------------------------
--- Job System
-------------------------
-sys_job_system_enable=0
-sys_job_system_max_worker=1
-
------------------------
-- Streaming
------------------------
sys_streaming_in_blocks=1
sys_streaming_memory_budget=512
-------------------------
--- General Rendering
-------------------------
-r_Flush=0
--- Enabling this will clear the GMEM buffer before the z-pass
-r_ClearGMEMGBuffer=2
-r_Fur=0
-
-------------------------
--- VisArea / Portals
-------------------------
-e_PortalsBlend=0
-r_GMEMVisAreasBlendWeight=0.5
-
-------------------------
--- Misc. memory buffers
-------------------------
-e_AutoPrecacheCgf=2
-e_AutoPrecacheTerrainAndProcVeget=1
-e_GeomCacheBufferSize=0
-e_CheckOcclusionQueueSize=512
-e_CheckOcclusionOutputQueueSize=2048
-
-------------------------
--- Animation
-------------------------
-ca_MemoryDefragPoolSize=32
-ca_StreamCHR=1
-
-------------------------
--- sys_spec_water
-------------------------
-e_WaterOcean=2
-e_WaterVolumes=2
-e_WaterOceanBottom=0
-
-
-------------------------
--- batching
-------------------------
-r_Batching = 1
-r_BatchType = 0
-
-------------------------
--- geom instancing
-------------------------
-r_GeomInstancing=1
-r_GeomInstancingThreshold=5
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
-------------------------
--- Geometry Cache
-------------------------
-e_GeomCaches=0
-
-
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
-
--- Sort ligths since we have limited space in the shadowmap pool texture
-r_DeferredShadingSortLights = 3
-
---Use an optimized pixel format for the lighting rendertargets during the lighting pass.
-r_DeferredShadingLBuffersFmt = 2
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/osx_metal_high.cfg b/Assets/Engine/Config/spec/osx_metal_high.cfg
deleted file mode 100644
index 8689e23c51..0000000000
--- a/Assets/Engine/Config/spec/osx_metal_high.cfg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-sys_spec_Full=7
-r_ShadersMETAL=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
-------------------------
--- sys_spec_postprocessing
-------------------------
-r_SunShafts=1
-
-------------------------
--- sys_spec_shading
-------------------------
-r_DeferredShadingTiled=0
-r_RefractionPartialResolves=0
-e_GI = 0
-
-
-r_Fur=2
-
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
diff --git a/Assets/Engine/Config/spec/osx_metal_low.cfg b/Assets/Engine/Config/spec/osx_metal_low.cfg
deleted file mode 100644
index a3084d48c5..0000000000
--- a/Assets/Engine/Config/spec/osx_metal_low.cfg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-sys_spec_Full=5
-r_ShadersMETAL=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
-------------------------
--- sys_spec_postprocessing
-------------------------
-r_SunShafts=1
-
-------------------------
--- sys_spec_shading
-------------------------
-r_DeferredShadingTiled=0
-r_RefractionPartialResolves=0
-e_GI=0
-
-r_Fur=2
-
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
diff --git a/Assets/Engine/Config/spec/osx_metal_medium.cfg b/Assets/Engine/Config/spec/osx_metal_medium.cfg
deleted file mode 100644
index 6477bbb217..0000000000
--- a/Assets/Engine/Config/spec/osx_metal_medium.cfg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-sys_spec_Full=6
-r_ShadersMETAL=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
-------------------------
--- sys_spec_postprocessing
-------------------------
-r_SunShafts=1
-
-------------------------
--- sys_spec_shading
-------------------------
-r_DeferredShadingTiled=0
-r_RefractionPartialResolves=0
-e_GI = 0
-
-r_Fur=2
-
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
diff --git a/Assets/Engine/Config/spec/osx_metal_veryhigh.cfg b/Assets/Engine/Config/spec/osx_metal_veryhigh.cfg
deleted file mode 100644
index 899c198f31..0000000000
--- a/Assets/Engine/Config/spec/osx_metal_veryhigh.cfg
+++ /dev/null
@@ -1,37 +0,0 @@
-
-sys_spec_Full=8
-r_ShadersMETAL=1
-
--- Default of 3 allocates all shaders (potentially >150 MB)
--- 1 is most memory efficient but definitely causes hitches when converting HLSL
--- shaders. Recommend 1 during dev, and 3 with optimized caches for release.
-r_ShadersPreactivate=1
-
--- Skip the native upscale as a second upscale occurs on Metal Present
-r_SkipNativeUpscale=1
-
-------------------------
--- sys_spec_postprocessing
-------------------------
-r_SunShafts=1
-
-------------------------
--- sys_spec_shading
-------------------------
-r_DeferredShadingTiled=0
-r_RefractionPartialResolves=0
-e_GI = 0
-
-r_Fur=2
-
-
-------------------------
--- Upscaling
-------------------------
---0 point, 1 bilinear, 2 bicubic, 3 lanczos
-r_UpscalingQuality=1
-
--- Due to performance issues with incremental cached shadow map updates, enable this to prevent us from culling every object in the world vs each cached shadow map each frame.
--- If no objects are present in the level this will eliminate the need to clear the massive cached textures each frame.
--- Set to 2 to allow distance-based updates along with script-based updates for the cached shadow maps
-e_ShadowsCacheRequireManualUpdate = 2
diff --git a/Assets/Engine/Config/spec/pc_high.cfg b/Assets/Engine/Config/spec/pc_high.cfg
index a62ed25a6a..e69de29bb2 100644
--- a/Assets/Engine/Config/spec/pc_high.cfg
+++ b/Assets/Engine/Config/spec/pc_high.cfg
@@ -1 +0,0 @@
-sys_spec_Full = 7
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/pc_low.cfg b/Assets/Engine/Config/spec/pc_low.cfg
index 068446e151..e69de29bb2 100644
--- a/Assets/Engine/Config/spec/pc_low.cfg
+++ b/Assets/Engine/Config/spec/pc_low.cfg
@@ -1 +0,0 @@
-sys_spec_Full = 5
diff --git a/Assets/Engine/Config/spec/pc_medium.cfg b/Assets/Engine/Config/spec/pc_medium.cfg
index 0d08b956b4..e69de29bb2 100644
--- a/Assets/Engine/Config/spec/pc_medium.cfg
+++ b/Assets/Engine/Config/spec/pc_medium.cfg
@@ -1 +0,0 @@
-sys_spec_Full = 6
\ No newline at end of file
diff --git a/Assets/Engine/Config/spec/pc_veryhigh.cfg b/Assets/Engine/Config/spec/pc_veryhigh.cfg
index 33959937e8..e69de29bb2 100644
--- a/Assets/Engine/Config/spec/pc_veryhigh.cfg
+++ b/Assets/Engine/Config/spec/pc_veryhigh.cfg
@@ -1 +0,0 @@
-sys_spec_Full = 8
diff --git a/Assets/Engine/Config/statoscope.cfg b/Assets/Engine/Config/statoscope.cfg
index d1d18c813c..ed2089bd67 100644
--- a/Assets/Engine/Config/statoscope.cfg
+++ b/Assets/Engine/Config/statoscope.cfg
@@ -1,12 +1,3 @@
profile=-1
-profile_allthreads=1
-i_forcefeedback=0
-g_godmode=1
log_verbosity=-1
sys_pakLogInvalidFileAccess=1
-e_StatoscopeDataGroups=fgmrtudlipny
-e_StatoscopeFilenameUseBuildInfo=0
-e_StatoscopeFilenameUseMap=1
-e_StatoscopeMinFuncLengthMs=0.1
-e_StatoscopeMaxNumFuncsPerFrame=60
-e_StatoscopeScreenshotCapturePeriod=5
diff --git a/Assets/Engine/Config/vr.cfg b/Assets/Engine/Config/vr.cfg
index 989f55f345..80d4b7ce81 100644
--- a/Assets/Engine/Config/vr.cfg
+++ b/Assets/Engine/Config/vr.cfg
@@ -3,39 +3,13 @@
-----------------------------------------------
r_width = 960
r_height = 1080
-r_backbufferWidth = 1920
-r_backbufferHeight = 1080
-
-------------------------------------------
-- Set the system Spec (Medium)
-------------------------------------------
sys_spec = 2
-
--------------------------------------------
--- HMD related
--------------------------------------------
-r_overrideDXGIoutput = 0
-r_stereodevice = 100
-r_stereomode = 1
-r_stereooutput = 7
-r_minimizeLatency = 1
-hmd_low_persistence = 1
-r_stereoScaleCoefficient = 1
-
-
-------------------------------------------
-- Set some video optimisations
-------------------------------------------
r_vsync = 0
-r_MotionBlur = 0
-r_ssdoHalfRes = 3
-r_Refraction = 0
-r_DeferredShadingTiled = 0
-r_CBufferUseNativeDepth = 0
-
--------------------------------------------
--- Hide the hud
--------------------------------------------
---hud_hide = 1
diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed
index 579fd3c444..aafbffbe8f 100644
--- a/Assets/Engine/SeedAssetList.seed
+++ b/Assets/Engine/SeedAssetList.seed
@@ -48,22 +48,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -432,110 +416,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -616,38 +496,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
index 821e0acfdb..11832f8846 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
@@ -113,7 +113,6 @@ def create_basic_atom_level(level_name):
general.close_pane("Error Log")
general.idle_wait(1.0)
general.run_console("r_displayInfo=0")
- general.run_console("r_antialiasingmode=0")
general.idle_wait(1.0)
# Delete all existing entities & create default_level entity
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
index 92199bf196..fbd9f3459a 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
@@ -66,7 +66,6 @@ def run():
general.close_pane("Error Log")
general.idle_wait(1.0)
general.run_console("r_displayInfo=0")
- general.run_console("r_antialiasingmode=0")
general.idle_wait(1.0)
return True
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
index ac28e67fa1..93e78a7c0a 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
@@ -82,7 +82,6 @@ def run():
general.close_pane("Error Log")
general.idle_wait(1.0)
general.run_console("r_displayInfo=0")
- general.run_console("r_antialiasingmode=0")
general.idle_wait(1.0)
return True
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
index ef3048d8d4..1b094b1cfa 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
@@ -149,7 +149,6 @@ class TestHelper:
general.idle_wait(1.0)
general.idle_wait(1.0)
general.run_console("r_displayInfo=0")
- general.run_console("r_antialiasingmode=0")
general.idle_wait(1.0)
diff --git a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py
index 49cf17855f..22fa3aca0d 100755
--- a/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/screenshot_utils.py
@@ -187,7 +187,3 @@ def prepare_for_screenshot_compare(remote_console_instance):
"""
wait_for(lambda: _retry_command(remote_console_instance, 'r_displayinfo 0',
'$3r_DisplayInfo = $60 $5[DUMPTODISK, RESTRICTEDMODE]$4'))
- wait_for(lambda: _retry_command(remote_console_instance, 'r_antialiasingmode 0',
- '$3r_AntialiasingMode = $60 $5[]$4'))
- wait_for(lambda: _retry_command(remote_console_instance, 'e_WaterOcean 0',
- '$3e_WaterOcean = $60 $5[]$4'))
diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py
new file mode 100644
index 0000000000..39cacf9af5
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD.py
@@ -0,0 +1,101 @@
+"""
+Copyright (c) Contributors to the Open 3D Engine Project.
+For complete copyright and license terms please see the LICENSE at the root of this distribution.
+
+SPDX-License-Identifier: Apache-2.0 OR MIT
+"""
+
+
+class Tests:
+ load_level = (
+ "Level loaded successfully",
+ "Failed to load the level"
+ )
+ create_entity = (
+ "Parent entity created successfully",
+ "Failed to create a parent entity"
+ )
+ set_entity_name = (
+ "Entity name set successfully",
+ "Failed to set entity name"
+ )
+ delete_entity = (
+ "Parent Entity deleted successfully",
+ "Failed to delete parent entity"
+ )
+ create_child_entity = (
+ "Child entity created successfully",
+ "Failed to create a child entity"
+ )
+ delete_child_entity = (
+ "Child entity deleted successfully",
+ "Failed to delete child entity"
+ )
+ add_mesh_component = (
+ "Mesh component added successfully",
+ "Failed to add mesh component"
+ )
+ found_component_typeId = (
+ "Found component typeId",
+ "Unable to find component TypeId"
+ )
+ remove_mesh_component = (
+ "Mesh component removed successfully",
+ "Failed to remove mesh component"
+ )
+
+
+def BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD():
+ """
+ Performing basic test in editor
+ 01. Load exiting level
+ 02. create parent entity and set name
+ 03. create child entity and set a name
+ 04. delete child entity
+ 05. add mesh component to parent entity
+ 06. delete parent entity
+ """
+
+ from editor_python_test_tools.utils import Report
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+
+ import azlmbr.bus as bus
+ import azlmbr.editor as editor
+ import azlmbr.entity as entity
+ import azlmbr.legacy.general as general
+ import azlmbr.object
+
+ # 01. load an existing level
+ test_level = 'Simple'
+ general.open_level_no_prompt(test_level)
+ Report.result(Tests.load_level, general.get_current_level_name() == test_level)
+
+ # 02. create parent entity and set name
+ # Delete any exiting entity and Create a new Entity at the root level
+ search_filter = azlmbr.entity.SearchFilter()
+ all_entities = entity.SearchBus(azlmbr.bus.Broadcast, "SearchEntities", search_filter)
+ editor.ToolsApplicationRequestBus(bus.Broadcast, "DeleteEntities", all_entities)
+ parent_entity = EditorEntity.create_editor_entity("Parent_1")
+ Report.result(Tests.create_entity, parent_entity.exists())
+
+ # 03. Create child Entity to above created parent entity and set a name
+ child_1_entity = EditorEntity.create_editor_entity("Child_1", parent_entity.id )
+ Report.result(Tests.create_child_entity, child_1_entity.exists())
+
+ # 04. delete_Child_entity
+ child_1_entity.delete()
+ Report.result(Tests.delete_child_entity, not child_1_entity.exists())
+
+ # 05. add mesh component to parent entity
+ parent_entity.add_component("Mesh")
+ Report.result(Tests.add_mesh_component, parent_entity.has_component("Mesh"))
+
+ # 06. delete parent entity
+ parent_entity.delete()
+ Report.result(Tests.delete_entity, not parent_entity.exists())
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+
+ Report.start_test(BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD)
diff --git a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py
index 9c0b99daff..afc52f962d 100644
--- a/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py
+++ b/AutomatedTesting/Gem/PythonTests/editor/TestSuite_Main_Optimized.py
@@ -73,3 +73,7 @@ class TestAutomationAutoTestMode(EditorTestSuite):
@pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208")
class test_Menus_FileMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_FileMenuOptions as test_module
+
+
+ class test_BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD(EditorSharedTest):
+ from .EditorScripts import BasicEditorWorkflows_ExistingLevel_EntityComponentCRUD as test_module
diff --git a/Code/Editor/Controls/FolderTreeCtrl.cpp b/Code/Editor/Controls/FolderTreeCtrl.cpp
index 4088ab976f..1464580ffc 100644
--- a/Code/Editor/Controls/FolderTreeCtrl.cpp
+++ b/Code/Editor/Controls/FolderTreeCtrl.cpp
@@ -279,7 +279,7 @@ void CFolderTreeCtrl::LoadTreeRec(const QString& currentFolder)
void CFolderTreeCtrl::AddItem(const QString& path)
{
AZ::IO::FixedMaxPath folder{ AZ::IO::PathView(path.toUtf8().constData()) };
- AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Extension();
+ AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Stem();
folder = folder.ParentPath();
auto regex = QRegExp(m_fileNameSpec, Qt::CaseInsensitive, QRegExp::Wildcard);
diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp
index 75bd0ad270..4944c3bff5 100644
--- a/Code/Editor/CryEditDoc.cpp
+++ b/Code/Editor/CryEditDoc.cpp
@@ -1273,7 +1273,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
if (savedEntities)
{
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel Updated PakFile levelEntities.editor_xml");
- pakFile.UpdateFile("LevelEntities.editor_xml", entitySaveBuffer.begin(), static_cast(entitySaveBuffer.size()));
+ pakFile.UpdateFile("levelentities.editor_xml", entitySaveBuffer.begin(), static_cast(entitySaveBuffer.size()));
// Save XML archive to pak file.
bool bSaved = xmlAr.SaveToPak(Path::GetPath(tempSaveFile), pakFile);
@@ -1501,7 +1501,7 @@ bool CCryEditDoc::LoadEntitiesFromLevel(const QString& levelPakFile)
bool pakOpened = pakSystem->OpenPack(levelPakFile.toUtf8().data());
if (pakOpened)
{
- const QString entityFilename = Path::GetPath(levelPakFile) + "LevelEntities.editor_xml";
+ const QString entityFilename = Path::GetPath(levelPakFile) + "levelentities.editor_xml";
CCryFile entitiesFile;
if (entitiesFile.Open(entityFilename.toUtf8().data(), "rt"))
diff --git a/Code/Editor/Util/XmlArchive.cpp b/Code/Editor/Util/XmlArchive.cpp
index 18c3fc8e63..3a965fb239 100644
--- a/Code/Editor/Util/XmlArchive.cpp
+++ b/Code/Editor/Util/XmlArchive.cpp
@@ -119,7 +119,7 @@ bool CXmlArchive::SaveToPak([[maybe_unused]] const QString& levelPath, CPakFile&
_smart_ptr pXmlStrData = root->getXMLData(5000000);
// Save xml file.
- QString xmlFilename = "Level.editor_xml";
+ QString xmlFilename = "level.editor_xml";
pakFile.UpdateFile(xmlFilename.toUtf8().data(), (void*)pXmlStrData->GetString(), static_cast(pXmlStrData->GetStringLength()));
if (pakFile.GetArchive())
@@ -134,7 +134,7 @@ bool CXmlArchive::SaveToPak([[maybe_unused]] const QString& levelPath, CPakFile&
//////////////////////////////////////////////////////////////////////////
bool CXmlArchive::LoadFromPak(const QString& levelPath, CPakFile& pakFile)
{
- QString xmlFilename = QDir(levelPath).absoluteFilePath("Level.editor_xml");
+ QString xmlFilename = QDir(levelPath).absoluteFilePath("level.editor_xml");
root = XmlHelpers::LoadXmlFromFile(xmlFilename.toUtf8().data());
if (!root)
{
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h
index 45da3a9d8f..2d7d9dc511 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntityInterface.h
@@ -11,6 +11,8 @@
#include
#include
+#include
+
namespace AzToolsFramework
{
//! Outcome object that returns an error message in case of failure to allow caller to handle internal errors.
@@ -43,7 +45,7 @@ namespace AzToolsFramework
//! @param entityId The entityId whose open state will be set.
//! @param open True if the container should be opened, false if it should be closed.
//! @return An error message if the operation was invalid, success otherwise.
- virtual ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) = 0;
+ virtual ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) = 0;
//! If the entity id provided is registered as a container, it returns whether it's open.
//! @note the default value for non-containers is true, so this function can be called without
@@ -56,6 +58,16 @@ namespace AzToolsFramework
//! @return The highest closed entity container id if any, or entityId otherwise.
virtual AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const = 0;
+ //! Clears all open state information for Container Entities for the EntityContextId provided.
+ //! Used when context is switched, for example in the case of a new root prefab being loaded
+ //! in place of an old one.
+ //! @note Clear is meant to be called when no container is registered for the context provided.
+ //! @return An error message if any container was registered for the context, success otherwise.
+ virtual ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) = 0;
+
+ //! Returns true if one of the ancestors of entityId is a closed container entity.
+ virtual bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const = 0;
+
};
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
index 0ea2eeb5f6..61b257a189 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.cpp
@@ -10,16 +10,19 @@
#include
#include
+#include
namespace AzToolsFramework
{
void ContainerEntitySystemComponent::Activate()
{
AZ::Interface::Register(this);
+ EditorEntityContextNotificationBus::Handler::BusConnect();
}
void ContainerEntitySystemComponent::Deactivate()
{
+ EditorEntityContextNotificationBus::Handler::BusDisconnect();
AZ::Interface::Unregister(this);
}
@@ -63,7 +66,7 @@ namespace AzToolsFramework
return m_containers.contains(entityId);
}
- ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpenState(AZ::EntityId entityId, bool open)
+ ContainerEntityOperationResult ContainerEntitySystemComponent::SetContainerOpen(AZ::EntityId entityId, bool open)
{
if (!IsContainer(entityId))
{
@@ -87,7 +90,7 @@ namespace AzToolsFramework
bool ContainerEntitySystemComponent::IsContainerOpen(AZ::EntityId entityId) const
{
- // If the entity is not a container, it should behave as open.
+ // Non-container entities behave the same as open containers. This saves the caller an additional check.
if(!m_containers.contains(entityId))
{
return true;
@@ -99,8 +102,17 @@ namespace AzToolsFramework
AZ::EntityId ContainerEntitySystemComponent::FindHighestSelectableEntity(AZ::EntityId entityId) const
{
+ if (!entityId.IsValid())
+ {
+ return entityId;
+ }
+
+ // Return the highest closed container, or the entity if none is found.
AZ::EntityId highestSelectableEntityId = entityId;
+ // Skip the queried entity, as we only want to check its ancestors.
+ AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
+
// Go up the hierarchy until you hit the root
while (entityId.IsValid())
{
@@ -117,4 +129,72 @@ namespace AzToolsFramework
return highestSelectableEntityId;
}
+ void ContainerEntitySystemComponent::OnEntityStreamLoadSuccess()
+ {
+ // We don't yet support multiple entity contexts, so just use the default.
+ auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
+ EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
+
+ Clear(editorEntityContextId);
+ }
+
+ ContainerEntityOperationResult ContainerEntitySystemComponent::Clear(AzFramework::EntityContextId entityContextId)
+ {
+ // We don't yet support multiple entity contexts, so only clear the default.
+ auto editorEntityContextId = AzFramework::EntityContextId::CreateNull();
+ EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &EditorEntityContextRequests::GetEditorEntityContextId);
+
+ if (entityContextId != editorEntityContextId)
+ {
+ return AZ::Failure(AZStd::string(
+ "Error in ContainerEntitySystemComponent::Clear - cannot clear non-default Entity Context!"));
+ }
+
+ if (!m_containers.empty())
+ {
+ return AZ::Failure(AZStd::string(
+ "Error in ContainerEntitySystemComponent::Clear - cannot clear container states if entities are still registered!"));
+ }
+
+ m_openContainers.clear();
+
+ return AZ::Success();
+ }
+
+ bool ContainerEntitySystemComponent::IsUnderClosedContainerEntity(AZ::EntityId entityId) const
+ {
+ if (!entityId.IsValid())
+ {
+ return false;
+ }
+
+ // Skip the queried entity, as we only want to check its ancestors.
+ AZ::TransformBus::EventResult(entityId, entityId, &AZ::TransformBus::Events::GetParentId);
+
+ // Go up the hierarchy until you hit the root.
+ while (entityId.IsValid())
+ {
+ if (!IsContainerOpen(entityId))
+ {
+ // One of the ancestors is a container and it's closed.
+ return true;
+ }
+
+ AZ::EntityId parentId;
+ AZ::TransformBus::EventResult(parentId, entityId, &AZ::TransformBus::Events::GetParentId);
+
+ if (parentId == entityId)
+ {
+ // In some circumstances, querying a root level entity with GetParentId will return
+ // the entity itself instead of an invalid entityId.
+ break;
+ }
+
+ entityId = parentId;
+ }
+
+ // All ancestors are either regular entities or open containers.
+ return false;
+ }
+
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h
index 18c0fb70c6..7a11e05096 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ContainerEntity/ContainerEntitySystemComponent.h
@@ -12,6 +12,7 @@
#include
#include
+#include
namespace AzToolsFramework
{
@@ -23,6 +24,7 @@ namespace AzToolsFramework
class ContainerEntitySystemComponent final
: public AZ::Component
, private ContainerEntityInterface
+ , private EditorEntityContextNotificationBus::Handler
{
public:
AZ_COMPONENT(ContainerEntitySystemComponent, "{74349759-B36B-44A6-B89F-F45D7111DD11}");
@@ -42,9 +44,14 @@ namespace AzToolsFramework
ContainerEntityOperationResult RegisterEntityAsContainer(AZ::EntityId entityId) override;
ContainerEntityOperationResult UnregisterEntityAsContainer(AZ::EntityId entityId) override;
bool IsContainer(AZ::EntityId entityId) const override;
- ContainerEntityOperationResult SetContainerOpenState(AZ::EntityId entityId, bool open) override;
+ ContainerEntityOperationResult SetContainerOpen(AZ::EntityId entityId, bool open) override;
bool IsContainerOpen(AZ::EntityId entityId) const override;
AZ::EntityId FindHighestSelectableEntity(AZ::EntityId entityId) const override;
+ ContainerEntityOperationResult Clear(AzFramework::EntityContextId entityContextId) override;
+ bool IsUnderClosedContainerEntity(AZ::EntityId entityId) const override;
+
+ // EditorEntityContextNotificationBus overrides ...
+ void OnEntityStreamLoadSuccess() override;
private:
AZStd::unordered_set m_containers; //!< All entities in this set are containers.
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp
index 7789070209..8d40162f52 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp
@@ -16,9 +16,11 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -588,15 +590,40 @@ namespace AzToolsFramework
{
AZ_PROFILE_FUNCTION(AzToolsFramework);
+ // Detect if the Entity is Visible
bool visible = false;
EditorEntityInfoRequestBus::EventResult(
visible, entityId, &EditorEntityInfoRequestBus::Events::IsVisible);
- bool locked = false;
- EditorEntityInfoRequestBus::EventResult(
- locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
+ if (!visible)
+ {
+ return false;
+ }
- return visible && !locked;
+ // Detect if the Entity is Locked
+ bool locked = false;
+ EditorEntityInfoRequestBus::EventResult(locked, entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
+
+ if (locked)
+ {
+ return false;
+ }
+
+ // Detect if the Entity is part of the Editor Focus
+ if (auto focusModeInterface = AZ::Interface::Get();
+ !focusModeInterface->IsInFocusSubTree(entityId))
+ {
+ return false;
+ }
+
+ // Detect if the Entity is a descendant of a closed container
+ if (auto containerEntityInterface = AZ::Interface::Get();
+ containerEntityInterface->IsUnderClosedContainerEntity(entityId))
+ {
+ return false;
+ }
+
+ return true;
}
static void SetEntityLockStateRecursively(
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
index 9ffc18af5a..fcec1edd54 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabFocusHandler.cpp
@@ -196,6 +196,9 @@ namespace AzToolsFramework::Prefab
Initialize();
}
+ // Clear the old focus vector
+ m_instanceFocusVector.clear();
+
// Focus on the root prefab (AZ::EntityId() will default to it)
FocusOnOwningPrefab(AZ::EntityId());
}
@@ -230,7 +233,7 @@ namespace AzToolsFramework::Prefab
{
if (instance.has_value())
{
- m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), true);
+ m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), true);
}
}
}
@@ -241,7 +244,7 @@ namespace AzToolsFramework::Prefab
{
if (instance.has_value())
{
- m_containerEntityInterface->SetContainerOpenState(instance->get().GetContainerEntityId(), false);
+ m_containerEntityInterface->SetContainerOpen(instance->get().GetContainerEntityId(), false);
}
}
}
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp
index d4b227c4ff..24cb71499e 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp
@@ -137,6 +137,7 @@ namespace AzToolsFramework
}
EditorContextMenuBus::Handler::BusConnect();
+ EditorEventsBus::Handler::BusConnect();
PrefabInstanceContainerNotificationBus::Handler::BusConnect();
AZ::Interface::Register(this);
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusConnect(s_prefabFileExtension);
@@ -147,6 +148,7 @@ namespace AzToolsFramework
AssetBrowser::AssetBrowserSourceDropBus::Handler::BusDisconnect();
AZ::Interface::Unregister(this);
PrefabInstanceContainerNotificationBus::Handler::BusDisconnect();
+ EditorEventsBus::Handler::BusDisconnect();
EditorContextMenuBus::Handler::BusDisconnect();
}
@@ -313,6 +315,11 @@ namespace AzToolsFramework
}
}
+ void PrefabIntegrationManager::OnEscape()
+ {
+ s_prefabFocusInterface->FocusOnOwningPrefab(AZ::EntityId());
+ }
+
void PrefabIntegrationManager::HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const
{
auto instantiatePrefabOutcome = s_prefabPublicInterface->InstantiatePrefab(sourceFilePath, parentId, position);
@@ -1393,7 +1400,7 @@ namespace AzToolsFramework
AZStd::unique_ptr PrefabIntegrationManager::ConstructUnsavedPrefabsCard(TemplateId templateId)
{
- FlowLayout* unsavedPrefabsLayout = new FlowLayout(AzToolsFramework::GetActiveWindow());
+ FlowLayout* unsavedPrefabsLayout = new FlowLayout(nullptr);
AZStd::set dirtyTemplatePaths = s_prefabSystemComponentInterface->GetDirtyTemplatePaths(templateId);
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h
index 696c05991c..6788af31e9 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.h
@@ -51,6 +51,7 @@ namespace AzToolsFramework
class PrefabIntegrationManager final
: public EditorContextMenuBus::Handler
+ , public EditorEventsBus::Handler
, public AssetBrowser::AssetBrowserSourceDropBus::Handler
, public PrefabInstanceContainerNotificationBus::Handler
, public PrefabIntegrationInterface
@@ -64,19 +65,22 @@ namespace AzToolsFramework
static void Reflect(AZ::ReflectContext* context);
- // EditorContextMenuBus...
+ // EditorContextMenuBus overrides ...
int GetMenuPosition() const override;
AZStd::string GetMenuIdentifier() const override;
void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override;
- // EntityOutlinerSourceDropHandlingBus...
+ // EditorEventsBus overrides ...
+ void OnEscape();
+
+ // EntityOutlinerSourceDropHandlingBus overrides ...
void HandleSourceFileType(AZStd::string_view sourceFilePath, AZ::EntityId parentId, AZ::Vector3 position) const override;
- // PrefabInstanceContainerNotificationBus...
+ // PrefabInstanceContainerNotificationBus overrides ...
void OnPrefabComponentActivate(AZ::EntityId entityId) override;
void OnPrefabComponentDeactivate(AZ::EntityId entityId) override;
- // PrefabIntegrationInterface...
+ // PrefabIntegrationInterface overrides ...
AZ::EntityId CreateNewEntityAtPosition(const AZ::Vector3& position, AZ::EntityId parentId) override;
int ExecuteClosePrefabDialog(TemplateId templateId) override;
void ExecuteSavePrefabDialog(TemplateId templateId, bool useSaveAllPrefabsPreference) override;
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp
index 3ce350287f..bb718d0dc9 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.cpp
@@ -187,15 +187,14 @@ namespace AzToolsFramework
}
// Verify if the entity Id corresponds to an entity that is focused; if not, halt selection.
- if (!m_focusModeInterface->IsInFocusSubTree(entityIdUnderCursor))
+ if (!IsSelectableAccordingToFocusMode(entityIdUnderCursor))
{
return AZ::EntityId();
}
// Container Entity support - if the entity that is being selected is part of a closed container,
// change the selection to the container instead.
- ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get();
- if (containerEntityInterface)
+ if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get())
{
return containerEntityInterface->FindHighestSelectableEntity(entityIdUnderCursor);
}
@@ -217,7 +216,7 @@ namespace AzToolsFramework
{
const AZ::EntityId entityId = m_entityDataCache->GetVisibleEntityId(entityCacheIndex);
- if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex))
+ if (!m_entityDataCache->IsVisibleEntityVisible(entityCacheIndex) || !IsSelectableInViewport(entityId))
{
continue;
}
@@ -263,4 +262,24 @@ namespace AzToolsFramework
}
}
}
+
+ bool EditorHelpers::IsSelectableInViewport(AZ::EntityId entityId)
+ {
+ return IsSelectableAccordingToFocusMode(entityId) && IsSelectableAccordingToContainerEntities(entityId);
+ }
+
+ bool EditorHelpers::IsSelectableAccordingToFocusMode(AZ::EntityId entityId)
+ {
+ return m_focusModeInterface->IsInFocusSubTree(entityId);
+ }
+
+ bool EditorHelpers::IsSelectableAccordingToContainerEntities(AZ::EntityId entityId)
+ {
+ if (ContainerEntityInterface* containerEntityInterface = AZ::Interface::Get())
+ {
+ return !containerEntityInterface->IsUnderClosedContainerEntity(entityId);
+ }
+
+ return true;
+ }
} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h
index a6a78a4e61..909a231635 100644
--- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h
+++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorHelpers.h
@@ -58,7 +58,19 @@ namespace AzToolsFramework
AzFramework::DebugDisplayRequests& debugDisplay,
const AZStd::function& showIconCheck);
+ //! Returns whether the entityId can be selected in the viewport according
+ //! to the current Editor Focus Mode and Container Entity setup.
+ bool IsSelectableInViewport(AZ::EntityId entityId);
+
private:
+ //! Returns whether the entityId can be selected in the viewport according
+ //! to the current Editor Focus Mode setup.
+ bool IsSelectableAccordingToFocusMode(AZ::EntityId entityId);
+
+ //! Returns whether the entityId can be selected in the viewport according
+ //! to the current Container Entityu setup.
+ bool IsSelectableAccordingToContainerEntities(AZ::EntityId entityId);
+
const EditorVisibleEntityDataCache* m_entityDataCache = nullptr; //!< Entity Data queried by the EditorHelpers.
const FocusModeInterface* m_focusModeInterface = nullptr;
};
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp
new file mode 100644
index 0000000000..a47e41da42
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntitySelectionTests.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+namespace AzToolsFramework
+{
+ TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithNoContainers)
+ {
+ // When no containers are in the way, the function will just return the entityId of the entity that was clicked.
+
+ // Click on Car Entity
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
+
+ // Verify the correct entity is selected
+ auto selectedEntitiesAfter = GetSelectedEntities();
+ EXPECT_EQ(selectedEntitiesAfter.size(), 1);
+ EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithClosedContainer)
+ {
+ // If a closed container is an ancestor of the queried entity, the closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]); // Containers are closed by default
+
+ // Click on Car Entity
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
+
+ // Verify the correct entity is selected
+ auto selectedEntitiesAfter = GetSelectedEntities();
+ EXPECT_EQ(selectedEntitiesAfter.size(), 1);
+ EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[StreetEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ }
+
+ TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithOpenContainer)
+ {
+ // If a closed container is an ancestor of the queried entity, the closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+
+ // Click on Car Entity
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
+
+ // Verify the correct entity is selected
+ auto selectedEntitiesAfter = GetSelectedEntities();
+ EXPECT_EQ(selectedEntitiesAfter.size(), 1);
+ EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ }
+
+ TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleClosedContainers)
+ {
+ // If multiple closed containers are ancestors of the queried entity, the highest closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+
+ // Click on Car Entity
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
+
+ // Verify the correct entity is selected
+ auto selectedEntitiesAfter = GetSelectedEntities();
+ EXPECT_EQ(selectedEntitiesAfter.size(), 1);
+ EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CityEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+ }
+
+ TEST_F(EditorFocusModeSelectionFixture, ContainerEntitySelectionTests_FindHighestSelectableEntityWithMultipleContainers)
+ {
+ // If multiple containers are ancestors of the queried entity, the highest closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true);
+
+ // Click on Car Entity
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
+
+ // Verify the correct entity is selected
+ auto selectedEntitiesAfter = GetSelectedEntities();
+ EXPECT_EQ(selectedEntitiesAfter.size(), 1);
+ EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[StreetEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+ }
+}
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp
new file mode 100644
index 0000000000..031062f027
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/ContainerEntityTests.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+namespace AzToolsFramework
+{
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_Register)
+ {
+ // Registering an entity is successful.
+ auto outcome = m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
+ EXPECT_TRUE(outcome.IsSuccess());
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_RegisterTwice)
+ {
+ // Registering an entity twice fails.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
+ auto outcome = m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
+ EXPECT_FALSE(outcome.IsSuccess());
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_Unregister)
+ {
+ // Unregistering a container entity is successful.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CarEntityName]);
+ auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
+ EXPECT_TRUE(outcome.IsSuccess());
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterRegularEntity)
+ {
+ // Unregistering an entity that was not previously registered fails.
+ auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
+ EXPECT_FALSE(outcome.IsSuccess());
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_UnregisterTwice)
+ {
+ // Unregistering a container entity twice fails.
+ auto outcome = m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CarEntityName]);
+ EXPECT_FALSE(outcome.IsSuccess());
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegularEntity)
+ {
+ // If a regular entity is passed, IsContainer returns false.
+ // Note that we use a different entity than the tests above to validate a completely new EntityId.
+ bool isContainer = m_containerEntityInterface->IsContainer(m_entityMap[SportsCarEntityName]);
+ EXPECT_FALSE(isContainer);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnRegisteredContainer)
+ {
+ // If a container entity is passed, IsContainer returns true.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ bool isContainer = m_containerEntityInterface->IsContainer(m_entityMap[SportsCarEntityName]);
+ EXPECT_TRUE(isContainer);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOnUnRegisteredContainer)
+ {
+ // If an entity that was previously a container but was then unregistered is passed, IsContainer returns false.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+
+ bool isContainer = m_containerEntityInterface->IsContainer(m_entityMap[SportsCarEntityName]);
+ EXPECT_FALSE(isContainer);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenOnRegularEntity)
+ {
+ // Setting a regular entity to open should return a failure.
+ auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+ EXPECT_FALSE(outcome.IsSuccess());
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpen)
+ {
+ // Set a container entity to open, and verify the operation was successful.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+ EXPECT_TRUE(outcome.IsSuccess());
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerOpenTwice)
+ {
+ // Set a container entity to open twice, and verify that does not cause a failure (as intended).
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+ auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+ EXPECT_TRUE(outcome.IsSuccess());
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_SetContainerClosed)
+ {
+ // Set a container entity to closed, and verify the operation was successful.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ auto outcome = m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+ EXPECT_TRUE(outcome.IsSuccess());
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnRegularEntity)
+ {
+ // Query open state on a regular entity, and verify it returns true.
+ // Open containers behave exactly as regular entities, so this is the expected return value.
+ bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]);
+ EXPECT_TRUE(isOpen);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnDefaultContainerEntity)
+ {
+ // Query open state on a newly registered container entity, and verify it returns false.
+ // Containers are registered closed by default.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+ bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]);
+ EXPECT_FALSE(isOpen);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnOpenContainerEntity)
+ {
+ // Query open state on a container entity that was opened, and verify it returns true.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true);
+ bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]);
+ EXPECT_TRUE(isOpen);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_IsContainerOpenOnClosedContainerEntity)
+ {
+ // Query open state on a container entity that was opened and then closed, and verify it returns false.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], false);
+ bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]);
+ EXPECT_FALSE(isOpen);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_ContainerOpenStateIsPreserved)
+ {
+ // Register an entity as container, open it, then unregister it.
+ // When the entity is registered again, the open state should be preserved.
+ // This behavior is necessary for the system to work alongside Prefab propagation refreshes.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[CityEntityName], true);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[CityEntityName]);
+ bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[CityEntityName]);
+ EXPECT_TRUE(isOpen);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[CityEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceeds)
+ {
+ // The Clear function works if no container is registered.
+ auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId);
+ EXPECT_TRUE(outcome.IsSuccess());
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearFailsIfContainersAreStillRegistered)
+ {
+ // The Clear function fails if a container is registered.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId);
+ EXPECT_FALSE(outcome.IsSuccess());
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearSucceedsIfContainersAreUnregistered)
+ {
+ // The Clear function fails if a container is registered.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ auto outcome = m_containerEntityInterface->Clear(m_editorEntityContextId);
+ EXPECT_TRUE(outcome.IsSuccess());
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_ClearDeletesPreservedOpenStates)
+ {
+ // Register an entity as container, open it, unregister it, then call clear.
+ // When the entity is registered again, the open state should not be preserved.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[Passenger1EntityName], true);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+
+ m_containerEntityInterface->Clear(m_editorEntityContextId);
+
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ bool isOpen = m_containerEntityInterface->IsContainerOpen(m_entityMap[Passenger1EntityName]);
+ EXPECT_FALSE(isOpen);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[Passenger1EntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithNoContainers)
+ {
+ // When no containers are in the way, the function will just return the entityId that was passed to it.
+ AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]);
+ EXPECT_EQ(selectedEntityId, m_entityMap[Passenger2EntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithClosedContainer)
+ {
+ // If a closed container is an ancestor of the queried entity, the closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]); // Containers are closed by default
+ AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]);
+ EXPECT_EQ(selectedEntityId, m_entityMap[SportsCarEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithOpenContainer)
+ {
+ // If an open container is an ancestor of the queried entity, it is ignored.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[SportsCarEntityName], true);
+
+ AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]);
+ EXPECT_EQ(selectedEntityId, m_entityMap[Passenger2EntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleClosedContainers)
+ {
+ // If multiple closed containers are ancestors of the queried entity, the highest closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+
+ AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]);
+ EXPECT_EQ(selectedEntityId, m_entityMap[StreetEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ }
+
+ TEST_F(EditorFocusModeFixture, ContainerEntityTests_FindHighestSelectableEntityWithMultipleContainers)
+ {
+ // If multiple containers are ancestors of the queried entity, the highest closed container is selected.
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->RegisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ m_containerEntityInterface->SetContainerOpen(m_entityMap[StreetEntityName], true);
+
+ AZ::EntityId selectedEntityId = m_containerEntityInterface->FindHighestSelectableEntity(m_entityMap[Passenger2EntityName]);
+ EXPECT_EQ(selectedEntityId, m_entityMap[SportsCarEntityName]);
+
+ // Restore default state for other tests.
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[StreetEntityName]);
+ m_containerEntityInterface->UnregisterEntityAsContainer(m_entityMap[SportsCarEntityName]);
+ }
+
+}
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp
index c309261a27..49bf7cee15 100644
--- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.cpp
@@ -14,6 +14,20 @@
namespace AzToolsFramework
{
+ void ClearSelectedEntities()
+ {
+ AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
+ &AzToolsFramework::ToolsApplicationRequestBus::Events::SetSelectedEntities, AzToolsFramework::EntityIdList());
+ }
+
+ AzToolsFramework::EntityIdList EditorFocusModeFixture::GetSelectedEntities()
+ {
+ AzToolsFramework::EntityIdList selectedEntities;
+ AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
+ selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities);
+ return selectedEntities;
+ }
+
void EditorFocusModeFixture::SetUpEditorFixtureImpl()
{
// Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is
@@ -21,6 +35,9 @@ namespace AzToolsFramework
// in the unit tests.
AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize);
+ m_containerEntityInterface = AZ::Interface::Get();
+ ASSERT_TRUE(m_containerEntityInterface != nullptr);
+
m_focusModeInterface = AZ::Interface::Get();
ASSERT_TRUE(m_focusModeInterface != nullptr);
@@ -31,6 +48,24 @@ namespace AzToolsFramework
m_editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId);
GenerateTestHierarchy();
+
+ // Clear the focus, disabling focus mode
+ m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
+
+ // Clear selection
+ ClearSelectedEntities();
+ }
+
+ void EditorFocusModeFixture::TearDownEditorFixtureImpl()
+ {
+ // Clear Container Entity preserved open states
+ m_containerEntityInterface->Clear(m_editorEntityContextId);
+
+ // Clear the focus, disabling focus mode
+ m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
+
+ // Clear selection
+ ClearSelectedEntities();
}
void EditorFocusModeFixture::GenerateTestHierarchy()
@@ -59,7 +94,7 @@ namespace AzToolsFramework
entity->Activate();
// Move the CarEntity so it's out of the way.
- AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, CarEntityPosition);
+ AZ::TransformBus::Event(m_entityMap[CarEntityName], &AZ::TransformBus::Events::SetWorldTranslation, WorldCarEntityPosition);
// Setup the camera so the Car entity is in view.
AzFramework::SetCameraTransform(
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h
index f038408012..c48795a3a4 100644
--- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeFixture.h
@@ -14,6 +14,7 @@
#include
+#include
#include
#include
@@ -24,16 +25,20 @@ namespace AzToolsFramework
{
protected:
void SetUpEditorFixtureImpl() override;
+ void TearDownEditorFixtureImpl() override;
void GenerateTestHierarchy();
AZ::EntityId CreateEditorEntity(const char* name, AZ::EntityId parentId);
AZStd::unordered_map m_entityMap;
+
+ ContainerEntityInterface* m_containerEntityInterface = nullptr;
FocusModeInterface* m_focusModeInterface = nullptr;
public:
- AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
+ AzToolsFramework::EntityIdList GetSelectedEntities();
+ AzFramework::EntityContextId m_editorEntityContextId = AzFramework::EntityContextId::CreateNull();
AzFramework::CameraState m_cameraState;
inline static const AZ::Vector3 CameraPosition = AZ::Vector3(10.0f, 15.0f, 10.0f);
@@ -45,6 +50,7 @@ namespace AzToolsFramework
inline static const char* Passenger1EntityName = "Passenger1";
inline static const char* Passenger2EntityName = "Passenger2";
- inline static AZ::Vector3 CarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f);
+ inline static AZ::Vector3 WorldCarEntityPosition = AZ::Vector3(5.0f, 15.0f, 0.0f);
};
+
}
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h
new file mode 100644
index 0000000000..4c9369bc46
--- /dev/null
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionFixture.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include
+
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace AzToolsFramework
+{
+ class EditorFocusModeSelectionFixture : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin
+ {
+ public:
+ void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition)
+ {
+ // Calculate the world position in screen space
+ const auto carScreenPosition = AzFramework::WorldToScreen(worldPosition, m_cameraState);
+
+ // Click the entity in the viewport
+ m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
+ }
+ };
+} // namespace AzToolsFramework
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp
index 968bb3f293..2f746c9d63 100644
--- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeSelectionTests.cpp
@@ -6,64 +6,14 @@
*
*/
-#include
-
-#include
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
+#include
namespace AzToolsFramework
{
- class EditorFocusModeSelectionFixture
- : public UnitTest::IndirectCallManipulatorViewportInteractionFixtureMixin
- {
- public:
- void ClickAtWorldPositionOnViewport(const AZ::Vector3& worldPosition)
- {
- // Calculate the world position in screen space
- const auto carScreenPosition = AzFramework::WorldToScreen(worldPosition, m_cameraState);
-
- // Click the entity in the viewport
- m_actionDispatcher->CameraState(m_cameraState)->MousePosition(carScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
- }
- };
-
- void ClearSelectedEntities()
- {
- AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
- &AzToolsFramework::ToolsApplicationRequestBus::Events::SetSelectedEntities, AzToolsFramework::EntityIdList());
- }
-
- AzToolsFramework::EntityIdList GetSelectedEntities()
- {
- AzToolsFramework::EntityIdList selectedEntities;
- AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
- selectedEntities, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetSelectedEntities);
- return selectedEntities;
- }
-
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnLevel)
{
- // Clear the focus, disabling focus mode
- m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull());
- // Clear selection
- ClearSelectedEntities();
-
// Click on Car Entity
- ClickAtWorldPositionOnViewport(CarEntityPosition);
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
// Verify entity is selected
auto selectedEntitiesAfter = GetSelectedEntities();
@@ -75,73 +25,53 @@ namespace AzToolsFramework
{
// Set the focus on the Street Entity (parent of the test entity)
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
- // Clear selection
- ClearSelectedEntities();
// Click on Car Entity
- ClickAtWorldPositionOnViewport(CarEntityPosition);
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
// Verify entity is selected
auto selectedEntitiesAfter = GetSelectedEntities();
EXPECT_EQ(selectedEntitiesAfter.size(), 1);
EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
-
- // Clear the focus, disabling focus mode
- m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull());
}
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnItself)
{
// Set the focus on the Car Entity (test entity)
m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
- // Clear selection
- ClearSelectedEntities();
// Click on Car Entity
- ClickAtWorldPositionOnViewport(CarEntityPosition);
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
// Verify entity is selected
auto selectedEntitiesAfter = GetSelectedEntities();
EXPECT_EQ(selectedEntitiesAfter.size(), 1);
EXPECT_EQ(selectedEntitiesAfter.front(), m_entityMap[CarEntityName]);
-
- // Clear the focus, disabling focus mode
- m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull());
}
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnSibling)
{
// Set the focus on the SportsCar Entity (sibling of the test entity)
m_focusModeInterface->SetFocusRoot(m_entityMap[SportsCarEntityName]);
- // Clear selection
- ClearSelectedEntities();
// Click on Car Entity
- ClickAtWorldPositionOnViewport(CarEntityPosition);
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
// Verify entity is selected
auto selectedEntitiesAfter = GetSelectedEntities();
EXPECT_EQ(selectedEntitiesAfter.size(), 0);
-
- // Clear the focus, disabling focus mode
- m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull());
}
TEST_F(EditorFocusModeSelectionFixture, EditorFocusModeSelectionTests_SelectEntityWithFocusOnDescendant)
{
// Set the focus on the Passenger1 Entity (child of the entity)
m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger1EntityName]);
- // Clear selection
- ClearSelectedEntities();
// Click on Car Entity
- ClickAtWorldPositionOnViewport(CarEntityPosition);
+ ClickAtWorldPositionOnViewport(WorldCarEntityPosition);
// Verify entity is selected
auto selectedEntitiesAfter = GetSelectedEntities();
EXPECT_EQ(selectedEntitiesAfter.size(), 0);
-
- // Clear the focus, disabling focus mode
- m_focusModeInterface->ClearFocusRoot(AzFramework::EntityContextId::CreateNull());
}
}
diff --git a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp
index 22bc7a494c..eec3902f99 100644
--- a/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp
+++ b/Code/Framework/AzToolsFramework/Tests/FocusMode/EditorFocusModeTests.cpp
@@ -33,55 +33,40 @@ namespace AzToolsFramework
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_AncestorsDescendants)
{
// When the focus is set to an entity, all its descendants are in the focus subtree while the ancestors aren't.
- {
- m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
+ m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
- }
-
- // Restore default expected focus.
- m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
}
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Siblings)
{
// If the root entity has siblings, they are also outside of the focus subtree.
- {
- m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
+ m_focusModeInterface->SetFocusRoot(m_entityMap[CarEntityName]);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false);
- }
-
- // Restore default expected focus.
- m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), false);
}
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Leaf)
{
// If the root is a leaf, then the focus subtree will consists of just that entity.
- {
- m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]);
+ m_focusModeInterface->SetFocusRoot(m_entityMap[Passenger2EntityName]);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
- }
-
- // Restore default expected focus.
- m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), false);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
}
TEST_F(EditorFocusModeFixture, EditorFocusModeTests_IsInFocusSubTree_Clear)
@@ -90,15 +75,13 @@ namespace AzToolsFramework
m_focusModeInterface->SetFocusRoot(m_entityMap[StreetEntityName]);
// When the focus is cleared, the whole level is in the focus subtree; so we expect all entities to return true.
- {
- m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
+ m_focusModeInterface->ClearFocusRoot(m_editorEntityContextId);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true);
- EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
- }
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CityEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[StreetEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[CarEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger1EntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[SportsCarEntityName]), true);
+ EXPECT_EQ(m_focusModeInterface->IsInFocusSubTree(m_entityMap[Passenger2EntityName]), true);
}
}
diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
index 87d522c4a6..ef6774f620 100644
--- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
+++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake
@@ -37,8 +37,11 @@ set(FILES
EntityTestbed.h
FileFunc.cpp
FingerprintingTests.cpp
+ FocusMode/ContainerEntitySelectionTests.cpp
+ FocusMode/ContainerEntityTests.cpp
FocusMode/EditorFocusModeFixture.cpp
FocusMode/EditorFocusModeFixture.h
+ FocusMode/EditorFocusModeSelectionFixture.h
FocusMode/EditorFocusModeSelectionTests.cpp
FocusMode/EditorFocusModeTests.cpp
GenericComponentWrapperTest.cpp
diff --git a/Code/Legacy/CrySystem/SystemInit.cpp b/Code/Legacy/CrySystem/SystemInit.cpp
index 6de10f3855..ee1c498a9a 100644
--- a/Code/Legacy/CrySystem/SystemInit.cpp
+++ b/Code/Legacy/CrySystem/SystemInit.cpp
@@ -1273,17 +1273,6 @@ AZ_POP_DISABLE_WARNING
//Load config files
//////////////////////////////////////////////////////////////////////////
- int curSpecVal = 0;
- ICVar* pSysSpecCVar = gEnv->pConsole->GetCVar("r_GraphicsQuality");
- if (gEnv->pSystem->IsDevMode())
- {
- if (pSysSpecCVar && pSysSpecCVar->GetFlags() & VF_WASINCONFIG)
- {
- curSpecVal = pSysSpecCVar->GetIVal();
- pSysSpecCVar->SetFlags(pSysSpecCVar->GetFlags() | VF_SYSSPEC_OVERWRITE);
- }
- }
-
// tools may not interact with @user@
if (!gEnv->IsInToolMode())
{
@@ -1293,16 +1282,6 @@ AZ_POP_DISABLE_WARNING
}
}
- // If sys spec variable was specified, is not 0, and we are in devmode restore the value from before loading game.cfg
- // This enables setting of a specific sys_spec outside menu and game.cfg
- if (gEnv->pSystem->IsDevMode())
- {
- if (pSysSpecCVar && curSpecVal && curSpecVal != pSysSpecCVar->GetIVal())
- {
- pSysSpecCVar->Set(curSpecVal);
- }
- }
-
{
// We have to load this file again since first time we did it without devmode
LoadConfiguration(m_systemConfigName.c_str());
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
index 14c76bd0c2..61220cefe7 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoInfo.h
@@ -30,7 +30,7 @@ namespace O3DE::ProjectManager
bool operator<(const GemRepoInfo& gemRepoInfo) const;
QString m_path = "";
- QString m_name = "Unknown Gem Repo Name";
+ QString m_name = "Unknown Repo Name";
QString m_creator = "Unknown Creator";
bool m_isEnabled = false; //! Is the repo currently enabled for this engine?
QString m_summary = "No summary provided.";
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
index 88ccee2636..58b10a1d1a 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoItemDelegate.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
#include
@@ -95,7 +96,7 @@ namespace O3DE::ProjectManager
painter->drawText(repoCreatorRect, Qt::TextSingleLine, repoCreator);
// Repo update
- QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString("dd/MM/yyyy hh:mmap");
+ QString repoUpdatedDate = GemRepoModel::GetLastUpdated(modelIndex).toString(RepoTimeFormat);
repoUpdatedDate = standardFontMetrics.elidedText(repoUpdatedDate, Qt::TextElideMode::ElideRight, s_updatedMaxWidth);
QRect repoUpdatedDateRect = GetTextRect(standardFont, repoUpdatedDate, s_fontSize);
diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
index 9c432884e6..a233010225 100644
--- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
+++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
@@ -104,9 +105,29 @@ namespace O3DE::ProjectManager
{
// Add all available repos to the model
const QVector allGemRepoInfos = allGemRepoInfosResult.GetValue();
+ QDateTime oldestRepoUpdate;
+ if (!allGemRepoInfos.isEmpty())
+ {
+ oldestRepoUpdate = allGemRepoInfos[0].m_lastUpdated;
+ }
for (const GemRepoInfo& gemRepoInfo : allGemRepoInfos)
{
m_gemRepoModel->AddGemRepo(gemRepoInfo);
+
+ // Find least recently updated repo
+ if (gemRepoInfo.m_lastUpdated < oldestRepoUpdate)
+ {
+ oldestRepoUpdate = gemRepoInfo.m_lastUpdated;
+ }
+ }
+
+ if (!allGemRepoInfos.isEmpty())
+ {
+ m_lastAllUpdateLabel->setText(tr("Last Updated: %1").arg(oldestRepoUpdate.toString(RepoTimeFormat)));
+ }
+ else
+ {
+ m_lastAllUpdateLabel->setText(tr("Last Updated: Never"));
}
}
else
diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h
index 81320e3732..d784fcf5fd 100644
--- a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h
+++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h
@@ -27,4 +27,6 @@ namespace O3DE::ProjectManager
static const QString ProjectCMakeCommand = "cmake";
static const QString ProjectCMakeBuildTargetEditor = "Editor";
+ static const QString RepoTimeFormat = "dd/MM/yyyy hh:mmap";
+
} // namespace O3DE::ProjectManager
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
index 768e44ce15..83f93630ac 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp
@@ -932,13 +932,55 @@ namespace O3DE::ProjectManager
return AZ::Failure("Adding Gem Repo not implemented yet in o3de scripts.");
}
- GemRepoInfo PythonBindings::GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath)
+ GemRepoInfo PythonBindings::GetGemRepoInfo(pybind11::handle repoUri)
{
- /* Placeholder Logic */
- (void)path;
- (void)pyEnginePath;
+ GemRepoInfo gemRepoInfo;
+ gemRepoInfo.m_repoLink = Py_To_String(repoUri);
- return GemRepoInfo();
+ auto data = m_manifest.attr("get_repo_json_data")(repoUri);
+ if (pybind11::isinstance(data))
+ {
+ try
+ {
+ // required
+ gemRepoInfo.m_repoLink = Py_To_String(data["repo_uri"]);
+ gemRepoInfo.m_name = Py_To_String(data["repo_name"]);
+ gemRepoInfo.m_creator = Py_To_String(data["origin"]);
+
+ // optional
+ gemRepoInfo.m_summary = Py_To_String_Optional(data, "summary", "No summary provided.");
+ gemRepoInfo.m_additionalInfo = Py_To_String_Optional(data, "additional_info", "");
+
+ auto repoPath = m_manifest.attr("get_repo_path")(repoUri);
+ gemRepoInfo.m_path = gemRepoInfo.m_directoryLink = Py_To_String(repoPath);
+
+ QString lastUpdated = Py_To_String_Optional(data, "last_updated", "");
+ gemRepoInfo.m_lastUpdated = QDateTime::fromString(lastUpdated, RepoTimeFormat);
+
+ if (data.contains("enabled"))
+ {
+ gemRepoInfo.m_isEnabled = data["enabled"].cast();
+ }
+ else
+ {
+ gemRepoInfo.m_isEnabled = false;
+ }
+
+ if (data.contains("gem_paths"))
+ {
+ for (auto gemPath : data["gem_paths"])
+ {
+ gemRepoInfo.m_includedGemPaths.push_back(Py_To_String(gemPath));
+ }
+ }
+ }
+ catch ([[maybe_unused]] const std::exception& e)
+ {
+ AZ_Warning("PythonBindings", false, "Failed to get GemRepoInfo for repo %s", Py_To_String(repoUri));
+ }
+ }
+
+ return gemRepoInfo;
}
//#define MOCK_GEM_REPO_INFO true
@@ -951,14 +993,10 @@ namespace O3DE::ProjectManager
auto result = ExecuteWithLockErrorHandling(
[&]
{
- /* Placeholder Logic, o3de scripts need method added
- *
- for (auto path : m_manifest.attr("get_gem_repos")())
+ for (auto repoUri : m_manifest.attr("get_repos")())
{
- gemRepos.push_back(GemRepoInfoFromPath(path, pybind11::none()));
+ gemRepos.push_back(GetGemRepoInfo(repoUri));
}
- *
- */
});
if (!result.IsSuccess())
{
diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h
index 5542fe146e..090094e9b6 100644
--- a/Code/Tools/ProjectManager/Source/PythonBindings.h
+++ b/Code/Tools/ProjectManager/Source/PythonBindings.h
@@ -67,7 +67,7 @@ namespace O3DE::ProjectManager
AZ::Outcome ExecuteWithLockErrorHandling(AZStd::function executionCallback);
bool ExecuteWithLock(AZStd::function executionCallback);
GemInfo GemInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
- GemRepoInfo GemRepoInfoFromPath(pybind11::handle path, pybind11::handle pyEnginePath);
+ GemRepoInfo GetGemRepoInfo(pybind11::handle repoUri);
ProjectInfo ProjectInfoFromPath(pybind11::handle path);
ProjectTemplateInfo ProjectTemplateInfoFromPath(pybind11::handle path, pybind11::handle pyProjectPath);
bool RegisterThisEngine();
diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h
index 96393f4a1f..99e752c90a 100644
--- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h
+++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageFlags.h
@@ -22,7 +22,7 @@ namespace ImageProcessingAtom
const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use
const static AZ::u32 EIF_AttachedAlpha = 0x400; // info for the engine: it's a texture with attached alpha channel
const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear)
- const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized with r_TexResolution
+ const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized
const static AZ::u32 EIF_RenormalizedTexture = 0x10000; // info for the engine: for dds textures that have renormalized color range
const static AZ::u32 EIF_CafeNative = 0x20000; // info for the engine: native Cafe texture format
const static AZ::u32 EIF_RestrictedPlatformONative = 0x40000; // native tiled texture for restrict platform O
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl
index 26a7e21a6a..11859de7d6 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl
@@ -185,7 +185,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
float detailLayerNormalFactor = MaterialSrg::m_detail_normal_factor * detailLayerBlendFactor;
-
+ surface.vertexNormal = normalize(IN.m_normal);
surface.normal = GetDetailedNormalInputWS(
isFrontFace, IN.m_normal,
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_normalFactor, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, uvMatrix, o_normal_useTexture,
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl
index 97cbfb2622..05059aba6f 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.azsl
@@ -237,6 +237,7 @@ PbrLightingOutput SkinPS_Common(VSOutput IN)
normalMapSample = ApplyNormalWrinkleMap(o_wrinkleLayers_normal_useTexture4, normalMapSample, MaterialSrg::m_wrinkle_normal_texture4, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, IN.m_wrinkleBlendFactors.a);
}
+ surface.vertexNormal = normalize(IN.m_normal);
if(o_detail_normal_useTexture)
{
float3 normalTS = GetTangentSpaceNormal(normalMapSample, uvMatrix, MaterialSrg::m_normalFactor);
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl
index 5d2aec063b..6a97c0e785 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_ForwardPass.azsl
@@ -445,6 +445,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
normalTS = ReorientTangentSpaceNormal(normalTS, lightingInputLayer3.m_normalTS);
}
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
+ surface.vertexNormal = normalize(IN.m_normal);
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
// ------- Combine Albedo, roughness, specular, roughness ---------
diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl
index 1fa5fc683c..8df5e1ba56 100644
--- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl
+++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl
@@ -146,7 +146,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float2 normalUv = IN.m_uv[MaterialSrg::m_normalMapUvIndex];
float3x3 uvMatrix = MaterialSrg::m_normalMapUvIndex == 0 ? MaterialSrg::m_uvMatrix : CreateIdentity3x3(); // By design, only UV0 is allowed to apply transforms.
-
+ surface.vertexNormal = normalize(IN.m_normal);
surface.normal = GetNormalInputWS(MaterialSrg::m_normalMap, MaterialSrg::m_sampler, normalUv, MaterialSrg::m_flipNormalX, MaterialSrg::m_flipNormalY, isFrontFace, IN.m_normal,
tangents[MaterialSrg::m_normalMapUvIndex], bitangents[MaterialSrg::m_normalMapUvIndex], uvMatrix, o_normal_useTexture, MaterialSrg::m_normalFactor);
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli
index 34c17e388c..1eee53a24f 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DirectionalLight.azsli
@@ -24,7 +24,7 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData)
litRatio = DirectionalLightShadow::GetVisibility(
shadowIndex,
lightingData.shadowCoords,
- surface.normal,
+ surface.vertexNormal,
debugInfo);
if (o_transmission_mode == TransmissionMode::ThickObject)
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli
index ac9227f64a..63f671f021 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/DiskLight.azsli
@@ -86,7 +86,7 @@ void ApplyDiskLight(ViewSrg::DiskLight light, Surface surface, inout LightingDat
light.m_position,
surface.position,
-dirToConeTip,
- surface.normal);
+ surface.vertexNormal);
// Use backShadowRatio to carry thickness from shadow map for thick mode
backShadowRatio = 1.0 - litRatio;
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli
index b88b6574a4..e6eea9728f 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Lights/PointLight.azsli
@@ -83,7 +83,7 @@ void ApplyPointLight(ViewSrg::PointLight light, Surface surface, inout LightingD
light.m_position,
surface.position,
lightDir,
- surface.normal);
+ surface.vertexNormal);
// Use backShadowRatio to carry thickness from shadow map for thick mode
backShadowRatio = 1.0 - litRatio;
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli
index 1b0ac3d76d..eb8c33cdce 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/EnhancedSurface.azsli
@@ -23,6 +23,7 @@ class Surface
float3 position; //!< Position in world-space
float3 normal; //!< Normal in world-space
+ float3 vertexNormal; //!< Vertex normal in world-space
float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value
float3 specularF0; //!< Fresnel f0 spectral value of the surface
float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli
index 40f30d4f03..f82d80adee 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/SkinSurface.azsli
@@ -22,6 +22,7 @@ class Surface
float3 position; //!< Position in world-space
float3 normal; //!< Normal in world-space
+ float3 vertexNormal; //!< Vertex normal in world-space
float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value
float3 specularF0; //!< Fresnel f0 spectral value of the surface
float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
index 30e90323a5..084943bf38 100644
--- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
+++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/Surfaces/StandardSurface.azsli
@@ -22,6 +22,7 @@ class Surface
float3 position; //!< Position in world-space
float3 normal; //!< Normal in world-space
+ float3 vertexNormal; //!< Vertex normal in world-space
float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value
float3 specularF0; //!< Fresnel f0 spectral value of the surface
float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp
index 042e934eb0..6e78d3170c 100644
--- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp
+++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.cpp
@@ -507,8 +507,13 @@ namespace AZ
}
}
- RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers"));
- m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, meshBuffers);
+ //Check if buffer view data changed from previous frame.
+ if (m_meshBuffers.size() != meshBuffers.size() || m_meshBuffers != meshBuffers)
+ {
+ m_meshBuffers = meshBuffers;
+ RHI::ShaderInputBufferUnboundedArrayIndex bufferUnboundedArrayIndex = srgLayout->FindShaderInputBufferUnboundedArrayIndex(AZ::Name("m_meshBuffers"));
+ m_rayTracingSceneSrg->SetBufferViewUnboundedArray(bufferUnboundedArrayIndex, m_meshBuffers);
+ }
}
m_rayTracingSceneSrg->Compile();
@@ -554,8 +559,13 @@ namespace AZ
}
}
- RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures"));
- m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, materialTextures);
+ // Check if image view data changed from previous frame.
+ if (m_materialTextures.size() != materialTextures.size() || m_materialTextures != materialTextures)
+ {
+ m_materialTextures = materialTextures;
+ RHI::ShaderInputImageUnboundedArrayIndex textureUnboundedArrayIndex = srgLayout->FindShaderInputImageUnboundedArrayIndex(AZ::Name("m_materialTextures"));
+ m_rayTracingMaterialSrg->SetImageViewUnboundedArray(textureUnboundedArrayIndex, materialTextures);
+ }
}
m_rayTracingMaterialSrg->Compile();
diff --git a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h
index 52bb67f547..c0ebd6a4e7 100644
--- a/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h
+++ b/Gems/Atom/Feature/Common/Code/Source/RayTracing/RayTracingFeatureProcessor.h
@@ -281,6 +281,10 @@ namespace AZ
using BlasInstanceMap = AZStd::unordered_map;
BlasInstanceMap m_blasInstanceMap;
+
+ // Cache view pointers so we dont need to update them if none changed from frame to frame.
+ AZStd::vector m_meshBuffers;
+ AZStd::vector m_materialTextures;
};
}
}
diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h
index cbb0db53c8..ef4e734c01 100644
--- a/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h
+++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/ShaderResourceGroupData.h
@@ -183,6 +183,42 @@ namespace AZ
//! Returns the shader resource layout for this group.
const ShaderResourceGroupLayout* GetLayout() const;
+ enum class ResourceType : uint32_t
+ {
+ ConstantData,
+ BufferView,
+ ImageView,
+ BufferViewUnboundedArray,
+ ImageViewUnboundedArray,
+ Sampler,
+ Count
+ };
+
+ enum class ResourceTypeMask : uint32_t
+ {
+ None = 0,
+ ConstantDataMask = AZ_BIT(static_cast(ResourceType::ConstantData)),
+ BufferViewMask = AZ_BIT(static_cast(ResourceType::BufferView)),
+ ImageViewMask = AZ_BIT(static_cast(ResourceType::ImageView)),
+ BufferViewUnboundedArrayMask = AZ_BIT(static_cast(ResourceType::BufferViewUnboundedArray)),
+ ImageViewUnboundedArrayMask = AZ_BIT(static_cast(ResourceType::ImageViewUnboundedArray)),
+ SamplerMask = AZ_BIT(static_cast(ResourceType::Sampler))
+ };
+
+ //! Returns true if a resource type specified by resourceTypeMask is enabled for compilation
+ bool IsResourceTypeEnabledForCompilation(uint32_t resourceTypeMask) const;
+
+ //! Disables all resource types for compilation after m_updateMaskResetLatency number of compiles
+ //! This allows higher level code to ensure that if SRG is multi-buffered it can compile multiple
+ //! times in order to ensure all SRG buffers are updated.
+ void DisableCompilationForAllResourceTypes();
+
+ //! Returns true if any of the resource type has been enabled for compilation.
+ bool IsAnyResourceTypeUpdated() const;
+
+ //! Enable compilation for a resourceType specified by resourceType/resourceTypeMask
+ void EnableResourceTypeCompilation(ResourceTypeMask resourceTypeMask, ResourceType resourceType);
+
private:
static const ConstPtr s_nullImageView;
static const ConstPtr s_nullBufferView;
@@ -207,23 +243,43 @@ namespace AZ
//! The backing data store of constants for the shader resource group.
ConstantsData m_constantsData;
+
+ //! Mask used to check whether to compile a specific resource type
+ uint32_t m_updateMask = 0;
+
+ //! Track iteration for each resource type in order to keep compiling it for m_updateMaskResetLatency number of times
+ uint32_t m_resourceTypeIteration[static_cast(ResourceType::Count)] = { 0 };
+ uint32_t m_updateMaskResetLatency = RHI::Limits::Device::FrameCountMax;
};
template
bool ShaderResourceGroupData::SetConstant(ShaderInputConstantIndex inputIndex, const T& value)
{
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
return m_constantsData.SetConstant(inputIndex, value);
}
template
bool ShaderResourceGroupData::SetConstant(ShaderInputConstantIndex inputIndex, const T& value, uint32_t arrayIndex)
{
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
return m_constantsData.SetConstant(inputIndex, value, arrayIndex);
}
+
+ template
+ bool ShaderResourceGroupData::SetConstantMatrixRows(ShaderInputConstantIndex inputIndex, const T& value, uint32_t rowCount)
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
+ return m_constantsData.SetConstantMatrixRows(inputIndex, value, rowCount);
+ }
template
bool ShaderResourceGroupData::SetConstantArray(ShaderInputConstantIndex inputIndex, AZStd::array_view values)
{
+ if (!values.empty())
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
+ }
return m_constantsData.SetConstantArray(inputIndex, values);
}
@@ -245,12 +301,6 @@ namespace AZ
return m_constantsData.GetConstant(inputIndex, arrayIndex);
}
- template
- bool ShaderResourceGroupData::SetConstantMatrixRows(ShaderInputConstantIndex inputIndex, const T& value, uint32_t rowCount)
- {
- return m_constantsData.SetConstantMatrixRows(inputIndex, value, rowCount);
- }
-
template
bool ShaderResourceGroupData::ValidateImageViewAccess(TShaderInput inputIndex, const ImageView* imageView, [[maybe_unused]] uint32_t arrayIndex) const
{
diff --git a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp
index 18b292ac64..eed14b41b7 100644
--- a/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp
+++ b/Gems/Atom/RHI/Code/Source/RHI/ShaderResourceGroupData.cpp
@@ -7,6 +7,7 @@
*/
#include
#include
+#include
namespace AZ
{
@@ -126,6 +127,12 @@ namespace AZ
}
isValidAll &= isValid;
}
+
+ if(!imageViews.empty())
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::ImageViewMask, ResourceType::ImageView);
+ }
+
return isValidAll;
}
return false;
@@ -146,6 +153,11 @@ namespace AZ
}
isValidAll &= isValid;
}
+
+ if (!imageViews.empty())
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::ImageViewUnboundedArrayMask, ResourceType::ImageViewUnboundedArray);
+ }
return isValidAll;
}
return false;
@@ -172,6 +184,11 @@ namespace AZ
}
isValidAll &= isValid;
}
+
+ if (!bufferViews.empty())
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::BufferViewMask, ResourceType::BufferView);
+ }
return isValidAll;
}
return false;
@@ -192,6 +209,11 @@ namespace AZ
}
isValidAll &= isValid;
}
+
+ if (!bufferViews.empty())
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::BufferViewUnboundedArrayMask, ResourceType::BufferViewUnboundedArray);
+ }
return isValidAll;
}
return false;
@@ -211,6 +233,11 @@ namespace AZ
{
m_samplers[interval.m_min + arrayIndex + i] = samplers[i];
}
+
+ if (!samplers.empty())
+ {
+ EnableResourceTypeCompilation(ResourceTypeMask::SamplerMask, ResourceType::Sampler);
+ }
return true;
}
return false;
@@ -223,16 +250,19 @@ namespace AZ
bool ShaderResourceGroupData::SetConstantRaw(ShaderInputConstantIndex inputIndex, const void* bytes, uint32_t byteOffset, uint32_t byteCount)
{
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
return m_constantsData.SetConstantRaw(inputIndex, bytes, byteOffset, byteCount);
}
bool ShaderResourceGroupData::SetConstantData(const void* bytes, uint32_t byteCount)
{
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
return m_constantsData.SetConstantData(bytes, byteCount);
}
bool ShaderResourceGroupData::SetConstantData(const void* bytes, uint32_t byteOffset, uint32_t byteCount)
{
+ EnableResourceTypeCompilation(ResourceTypeMask::ConstantDataMask, ResourceType::ConstantData);
return m_constantsData.SetConstantData(bytes, byteOffset, byteCount);
}
@@ -348,5 +378,33 @@ namespace AZ
return m_constantsData;
}
+ bool ShaderResourceGroupData::IsResourceTypeEnabledForCompilation(uint32_t resourceTypeMask) const
+ {
+ return RHI::CheckBitsAny(m_updateMask, resourceTypeMask);
+ }
+
+ bool ShaderResourceGroupData::IsAnyResourceTypeUpdated() const
+ {
+ return m_updateMask != 0;
+ }
+
+ void ShaderResourceGroupData::EnableResourceTypeCompilation(ResourceTypeMask resourceTypeMask, ResourceType resourceType)
+ {
+ AZ_Assert(static_cast(resourceTypeMask) == AZ_BIT(static_cast(resourceType)), "resourceType and resourceTypeMask should point to the same ResourceType");
+ m_updateMask = RHI::SetBits(m_updateMask, static_cast(resourceTypeMask));
+ m_resourceTypeIteration[static_cast(resourceType)] = 0;
+ }
+
+ void ShaderResourceGroupData::DisableCompilationForAllResourceTypes()
+ {
+ for (uint32_t i = 0; i < static_cast(ResourceType::Count); i++)
+ {
+ if (m_resourceTypeIteration[i] == m_updateMaskResetLatency)
+ {
+ m_updateMask = RHI::ResetBits(m_updateMask, AZ_BIT(i));
+ }
+ m_resourceTypeIteration[i]++;
+ }
+ }
} // namespace RHI
} // namespace AZ
diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp
index bd648cf535..087a36dc2f 100644
--- a/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp
+++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/ShaderResourceGroupPool.cpp
@@ -206,12 +206,21 @@ namespace AZ
auto& device = static_cast(GetDevice());
group.m_compiledDataIndex = (group.m_compiledDataIndex + 1) % RHI::Limits::Device::FrameCountMax;
- if (m_constantBufferSize)
+ if (!groupData.IsAnyResourceTypeUpdated())
+ {
+ return RHI::ResultCode::Success;
+ }
+
+ if (m_constantBufferSize &&
+ groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
{
memcpy(group.GetCompiledData().m_cpuConstantAddress, groupData.GetConstantData().data(), groupData.GetConstantData().size());
}
- if (m_viewsDescriptorTableSize)
+ if (m_viewsDescriptorTableSize &&
+ groupData.IsResourceTypeEnabledForCompilation(
+ static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask) |
+ static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
{
//Lazy initialization for cbv/srv/uav Descriptor Tables
if (!group.m_viewsDescriptorTable.IsValid())
@@ -236,12 +245,17 @@ namespace AZ
UpdateViewsDescriptorTable(descriptorTable, groupData);
}
- if (m_unboundedArrayCount)
+ if (m_unboundedArrayCount &&
+ groupData.IsResourceTypeEnabledForCompilation(
+ static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask) |
+ static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask)))
{
UpdateUnboundedArrayDescriptorTables(group, groupData);
}
- if (m_samplersDescriptorTableSize)
+ if (m_samplersDescriptorTableSize &&
+ groupData.IsResourceTypeEnabledForCompilation(
+ static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
{
const DescriptorTable descriptorTable(
group.m_samplersDescriptorTable.GetOffset() + group.m_compiledDataIndex * m_samplersDescriptorTableSize,
diff --git a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp
index 6be5ec7259..0a9c001868 100644
--- a/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp
+++ b/Gems/Atom/RHI/Metal/Code/Source/RHI/ShaderResourceGroupPool.cpp
@@ -63,39 +63,58 @@ namespace AZ
{
ShaderResourceGroup& group = static_cast(groupBase);
group.UpdateCompiledDataIndex();
-
+
+ if (!groupData.IsAnyResourceTypeUpdated())
+ {
+ return RHI::ResultCode::Success;
+ }
+
ArgumentBuffer& argBuffer = *group.m_compiledArgBuffers[group.m_compiledDataIndex];
argBuffer.ClearResourceTracking();
- argBuffer.UpdateConstantBufferViews(groupData.GetConstantData());
-
+
+ auto constantData = groupData.GetConstantData();
+ if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
+ {
+ argBuffer.UpdateConstantBufferViews(groupData.GetConstantData());
+ }
+
const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout();
uint32_t shaderInputIndex = 0;
- for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages())
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask)))
{
- const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex);
- AZStd::array_view> imageViews = groupData.GetImageViewArray(imageInputIndex);
- argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews);
- ++shaderInputIndex;
+ for (const RHI::ShaderInputImageDescriptor& shaderInputImage : layout->GetShaderInputListForImages())
+ {
+ const RHI::ShaderInputImageIndex imageInputIndex(shaderInputIndex);
+ AZStd::array_view> imageViews = groupData.GetImageViewArray(imageInputIndex);
+ argBuffer.UpdateImageViews(shaderInputImage, imageInputIndex, imageViews);
+ ++shaderInputIndex;
+ }
}
-
- shaderInputIndex = 0;
- for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers())
+
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
{
- const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex);
- AZStd::array_view samplerStates= groupData.GetSamplerArray(samplerInputIndex);
- argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates);
- ++shaderInputIndex;
+ shaderInputIndex = 0;
+ for (const RHI::ShaderInputSamplerDescriptor& shaderInputSampler : layout->GetShaderInputListForSamplers())
+ {
+ const RHI::ShaderInputSamplerIndex samplerInputIndex(shaderInputIndex);
+ AZStd::array_view samplerStates = groupData.GetSamplerArray(samplerInputIndex);
+ argBuffer.UpdateSamplers(shaderInputSampler, samplerInputIndex, samplerStates);
+ ++shaderInputIndex;
+ }
}
-
- shaderInputIndex = 0;
- for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers())
+
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
{
- const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex);
- AZStd::array_view> bufferViews = groupData.GetBufferViewArray(bufferInputIndex);
- argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews);
- ++shaderInputIndex;
+ shaderInputIndex = 0;
+ for (const RHI::ShaderInputBufferDescriptor& shaderInputBuffer : layout->GetShaderInputListForBuffers())
+ {
+ const RHI::ShaderInputBufferIndex bufferInputIndex(shaderInputIndex);
+ AZStd::array_view> bufferViews = groupData.GetBufferViewArray(bufferInputIndex);
+ argBuffer.UpdateBufferViews(shaderInputBuffer, bufferInputIndex, bufferViews);
+ ++shaderInputIndex;
+ }
}
-
+
return RHI::ResultCode::Success;
}
diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp
index c5ca07eb27..59dbaf4377 100644
--- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp
+++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/ShaderResourceGroupPool.cpp
@@ -105,66 +105,87 @@ namespace AZ
{
auto& group = static_cast(groupBase);
group.UpdateCompiledDataIndex(m_currentIteration);
+
+ if (!groupData.IsAnyResourceTypeUpdated())
+ {
+ return RHI::ResultCode::Success;
+ }
+
DescriptorSet& descriptorSet = *group.m_compiledData[group.GetCompileDataIndex()];
const RHI::ShaderResourceGroupLayout* layout = groupData.GetLayout();
- for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex)
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewMask)))
{
- const RHI::ShaderInputBufferIndex index(groupIndex);
- auto bufViews = groupData.GetBufferViewArray(index);
- uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView);
- descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
- }
-
- auto const& shaderImageList = layout->GetShaderInputListForImages();
- for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImages().size()); ++groupIndex)
- {
- const RHI::ShaderInputImageIndex index(groupIndex);
- auto imgViews = groupData.GetImageViewArray(index);
- uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView);
- descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type);
- }
-
- for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex)
- {
- const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex);
- auto bufViews = groupData.GetBufferViewUnboundedArray(index);
- if (bufViews.empty())
+ for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBuffers().size()); ++groupIndex)
{
- // skip empty unbounded arrays
- continue;
+ const RHI::ShaderInputBufferIndex index(groupIndex);
+ auto bufViews = groupData.GetBufferViewArray(index);
+ uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferView);
+ descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
}
-
- uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray);
- descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
}
- auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays();
- for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImageUnboundedArrays().size()); ++groupIndex)
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewMask)))
{
- const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex);
- auto imgViews = groupData.GetImageViewUnboundedArray(index);
- if (imgViews.empty())
+ auto const& shaderImageList = layout->GetShaderInputListForImages();
+ for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImages().size()); ++groupIndex)
{
- // skip empty unbounded arrays
- continue;
+ const RHI::ShaderInputImageIndex index(groupIndex);
+ auto imgViews = groupData.GetImageViewArray(index);
+ uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageView);
+ descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageList[groupIndex].m_type);
}
-
- uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray);
- descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type);
}
- for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex)
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::BufferViewUnboundedArrayMask)))
{
- const RHI::ShaderInputSamplerIndex index(groupIndex);
- auto samplerArray = groupData.GetSamplerArray(index);
- uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler);
- descriptorSet.UpdateSamplers(layoutIndex, samplerArray);
+ for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForBufferUnboundedArrays().size()); ++groupIndex)
+ {
+ const RHI::ShaderInputBufferUnboundedArrayIndex index(groupIndex);
+ auto bufViews = groupData.GetBufferViewUnboundedArray(index);
+ if (bufViews.empty())
+ {
+ // skip empty unbounded arrays
+ continue;
+ }
+
+ uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::BufferViewUnboundedArray);
+ descriptorSet.UpdateBufferViews(layoutIndex, bufViews);
+ }
+ }
+
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ImageViewUnboundedArrayMask)))
+ {
+ auto const& shaderImageUnboundeArrayList = layout->GetShaderInputListForImageUnboundedArrays();
+ for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForImageUnboundedArrays().size()); ++groupIndex)
+ {
+ const RHI::ShaderInputImageUnboundedArrayIndex index(groupIndex);
+ auto imgViews = groupData.GetImageViewUnboundedArray(index);
+ if (imgViews.empty())
+ {
+ // skip empty unbounded arrays
+ continue;
+ }
+
+ uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::ImageViewUnboundedArray);
+ descriptorSet.UpdateImageViews(layoutIndex, imgViews, shaderImageUnboundeArrayList[groupIndex].m_type);
+ }
+ }
+
+ if (groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::SamplerMask)))
+ {
+ for (uint32_t groupIndex = 0; groupIndex < static_cast(layout->GetShaderInputListForSamplers().size()); ++groupIndex)
+ {
+ const RHI::ShaderInputSamplerIndex index(groupIndex);
+ auto samplerArray = groupData.GetSamplerArray(index);
+ uint32_t layoutIndex = m_descriptorSetLayout->GetLayoutIndexFromGroupIndex(groupIndex, DescriptorSetLayout::ResourceType::Sampler);
+ descriptorSet.UpdateSamplers(layoutIndex, samplerArray);
+ }
}
auto constantData = groupData.GetConstantData();
- if (!constantData.empty())
+ if (!constantData.empty() && groupData.IsResourceTypeEnabledForCompilation(static_cast(RHI::ShaderResourceGroupData::ResourceTypeMask::ConstantDataMask)))
{
descriptorSet.UpdateConstantData(constantData);
}
diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h
index 90389687de..fcf812cc38 100644
--- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h
+++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/RenderPipeline.h
@@ -228,9 +228,6 @@ namespace AZ
PipelineViewMap m_pipelineViewsByTag;
- /// The system time when the last time this pipeline render was started
- float m_lastRenderStartTime = 0;
-
// RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene
RenderPipelineId m_nameId;
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp
index 5df1c655d6..eb74a81e3e 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RPISystem.cpp
@@ -263,7 +263,7 @@ namespace AZ
AZ::TickRequestBus::BroadcastResult(m_tickTime.m_gameDeltaTime, &AZ::TickRequestBus::Events::GetTickDeltaTime);
ScriptTimePoint currentTime;
AZ::TickRequestBus::BroadcastResult(currentTime, &AZ::TickRequestBus::Events::GetTimeAtCurrentTick);
- m_tickTime.m_currentGameTime = static_cast(currentTime.GetMilliseconds());
+ m_tickTime.m_currentGameTime = static_cast(currentTime.GetSeconds());
}
void RPISystem::RenderTick()
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp
index 1b99abae4e..6378a249a4 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/RenderPipeline.cpp
@@ -375,12 +375,10 @@ namespace AZ
m_scene->RemoveRenderPipeline(m_nameId);
}
- void RenderPipeline::OnStartFrame(const TickTimeInfo& tick)
+ void RenderPipeline::OnStartFrame([[maybe_unused]] const TickTimeInfo& tick)
{
AZ_PROFILE_SCOPE(RPI, "RenderPipeline: OnStartFrame");
- m_lastRenderStartTime = tick.m_currentGameTime;
-
OnPassModified();
for (auto& viewItr : m_pipelineViewsByTag)
diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp
index f95c6abfcd..df16b5cd08 100644
--- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp
+++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderResourceGroup.cpp
@@ -114,6 +114,10 @@ namespace AZ
void ShaderResourceGroup::Compile()
{
m_shaderResourceGroup->Compile(m_data);
+
+ //Disable compilation for all resource types as a performance optimization
+ //No need to re-update SRG data on GPU timeline if nothing was updated.
+ m_data.DisableCompilationForAllResourceTypes();
}
bool ShaderResourceGroup::IsQueuedForCompile() const
diff --git a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl
index 7be62c9343..2dbba46d8b 100644
--- a/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl
+++ b/Gems/Atom/TestData/TestData/Materials/Types/AutoBrick_ForwardPass.azsl
@@ -170,6 +170,7 @@ ForwardPassOutput AutoBrick_ForwardPassPS(VSOutput IN)
// Position, Normal, Roughness
surface.position = IN.m_worldPosition.xyz;
surface.normal = normalize(normal);
+ surface.vertexNormal = surfaceNormal;
surface.roughnessLinear = 1.0f;
surface.CalculateRoughnessA();
diff --git a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl
index 6f73b63ad7..2f6f038e4b 100644
--- a/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl
+++ b/Gems/Atom/TestData/TestData/Materials/Types/MinimalPBR_ForwardPass.azsl
@@ -63,6 +63,7 @@ ForwardPassOutput MinimalPBR_MainPassPS(VSOutput IN)
// Position, Normal, Roughness
surface.position = IN.m_worldPosition.xyz;
surface.normal = normalize(IN.m_normal);
+ surface.vertexNormal = normalize(IN.m_normal);
surface.roughnessLinear = MinimalPBRSrg::m_roughness;
surface.CalculateRoughnessA();
diff --git a/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli b/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli
index 535d1380e7..4b0fa654e3 100644
--- a/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli
+++ b/Gems/AtomTressFX/Assets/Shaders/HairLightTypes.azsli
@@ -135,6 +135,7 @@ void SetNormalAndUpdateLightingParams(
float3 projectedNormal = cross(biNormal, tangent);
surface.normal = normalize(projectedNormal); // the normalization might be redundunt
+ surface.vertexNormal = surface.normal; // [To Do] - support proper vertex normals in the hair shader.
// Next is important in order to set NdotV and other PBR settings - needs to be set once per light
UpdateLightingParameters(lightingData, surface.position, surface.normal, surface.roughnessLinear);
@@ -362,7 +363,7 @@ void ApplyDirectionalLights(Surface surface, inout LightingData lightingData)
litRatio = DirectionalLightShadow::GetVisibility(
shadowIndex,
lightingData.shadowCoords,
- surface.normal,
+ surface.vertexNormal,
debugInfo);
}
diff --git a/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli b/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli
index bf452e6ba8..dcdcf43243 100644
--- a/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli
+++ b/Gems/AtomTressFX/Assets/Shaders/HairLighting.azsli
@@ -197,6 +197,7 @@ float3 CalculateLighting(
surface.position = vPositionWS;
surface.tangent = vTangent; // Redundant - will be calculated per light
surface.normal = float3(0, 0, 0); // Will fail lights that did not initialize properly.
+ surface.vertexNormal = float3(0,0,0); // [To Do] - vertex normals are not handled yet in the hair shader.
surface.roughnessLinear = material.m_roughness;
surface.cuticleTilt = material.m_cuticleTilt;
surface.thickness = thickness;
diff --git a/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli b/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli
index 16496f0dcd..6ffd342734 100644
--- a/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli
+++ b/Gems/AtomTressFX/Assets/Shaders/HairSurface.azsli
@@ -18,6 +18,7 @@ class Surface
// ------- BasePbrSurfaceData -------
float3 position; //!< Position in world-space
float3 normal; //!< Normal in world-space
+ float3 vertexNormal; //!< Vertex normal in world-space
float3 albedo; //!< Albedo color of the non-metallic material, will be multiplied against the diffuse lighting value
float3 specularF0; //!< Fresnel f0 spectral value of the surface
float roughnessLinear; //!< Perceptually linear roughness value authored by artists. Must be remapped to roughnessA before use
diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp
new file mode 100644
index 0000000000..6313d6ec17
--- /dev/null
+++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.cpp
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include
+
+#include
+
+namespace GraphCanvas
+{
+ namespace Styling
+ {
+
+ StyleHelper::StyleHelper(const AZ::EntityId& styledEntity)
+ {
+ SetStyle(styledEntity);
+ }
+
+ StyleHelper::StyleHelper(const AZ::EntityId& realStyledEntity, const AZStd::string& virtualChildElement)
+ {
+ SetStyle(realStyledEntity, virtualChildElement);
+ }
+
+ StyleHelper::~StyleHelper()
+ {
+ ReleaseStyle();
+ }
+
+ void StyleHelper::OnStylesUnloaded()
+ {
+ ReleaseStyle();
+ }
+
+ void StyleHelper::SetEditorId(const EditorId& editorId)
+ {
+ if (m_editorId != editorId)
+ {
+ ReleaseStyle();
+ m_editorId = editorId;
+
+ RegisterStyleSheetBus(m_editorId);
+ }
+ }
+
+ void StyleHelper::SetScene(const AZ::EntityId& sceneId)
+ {
+ m_scene = sceneId;
+
+ EditorId editorId;
+ SceneRequestBus::EventResult(editorId, m_scene, &SceneRequests::GetEditorId);
+ SetEditorId(editorId);
+ }
+
+ void StyleHelper::SetStyle(const AZ::EntityId& styledEntity)
+ {
+ ReleaseStyle();
+
+ m_styledEntity = styledEntity;
+
+ AZ::EntityId sceneId;
+ SceneMemberRequestBus::EventResult(sceneId, m_styledEntity, &SceneMemberRequests::GetScene);
+ if (!sceneId.IsValid())
+ {
+ return;
+ }
+
+ SetScene(sceneId);
+
+ for (const auto& selector : m_styleSelectors)
+ {
+ StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str());
+ }
+
+ UpdateStyle();
+ }
+
+ void StyleHelper::SetStyle(const AZStd::string& style)
+ {
+ ReleaseStyle();
+
+ m_deleteStyledEntity = true;
+
+ PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateStyleEntity, style);
+
+ for (const auto& selector : m_styleSelectors)
+ {
+ StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str());
+ }
+
+ // TODO: remove/replace OnSceneSet and fix any systems/components listening for that event.
+ SceneMemberNotificationBus::Event(m_styledEntity, &SceneMemberNotifications::OnSceneSet, m_scene);
+
+ UpdateStyle();
+
+ static bool enableDiagnostic = false;
+ if (enableDiagnostic)
+ {
+ AZStd::string description;
+ StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription);
+ qDebug() << description.c_str();
+ }
+ }
+
+ void StyleHelper::SetStyle(const AZ::EntityId& parentStyledEntity, const AZStd::string& virtualChildElement)
+ {
+ ReleaseStyle();
+
+ m_deleteStyledEntity = true;
+
+ AZ::EntityId sceneId;
+ SceneMemberRequestBus::EventResult(sceneId, parentStyledEntity, &SceneMemberRequests::GetScene);
+
+ SetScene(sceneId);
+
+ PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateVirtualChild, parentStyledEntity, virtualChildElement);
+
+ for (const auto& selector : m_styleSelectors)
+ {
+ StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str());
+ }
+
+ UpdateStyle();
+
+ static bool enableDiagnostic = false;
+ if (enableDiagnostic)
+ {
+ AZStd::string description;
+ StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription);
+ qDebug() << description.c_str();
+ }
+
+ }
+
+ void StyleHelper::RemoveAttributeOverride(Styling::Attribute attribute)
+ {
+ m_attributeOverride.erase(attribute);
+ }
+
+ bool StyleHelper::HasAttribute(Styling::Attribute attribute) const
+ {
+ bool hasAttribute = (m_attributeOverride.find(attribute) != m_attributeOverride.end());
+
+ if (!hasAttribute)
+ {
+ StyleRequestBus::EventResult(hasAttribute, m_style, &StyleRequests::HasAttribute, static_cast(attribute));
+ }
+
+ return hasAttribute;
+ }
+
+ QColor StyleHelper::GetColor(Styling::Attribute color, QColor defaultValue /*= QColor()*/) const
+ {
+ return GetAttribute(color, defaultValue);
+ }
+
+ QFont StyleHelper::GetFont() const
+ {
+ QFont font;
+ QFontInfo info(font);
+ info.pixelSize();
+
+ font.setFamily(GetAttribute(Attribute::FontFamily, font.family()));
+ font.setPixelSize(GetAttribute(Attribute::FontSize, info.pixelSize()));
+ font.setWeight(GetAttribute(Attribute::FontWeight, font.weight()));
+ font.setStyle(GetAttribute(Attribute::FontStyle, font.style()));
+ font.setCapitalization(GetAttribute(Attribute::FontVariant, font.capitalization()));
+
+ return font;
+ }
+
+ QString StyleHelper::GetFontStyleSheet() const
+ {
+ QFont font = GetFont();
+ QColor color = GetColor(Styling::Attribute::Color);
+
+ QStringList fields;
+
+ fields.push_back(QString("color: rgba(%1,%2,%3,%4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()));
+
+ fields.push_back(QString("font-family: %1").arg(font.family()));
+ fields.push_back(QString("font-size: %1px").arg(font.pixelSize()));
+
+ if (font.bold())
+ {
+ fields.push_back("font-weight: bold");
+ }
+
+ switch (font.style())
+ {
+ case QFont::StyleNormal:
+ break;
+ case QFont::StyleItalic:
+ fields.push_back("font-style: italic");
+ break;
+ case QFont::StyleOblique:
+ fields.push_back("font-style: italic");
+ break;
+ }
+
+ const bool underline = font.underline();
+ const bool strikeOut = font.strikeOut();
+
+ if (underline && strikeOut)
+ {
+ fields.push_back("text-decoration: underline line-through");
+ }
+ else if (underline)
+ {
+ fields.push_back("text-decoration: underline");
+ }
+ else if (strikeOut)
+ {
+ fields.push_back("text-decoration: line-through");
+ }
+
+ return fields.join("; ");
+ }
+
+ QPen StyleHelper::GetPen(Styling::Attribute width, Styling::Attribute style, Styling::Attribute color, Styling::Attribute cap, bool cosmetic /*= false*/) const
+ {
+ QPen pen;
+ pen.setColor(GetAttribute(color, QColor(Qt::black)));
+ pen.setWidth(GetAttribute(width, 1));
+ pen.setStyle(GetAttribute(style, Qt::SolidLine));
+ pen.setCapStyle(GetAttribute(cap, Qt::SquareCap));
+ pen.setCosmetic(cosmetic);
+
+ return pen;
+ }
+
+ QPen StyleHelper::GetBorder() const
+ {
+ return GetPen(Styling::Attribute::BorderWidth, Styling::Attribute::BorderStyle, Styling::Attribute::BorderColor, Styling::Attribute::CapStyle);
+ }
+
+ QBrush StyleHelper::GetBrush(Styling::Attribute color, QBrush defaultValue /*= QBrush()*/) const
+ {
+ return GetAttribute(color, defaultValue);
+ }
+
+ QSizeF StyleHelper::GetSize(QSizeF defaultSize) const
+ {
+ return{
+ GetAttribute(Styling::Attribute::Width, defaultSize.width()),
+ GetAttribute(Styling::Attribute::Height, defaultSize.height())
+ };
+ }
+
+ QSizeF StyleHelper::GetMinimumSize(QSizeF defaultSize /*= QSizeF(0,0)*/) const
+ {
+ return QSizeF(GetAttribute(Styling::Attribute::MinWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MinHeight, defaultSize.height()));
+ }
+
+ QSizeF StyleHelper::GetMaximumSize(QSizeF defaultSize /*= QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)*/) const
+ {
+ return QSizeF(GetAttribute(Styling::Attribute::MaxWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MaxHeight, defaultSize.height()));
+ }
+
+ QMarginsF StyleHelper::GetMargins(QMarginsF defaultMargins /*= QMarginsF()*/) const
+ {
+ bool hasMargin = false;
+ StyleRequestBus::EventResult(hasMargin, m_style, &StyleRequests::HasAttribute, static_cast(Styling::Attribute::Margin));
+
+ if (hasMargin)
+ {
+ qreal defaultMargin = GetAttribute(Styling::Attribute::Margin, 0);
+ defaultMargins = QMarginsF(defaultMargin, defaultMargin, defaultMargin, defaultMargin);
+ }
+
+ return QMarginsF(
+ GetAttribute(Styling::Attribute::Margin/*TODO Left*/, defaultMargins.left()),
+ GetAttribute(Styling::Attribute::Margin/*TODO Top*/, defaultMargins.top()),
+ GetAttribute(Styling::Attribute::Margin/*TODO Right*/, defaultMargins.right()),
+ GetAttribute(Styling::Attribute::Margin/*TODO Bottom*/, defaultMargins.bottom())
+ );
+ }
+
+ bool StyleHelper::HasTextAlignment() const
+ {
+ return HasAttribute(Styling::Attribute::TextAlignment) || HasAttribute(Styling::Attribute::TextVerticalAlignment);
+ }
+
+ Qt::Alignment StyleHelper::GetTextAlignment(Qt::Alignment defaultAlignment) const
+ {
+ bool horizontalAlignment = HasAttribute(Styling::Attribute::TextAlignment);
+ bool verticalAlignment = HasAttribute(Styling::Attribute::TextVerticalAlignment);
+
+ if (horizontalAlignment || verticalAlignment)
+ {
+ Qt::Alignment alignment = GetAttribute(Styling::Attribute::TextAlignment, Qt::AlignmentFlag::AlignLeft);
+ alignment = alignment | GetAttribute(Styling::Attribute::TextVerticalAlignment, Qt::AlignmentFlag::AlignTop);
+
+ return alignment;
+ }
+
+ return defaultAlignment;
+ }
+
+ void StyleHelper::AddSelector(const AZStd::string_view& selector)
+ {
+ auto insertResult = m_styleSelectors.insert(AZStd::string(selector));
+
+ if (insertResult.second && m_styledEntity.IsValid())
+ {
+ StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.data());
+
+ UpdateStyle();
+ }
+ }
+
+ void StyleHelper::RemoveSelector(const AZStd::string_view& selector)
+ {
+ AZStd::size_t elements = m_styleSelectors.erase(selector);
+
+ if (elements > 0)
+ {
+ StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::RemoveSelectorState, selector.data());
+
+ UpdateStyle();
+ }
+ }
+
+ GraphCanvas::CandyStripeConfiguration StyleHelper::GetCandyStripeConfiguration() const
+ {
+ CandyStripeConfiguration config;
+
+ config.m_initialOffset = GetAttribute(Styling::Attribute::StripeOffset, 0);
+ config.m_maximumSize = GetAttribute(Styling::Attribute::MaximumStripeSize, 10);
+
+ if (config.m_maximumSize <= 0)
+ {
+ config.m_maximumSize = 1;
+ }
+
+ config.m_minStripes = GetAttribute(Styling::Attribute::MinimumStripes, 2);
+
+ if (config.m_minStripes <= 0)
+ {
+ config.m_minStripes = 1;
+ }
+
+ config.m_stripeAngle = GetAttribute(Styling::Attribute::StripeAngle, 60);
+
+ if (config.m_stripeAngle > 90)
+ {
+ config.m_stripeAngle = 89;
+ }
+ else if (config.m_stripeAngle < -90)
+ {
+ config.m_stripeAngle = -89;
+ }
+
+ if (!HasAttribute(Styling::Attribute::StripeColor))
+ {
+ QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0, 0, 0));
+
+ config.m_stripeColor = backgroundColor.darker();
+
+ int totalDifference = 0;
+
+ totalDifference += backgroundColor.red() - config.m_stripeColor.red();
+ totalDifference += backgroundColor.green() - config.m_stripeColor.green();
+ totalDifference += backgroundColor.blue() - config.m_stripeColor.blue();
+
+ if (totalDifference < 150)
+ {
+ config.m_stripeColor = backgroundColor.lighter();
+ }
+ }
+ else
+ {
+ config.m_stripeColor = GetAttribute(Styling::Attribute::StripeColor, QColor(0, 0, 0));
+ }
+
+ return config;
+ }
+
+ GraphCanvas::PatternedFillGenerator StyleHelper::GetPatternedFillGenerator() const
+ {
+ PatternedFillGenerator generator;
+ generator.m_editorId = m_editorId;
+
+ generator.m_id = GetAttribute(Styling::Attribute::PatternTemplate, QString()).toUtf8().data();
+
+ if (HasAttribute(Styling::Attribute::PatternPalettes))
+ {
+ AZStd::string paletteStrings = GetAttribute(Styling::Attribute::PatternPalettes, QString()).toUtf8().data();
+
+ AzFramework::StringFunc::Tokenize(paletteStrings.c_str(), generator.m_palettes, ',');
+ }
+ else
+ {
+ QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0, 0, 0));
+
+ QColor patternColor = backgroundColor.darker();
+
+ int totalDifference = 0;
+
+ totalDifference += backgroundColor.red() - patternColor.red();
+ totalDifference += backgroundColor.green() - patternColor.green();
+ totalDifference += backgroundColor.blue() - patternColor.blue();
+
+ if (totalDifference < 150)
+ {
+ patternColor = backgroundColor.lighter();
+ }
+
+ generator.m_colors.push_back(patternColor);
+ }
+
+ generator.m_configuration = GetPatternFillConfiguration();
+
+ return generator;
+ }
+
+ GraphCanvas::PatternFillConfiguration StyleHelper::GetPatternFillConfiguration() const
+ {
+ PatternFillConfiguration configuration;
+
+ configuration.m_minimumTileRepetitions = GetAttribute(Styling::Attribute::MinimumRepetitions, 1);
+ configuration.m_evenRowOffsetPercent = GetAttribute(Styling::Attribute::EvenOffsetPercent, 0.0f);
+ configuration.m_oddRowOffsetPercent = GetAttribute(Styling::Attribute::OddOffsetPercent, 0.0f);
+
+ return configuration;
+ }
+
+ void StyleHelper::PopulatePaletteConfiguration(PaletteIconConfiguration& configuration) const
+ {
+ AZStd::string stylePalette;
+ StyledEntityRequestBus::EventResult(stylePalette, m_styledEntity, &StyledEntityRequests::GetFullStyleElement);
+
+ if (!stylePalette.empty())
+ {
+ configuration.SetColorPalette(stylePalette);
+ }
+ }
+
+ void StyleHelper::UpdateStyle()
+ {
+ ReleaseStyle(false);
+ StyleManagerRequestBus::EventResult(m_style, m_editorId, &StyleManagerRequests::ResolveStyles, m_styledEntity);
+ }
+
+ void StyleHelper::ReleaseStyle(bool destroyChildElement /*= true*/)
+ {
+ if (m_style.IsValid())
+ {
+ if (m_deleteStyledEntity && destroyChildElement)
+ {
+ m_deleteStyledEntity = false;
+ AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_styledEntity);
+ }
+ AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_style);
+
+ m_style.SetInvalid();
+ }
+ }
+
+ void StyleHelper::RegisterStyleSheetBus(const EditorId& editorId)
+ {
+ StyleManagerNotificationBus::Handler::BusDisconnect();
+ StyleManagerNotificationBus::Handler::BusConnect(editorId);
+ }
+
+}
+}
diff --git a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h
index cc7429f8fc..b500d4b197 100644
--- a/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h
+++ b/Gems/GraphCanvas/Code/StaticLib/GraphCanvas/Styling/StyleHelper.h
@@ -8,7 +8,8 @@
#pragma once
-AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
+#if !defined(Q_MOC_RUN)
+
#include
#include
#include
@@ -16,7 +17,6 @@ AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
#include
#include
#include
-AZ_POP_DISABLE_WARNING
#include
#include
@@ -32,6 +32,8 @@ AZ_POP_DISABLE_WARNING
#include
#include
+#endif
+
namespace GraphCanvas
{
namespace Styling
@@ -45,124 +47,49 @@ namespace GraphCanvas
AZ_CLASS_ALLOCATOR(StyleHelper, AZ::SystemAllocator, 0);
StyleHelper() = default;
-
- StyleHelper(const AZ::EntityId& styledEntity)
- {
- SetStyle(styledEntity);
- }
-
- StyleHelper(const AZ::EntityId& realStyledEntity, const AZStd::string& virtualChildElement)
- {
- SetStyle(realStyledEntity, virtualChildElement);
- }
-
- virtual ~StyleHelper()
- {
- ReleaseStyle();
- }
+ StyleHelper(const AZ::EntityId& styledEntity);
+ StyleHelper(const AZ::EntityId& realStyledEntity, const AZStd::string& virtualChildElement);
+ virtual ~StyleHelper();
// StyleManagerNotificationBus
- void OnStylesUnloaded() override
- {
- ReleaseStyle();
- }
+ void OnStylesUnloaded() override;
////
- void SetEditorId(const EditorId& editorId)
- {
- if (m_editorId != editorId)
- {
- ReleaseStyle();
- m_editorId = editorId;
+ void SetEditorId(const EditorId& editorId);
+ void SetScene(const AZ::EntityId& sceneId);
- RegisterStyleSheetBus(m_editorId);
- }
- }
+ void SetStyle(const AZStd::string& style);
+ void SetStyle(const AZ::EntityId& styledEntity);
+ void SetStyle(const AZ::EntityId& parentStyledEntity, const AZStd::string& virtualChildElement);
- // TODO: Get rid of this and m_scene once the OnSceneSet notification is removed (see below).
- void SetScene(const AZ::EntityId& sceneId)
- {
- m_scene = sceneId;
+ bool HasAttribute(Styling::Attribute attribute) const;
+ void RemoveAttributeOverride(Styling::Attribute attribute);
- EditorId editorId;
- SceneRequestBus::EventResult(editorId, m_scene, &SceneRequests::GetEditorId);
- SetEditorId(editorId);
- }
+ QColor GetColor(Styling::Attribute color, QColor defaultValue = QColor()) const;
+ QFont GetFont() const;
- void SetStyle(const AZ::EntityId& styledEntity)
- {
- ReleaseStyle();
+ //! Helper method which constructs a stylesheet based on the calculated font style.
+ //! We need this too pass along to certain Qt widgets because we use our own custom style parsing system.
+ QString GetFontStyleSheet() const;
- m_styledEntity = styledEntity;
+ QPen GetPen(Styling::Attribute width, Styling::Attribute style, Styling::Attribute color, Styling::Attribute cap, bool cosmetic = false) const;
+ QPen GetBorder() const;
+ QBrush GetBrush(Styling::Attribute color, QBrush defaultValue = QBrush()) const;
+ QSizeF GetSize(QSizeF defaultSize) const;
+ QSizeF GetMinimumSize(QSizeF defaultSize = QSizeF(0,0)) const;
+ QSizeF GetMaximumSize(QSizeF defaultSize = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) const;
+ QMarginsF GetMargins(QMarginsF defaultMargins = QMarginsF()) const;
- AZ::EntityId sceneId;
- SceneMemberRequestBus::EventResult(sceneId, m_styledEntity, &SceneMemberRequests::GetScene);
- if (!sceneId.IsValid())
- {
- return;
- }
+ bool HasTextAlignment() const;
+ Qt::Alignment GetTextAlignment(Qt::Alignment defaultAlignment) const;
- SetScene(sceneId);
+ void AddSelector(const AZStd::string_view& selector);
+ void RemoveSelector(const AZStd::string_view& selector);
- for (const auto& selector : m_styleSelectors)
- {
- StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str());
- }
-
- UpdateStyle();
-
-#if 0
- AZStd::string description;
- StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription);
- qDebug() << description.c_str();
-#endif
- }
-
- void SetStyle(const AZStd::string& style)
- {
- ReleaseStyle();
-
- m_deleteStyledEntity = true;
-
- PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateStyleEntity, style);
-
- for (const auto& selector : m_styleSelectors)
- {
- StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str());
- }
-
- // TODO: remove/replace OnSceneSet and fix any systems/components listening for that event.
- SceneMemberNotificationBus::Event(m_styledEntity, &SceneMemberNotifications::OnSceneSet, m_scene);
-
- UpdateStyle();
- }
-
- void SetStyle(const AZ::EntityId& parentStyledEntity, const AZStd::string& virtualChildElement)
- {
- ReleaseStyle();
-
- m_deleteStyledEntity = true;
-
- AZ::EntityId sceneId;
- SceneMemberRequestBus::EventResult(sceneId, parentStyledEntity, &SceneMemberRequests::GetScene);
-
- SetScene(sceneId);
-
- PseudoElementFactoryRequestBus::BroadcastResult(m_styledEntity, &PseudoElementFactoryRequests::CreateVirtualChild, parentStyledEntity, virtualChildElement);
-
- for (const auto& selector : m_styleSelectors)
- {
- StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.c_str());
- }
-
- UpdateStyle();
-
-#if 0
- AZStd::string description;
- StyleRequestBus::EventResult(description, m_style, &StyleRequests::GetDescription);
- qDebug() << description.c_str();
-#endif
- }
+ CandyStripeConfiguration GetCandyStripeConfiguration() const;
+ PatternedFillGenerator GetPatternedFillGenerator() const;
+ PatternFillConfiguration GetPatternFillConfiguration() const;
+ void PopulatePaletteConfiguration(PaletteIconConfiguration& configuration) const;
template
void AddAttributeOverride(Styling::Attribute attribute, const Value& defaultValue = Value())
@@ -170,23 +97,6 @@ namespace GraphCanvas
m_attributeOverride[attribute] = QVariant(defaultValue);
}
- void RemoveAttributeOverride(Styling::Attribute attribute)
- {
- m_attributeOverride.erase(attribute);
- }
-
- bool HasAttribute(Styling::Attribute attribute) const
- {
- bool hasAttribute = (m_attributeOverride.find(attribute) != m_attributeOverride.end());
-
- if (!hasAttribute)
- {
- StyleRequestBus::EventResult(hasAttribute, m_style, &StyleRequests::HasAttribute, static_cast(attribute));
- }
-
- return hasAttribute;
- }
-
template
Value GetAttribute(Styling::Attribute attribute, const Value& defaultValue = Value()) const
{
@@ -202,7 +112,7 @@ namespace GraphCanvas
{
bool hasAttribute = false;
auto rawAttribute = static_cast(attribute);
-
+
StyleRequestBus::EventResult(hasAttribute, m_style, &StyleRequests::HasAttribute, rawAttribute);
if (hasAttribute)
@@ -217,323 +127,11 @@ namespace GraphCanvas
return retVal;
}
- QColor GetColor(Styling::Attribute color, QColor defaultValue = QColor()) const
- {
- return GetAttribute(color, defaultValue);
- }
-
- QFont GetFont() const
- {
- QFont font;
- QFontInfo info(font);
- info.pixelSize();
-
- font.setFamily(GetAttribute(Attribute::FontFamily, font.family()));
- font.setPixelSize(GetAttribute(Attribute::FontSize, info.pixelSize()));
- font.setWeight(GetAttribute(Attribute::FontWeight, font.weight()));
- font.setStyle(GetAttribute(Attribute::FontStyle, font.style()));
- font.setCapitalization(GetAttribute(Attribute::FontVariant, font.capitalization()));
-
- return font;
- }
-
- //! Helper method which constructs a stylesheet based on the calculated font style.
- //! We need this too pass along to certain Qt widgets because we use our own custom style parsing system.
- QString GetFontStyleSheet() const
- {
- QFont font = GetFont();
- QColor color = GetColor(Styling::Attribute::Color);
-
- QStringList fields;
-
- fields.push_back(QString("color: rgba(%1,%2,%3,%4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()));
-
- fields.push_back(QString("font-family: %1").arg(font.family()));
- fields.push_back(QString("font-size: %1px").arg(font.pixelSize()));
-
- if (font.bold())
- {
- fields.push_back("font-weight: bold");
- }
-
- switch (font.style())
- {
- case QFont::StyleNormal:
- break;
- case QFont::StyleItalic:
- fields.push_back("font-style: italic");
- break;
- case QFont::StyleOblique:
- fields.push_back("font-style: italic");
- break;
- }
-
- const bool underline = font.underline();
- const bool strikeOut = font.strikeOut();
-
- if (underline && strikeOut)
- {
- fields.push_back("text-decoration: underline line-through");
- }
- else if (underline)
- {
- fields.push_back("text-decoration: underline");
- }
- else if (strikeOut)
- {
- fields.push_back("text-decoration: line-through");
- }
-
- return fields.join("; ");
- }
-
- QPen GetPen(Styling::Attribute width, Styling::Attribute style, Styling::Attribute color, Styling::Attribute cap, bool cosmetic = false) const
- {
- QPen pen;
- pen.setColor(GetAttribute(color, QColor(Qt::black)));
- pen.setWidth(GetAttribute(width, 1));
- pen.setStyle(GetAttribute(style, Qt::SolidLine));
- pen.setCapStyle(GetAttribute(cap, Qt::SquareCap));
- pen.setCosmetic(cosmetic);
-
- return pen;
- }
-
- QPen GetBorder() const
- {
- return GetPen(Styling::Attribute::BorderWidth, Styling::Attribute::BorderStyle, Styling::Attribute::BorderColor, Styling::Attribute::CapStyle);
- }
-
- QBrush GetBrush(Styling::Attribute color, QBrush defaultValue = QBrush()) const
- {
- return GetAttribute(color, defaultValue);
- }
-
- QSizeF GetSize(QSizeF defaultSize) const
- {
- return{
- GetAttribute(Styling::Attribute::Width, defaultSize.width()),
- GetAttribute(Styling::Attribute::Height, defaultSize.height())
- };
- }
-
- QSizeF GetMinimumSize(QSizeF defaultSize = QSizeF(0,0)) const
- {
- return QSizeF(GetAttribute(Styling::Attribute::MinWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MinHeight, defaultSize.height()));
- }
-
- QSizeF GetMaximumSize(QSizeF defaultSize = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) const
- {
- return QSizeF(GetAttribute(Styling::Attribute::MaxWidth, defaultSize.width()), GetAttribute(Styling::Attribute::MaxHeight, defaultSize.height()));
- }
-
- QMarginsF GetMargins(QMarginsF defaultMargins = QMarginsF()) const
- {
- bool hasMargin = false;
- StyleRequestBus::EventResult(hasMargin, m_style, &StyleRequests::HasAttribute, static_cast(Styling::Attribute::Margin));
-
- if (hasMargin)
- {
- qreal defaultMargin = GetAttribute(Styling::Attribute::Margin, 0);
- defaultMargins = QMarginsF(defaultMargin, defaultMargin, defaultMargin, defaultMargin);
- }
-
- return QMarginsF(
- GetAttribute(Styling::Attribute::Margin/*TODO Left*/, defaultMargins.left()),
- GetAttribute(Styling::Attribute::Margin/*TODO Top*/, defaultMargins.top()),
- GetAttribute(Styling::Attribute::Margin/*TODO Right*/, defaultMargins.right()),
- GetAttribute(Styling::Attribute::Margin/*TODO Bottom*/, defaultMargins.bottom())
- );
- }
-
- bool HasTextAlignment() const
- {
- return HasAttribute(Styling::Attribute::TextAlignment) || HasAttribute(Styling::Attribute::TextVerticalAlignment);
- }
-
- Qt::Alignment GetTextAlignment(Qt::Alignment defaultAlignment) const
- {
- bool horizontalAlignment = HasAttribute(Styling::Attribute::TextAlignment);
- bool verticalAlignment = HasAttribute(Styling::Attribute::TextVerticalAlignment);
-
- if (horizontalAlignment || verticalAlignment)
- {
- Qt::Alignment alignment = GetAttribute(Styling::Attribute::TextAlignment, Qt::AlignmentFlag::AlignLeft);
- alignment = alignment | GetAttribute(Styling::Attribute::TextVerticalAlignment, Qt::AlignmentFlag::AlignTop);
-
- return alignment;
- }
-
- return defaultAlignment;
- }
-
- void AddSelector(const AZStd::string_view& selector)
- {
- auto insertResult = m_styleSelectors.insert(AZStd::string(selector));
-
- if (insertResult.second && m_styledEntity.IsValid())
- {
- StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::AddSelectorState, selector.data());
-
- UpdateStyle();
- }
- }
-
- void RemoveSelector(const AZStd::string_view& selector)
- {
- AZStd::size_t elements = m_styleSelectors.erase(selector);
-
- if (elements > 0)
- {
- StyledEntityRequestBus::Event(m_styledEntity, &StyledEntityRequests::RemoveSelectorState, selector.data());
-
- UpdateStyle();
- }
- }
-
- CandyStripeConfiguration GetCandyStripeConfiguration() const
- {
- CandyStripeConfiguration config;
-
- config.m_initialOffset = GetAttribute(Styling::Attribute::StripeOffset, 0);
- config.m_maximumSize = GetAttribute(Styling::Attribute::MaximumStripeSize, 10);
-
- if (config.m_maximumSize <= 0)
- {
- config.m_maximumSize = 1;
- }
-
- config.m_minStripes = GetAttribute(Styling::Attribute::MinimumStripes, 2);
-
- if (config.m_minStripes <= 0)
- {
- config.m_minStripes = 1;
- }
-
- config.m_stripeAngle = GetAttribute(Styling::Attribute::StripeAngle, 60);
-
- if (config.m_stripeAngle > 90)
- {
- config.m_stripeAngle = 89;
- }
- else if (config.m_stripeAngle < -90)
- {
- config.m_stripeAngle = -89;
- }
-
- if (!HasAttribute(Styling::Attribute::StripeColor))
- {
- QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0,0,0));
-
- config.m_stripeColor = backgroundColor.darker();
-
- int totalDifference = 0;
-
- totalDifference += backgroundColor.red() - config.m_stripeColor.red();
- totalDifference += backgroundColor.green() - config.m_stripeColor.green();
- totalDifference += backgroundColor.blue() - config.m_stripeColor.blue();
-
- if (totalDifference < 150)
- {
- config.m_stripeColor = backgroundColor.lighter();
- }
- }
- else
- {
- config.m_stripeColor = GetAttribute(Styling::Attribute::StripeColor, QColor(0, 0, 0));
- }
-
- return config;
- }
-
- PatternedFillGenerator GetPatternedFillGenerator() const
- {
- PatternedFillGenerator generator;
- generator.m_editorId = m_editorId;
-
- generator.m_id = GetAttribute(Styling::Attribute::PatternTemplate, QString()).toUtf8().data();
-
- if (HasAttribute(Styling::Attribute::PatternPalettes))
- {
- AZStd::string paletteStrings = GetAttribute(Styling::Attribute::PatternPalettes, QString()).toUtf8().data();
-
- AzFramework::StringFunc::Tokenize(paletteStrings.c_str(), generator.m_palettes, ',');
- }
- else
- {
- QColor backgroundColor = GetAttribute(Styling::Attribute::BackgroundColor, QColor(0, 0, 0));
-
- QColor patternColor = backgroundColor.darker();
-
- int totalDifference = 0;
-
- totalDifference += backgroundColor.red() - patternColor.red();
- totalDifference += backgroundColor.green() - patternColor.green();
- totalDifference += backgroundColor.blue() - patternColor.blue();
-
- if (totalDifference < 150)
- {
- patternColor = backgroundColor.lighter();
- }
-
- generator.m_colors.push_back(patternColor);
- }
-
- generator.m_configuration = GetPatternFillConfiguration();
-
- return generator;
- }
-
- PatternFillConfiguration GetPatternFillConfiguration() const
- {
- PatternFillConfiguration configuration;
-
- configuration.m_minimumTileRepetitions = GetAttribute(Styling::Attribute::MinimumRepetitions, 1);
- configuration.m_evenRowOffsetPercent = GetAttribute(Styling::Attribute::EvenOffsetPercent, 0.0f);
- configuration.m_oddRowOffsetPercent = GetAttribute(Styling::Attribute::OddOffsetPercent, 0.0f);
-
- return configuration;
- }
-
- void PopulatePaletteConfiguration(PaletteIconConfiguration& configuration) const
- {
- AZStd::string stylePalette;
- StyledEntityRequestBus::EventResult(stylePalette, m_styledEntity, &StyledEntityRequests::GetFullStyleElement);
-
- if (!stylePalette.empty())
- {
- configuration.SetColorPalette(stylePalette);
- }
- }
-
private:
- void UpdateStyle()
- {
- ReleaseStyle(false);
- StyleManagerRequestBus::EventResult(m_style, m_editorId, &StyleManagerRequests::ResolveStyles, m_styledEntity);
- }
-
- void ReleaseStyle(bool destroyChildElement = true)
- {
- if (m_style.IsValid())
- {
- if (m_deleteStyledEntity && destroyChildElement)
- {
- m_deleteStyledEntity = false;
- AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_styledEntity);
- }
- AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationRequests::DeleteEntity, m_style);
-
- m_style.SetInvalid();
- }
- }
-
- void RegisterStyleSheetBus(const EditorId& editorId)
- {
- StyleManagerNotificationBus::Handler::BusDisconnect();
- StyleManagerNotificationBus::Handler::BusConnect(editorId);
- }
+ void UpdateStyle();
+ void ReleaseStyle(bool destroyChildElement = true);
+ void RegisterStyleSheetBus(const EditorId& editorId);
EditorId m_editorId;
AZ::EntityId m_scene;
diff --git a/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake b/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake
index 58a28484f7..bedc6329d5 100644
--- a/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake
+++ b/Gems/GraphCanvas/Code/graphcanvas_staticlib_files.cmake
@@ -91,6 +91,7 @@ set(FILES
StaticLib/GraphCanvas/Styling/Style.cpp
StaticLib/GraphCanvas/Styling/Style.h
StaticLib/GraphCanvas/Styling/StyleHelper.h
+ StaticLib/GraphCanvas/Styling/StyleHelper.cpp
StaticLib/GraphCanvas/Styling/StyleManager.cpp
StaticLib/GraphCanvas/Styling/StyleManager.h
StaticLib/GraphCanvas/Types/ComponentSaveDataInterface.h
diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp
index 28a5a30e9c..81ec4b17c8 100644
--- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp
+++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp
@@ -199,20 +199,6 @@ namespace ImGui
}
}
- // Lod Min
- static ICVar* eLodMinCVAR = gEnv->pConsole->GetCVar("e_LodMin");
- if (eLodMinCVAR)
- {
- int minLodValue = eLodMinCVAR->GetIVal();
- int dragIntVal = minLodValue;
- ImGui::Text("e_LodMin: %d ( Force a lowest LOD level )", minLodValue);
- ImGui::SliderInt("##LodMin", &dragIntVal, 0, 5);
- if (dragIntVal != minLodValue)
- {
- eLodMinCVAR->Set(dragIntVal);
- }
- }
-
// Texel Density
static ICVar* eTexelDensityCVAR = gEnv->pConsole->GetCVar("e_texeldensity");
if (eTexelDensityCVAR)
diff --git a/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp b/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp
index 940a2626f5..259efef392 100644
--- a/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp
+++ b/Gems/ScriptCanvas/Code/Editor/View/Dialogs/ContainerWizard/ContainerWizard.cpp
@@ -226,7 +226,6 @@ namespace ScriptCanvasEditor
auto dataTypeIter = m_containerDataTypeSets.find(workingCrc);
if (dataTypeIter == m_containerDataTypeSets.end())
{
- // No idea wtf do here we've managed to put ourselves into an invalid state
AZ_Error("ScriptCanvas", false, "Unknown partial type found in Container Creation. Aborting.");
close();
break;
diff --git a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui
index 15998bd83b..b5965c9746 100644
--- a/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui
+++ b/Gems/ScriptCanvas/Code/Editor/View/Windows/Tools/UpgradeTool/UpgradeHelper.ui
@@ -184,8 +184,5 @@
-
-
-
diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl
index df2a801969..fedd19a498 100644
--- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl
+++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl
@@ -95,6 +95,7 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN)
detailNormal = ReorientTangentSpaceNormal(macroNormal, detailNormal);
surface.normal = lerp(detailNormal, macroNormal, detailFactor);
surface.normal = normalize(surface.normal);
+ surface.vertexNormal = normalize(IN.m_normal);
// ------- Macro Color -------
float3 macroColor = GetBaseColorInput(TerrainMaterialSrg::m_macroColorMap, TerrainMaterialSrg::m_sampler, origUv, TerrainMaterialSrg::m_baseColor.rgb, o_baseColor_useTexture);
diff --git a/Tools/LyTestTools/ly_test_tools/__init__.py b/Tools/LyTestTools/ly_test_tools/__init__.py
index 58340342ab..972e97d488 100755
--- a/Tools/LyTestTools/ly_test_tools/__init__.py
+++ b/Tools/LyTestTools/ly_test_tools/__init__.py
@@ -16,7 +16,7 @@ ALL_PLATFORM_OPTIONS = ['android', 'ios', 'linux', 'mac', 'windows']
ALL_LAUNCHER_OPTIONS = ['android', 'base', 'linux', 'mac', 'windows', 'windows_editor', 'windows_dedicated', 'windows_generic']
ANDROID = False
IOS = False # Not implemented - see SPEC-2505
-LINUX = sys.platform.startswith('linux') # Not implemented - see SPEC-2501
+LINUX = sys.platform.startswith('linux')
MAC = sys.platform.startswith('darwin')
WINDOWS = sys.platform.startswith('win')
@@ -54,9 +54,11 @@ elif LINUX:
HOST_OS_PLATFORM = 'linux'
HOST_OS_EDITOR = 'linux_editor'
HOST_OS_DEDICATED_SERVER = 'linux_dedicated'
- from ly_test_tools.launchers.platforms.linux.launcher import (LinuxLauncher, LinuxEditor, DedicatedLinuxLauncher)
+ HOST_OS_GENERIC_EXECUTABLE = 'linux_generic'
+ from ly_test_tools.launchers.platforms.linux.launcher import (LinuxLauncher, LinuxEditor, DedicatedLinuxLauncher, LinuxGenericLauncher)
LAUNCHERS['linux'] = LinuxLauncher
LAUNCHERS['linux_editor'] = LinuxEditor
LAUNCHERS['linux_dedicated'] = DedicatedLinuxLauncher
+ LAUNCHERS['linux_generic'] = LinuxGenericLauncher
else:
logger.warning(f'WARNING: LyTestTools only supports Windows, Mac, and Linux. Unexpectedly detected HOST_OS_PLATFORM: "{HOST_OS_PLATFORM}".')
diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py
index 77d58e3a48..fccc94bdcc 100755
--- a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py
+++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py
@@ -265,7 +265,7 @@ class AbstractResourceLocator(object):
Return path to AssetProcessor's log file using the project bin dir
:return: path to 'AP_Gui.log' file in folder
"""
- return os.path.join(self.ap_log_dir(), 'AP_Gui.log')
+ return os.path.join(self.ap_log_dir(), 'AP_GUI.log')
def project_cache(self):
"""
diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py
index cdbd379183..fea60cc9cb 100644
--- a/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py
+++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/platforms/linux.py
@@ -23,9 +23,6 @@ class _LinuxResourceManager(AbstractResourceLocator):
"""
Override for locating resources in a Linux operating system running LyTestTools.
"""
- def __init__(self, build_directory: str, project: str):
- pass
-
def platform_config_file(self):
"""
:return: path to the platform config file
diff --git a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py
index 1c0be299a8..f8245495fa 100755
--- a/Tools/LyTestTools/ly_test_tools/environment/process_utils.py
+++ b/Tools/LyTestTools/ly_test_tools/environment/process_utils.py
@@ -31,45 +31,59 @@ def kill_processes_named(names, ignore_extensions=False):
Kills all processes with a given name
:param names: string process name, or list of strings of process name
- :param ignore_extensions: ignore trailing file extension
+ :param ignore_extensions: ignore trailing file extensions. By default 'abc.exe' will not match 'abc'. Note that
+ enabling this will cause 'abc.exe' to match 'abc', 'abc.bat', and 'abc.sh', though 'abc.GameLauncher.exe'
+ will not match 'abc.DedicatedServer'
"""
if not names:
return
- names = [names] if isinstance(names, str) else names
+ name_set = set()
+ if isinstance(names, str):
+ name_set.add(names)
+ else:
+ name_set.update(names)
if ignore_extensions:
- names = [_remove_extension(name) for name in names]
+ # both exact matches and extensionless
+ stripped_names = set()
+ for name in name_set:
+ stripped_names.add(_remove_extension(name))
+ name_set.update(stripped_names)
# remove any blank names, which may empty the list
- names = list(filter(lambda x: not x.isspace(), names))
- if not names:
+ name_set = set(filter(lambda x: not x.isspace(), name_set))
+ if not name_set:
return
- logger.info(f"Killing all processes named {names}")
- process_list_to_kill = []
+ logger.info(f"Killing all processes named {name_set}")
+ process_set_to_kill = set()
for process in _safe_get_processes(['name', 'pid']):
try:
proc_name = process.name()
except psutil.AccessDenied:
- logger.info(f"Process {process} permissions error during kill_processes_named()", exc_info=True)
+ logger.warning(f"Process {process} permissions error during kill_processes_named()", exc_info=True)
continue
except psutil.ProcessLookupError:
- logger.debug(f"Process {process} could not be killed during kill_processes_named() and was likely already stopped", exc_info=True)
+ logger.debug(f"Process {process} could not be killed during kill_processes_named() and was likely already "
+ f"stopped", exc_info=True)
continue
except psutil.NoSuchProcess:
logger.debug(f"Process '{process}' was active when list of processes was requested but it was not found "
f"during kill_processes_named()", exc_info=True)
continue
+ if proc_name in name_set:
+ logger.debug(f"Found process with name {proc_name}.")
+ process_set_to_kill.add(process)
+
if ignore_extensions:
- proc_name = _remove_extension(proc_name)
+ extensionless_name = _remove_extension(proc_name)
+ if extensionless_name in name_set:
+ process_set_to_kill.add(process)
- if proc_name in names:
- logger.debug(f"Found process with name {proc_name}. Attempting to kill...")
- process_list_to_kill.append(process)
-
- _safe_kill_process_list(process_list_to_kill)
+ if process_set_to_kill:
+ _safe_kill_processes(process_set_to_kill)
def kill_processes_started_from(path):
@@ -90,7 +104,7 @@ def kill_processes_started_from(path):
if process_path.lower().startswith(path.lower()):
process_list.append(process)
- _safe_kill_process_list(process_list)
+ _safe_kill_processes(process_list)
else:
logger.warning(f"Path:'{path}' not found")
@@ -118,7 +132,7 @@ def kill_processes_with_name_not_started_from(name, path):
logger.info("%s -> %s" % (os.path.dirname(process_path.lower()), path))
proccesses_to_kill.append(process)
- _safe_kill_process_list(proccesses_to_kill)
+ _safe_kill_processes(proccesses_to_kill)
else:
logger.warning(f"Path:'{path}' not found")
@@ -151,10 +165,12 @@ def process_exists(name, ignore_extensions=False):
:return: A boolean determining whether the process is alive or not
"""
name = name.lower()
- if ignore_extensions:
- name = _remove_extension(name)
if name.isspace():
return False
+
+ if ignore_extensions:
+ name_extensionless = _remove_extension(name)
+
for process in _safe_get_processes(["name"]):
try:
proc_name = process.name().lower()
@@ -165,10 +181,17 @@ def process_exists(name, ignore_extensions=False):
except psutil.AccessDenied as e:
logger.info(f"Permissions issue on {process} during process_exists check", exc_info=True)
continue
- if ignore_extensions:
- proc_name = _remove_extension(proc_name)
- if proc_name == name:
+
+ if proc_name == name: # abc.exe matches abc.exe
return True
+ if ignore_extensions:
+ proc_name_extensionless = _remove_extension(proc_name)
+ if proc_name_extensionless == name: # abc matches abc.exe
+ return True
+ if proc_name == name_extensionless: # abc.exe matches abc
+ return True
+ # don't check proc_name_extensionless against name_extensionless: abc.exe and abc.exe are already tested,
+ # however xyz.Gamelauncher should not match xyz.DedicatedServer
return False
@@ -341,17 +364,14 @@ def _safe_kill_process(proc):
except Exception: # purposefully broad
logger.warning("Unexpected exception while terminating process", exc_info=True)
-def _safe_kill_process_list(proc_list):
+
+def _safe_kill_processes(processes):
"""
Kills a given process without raising an error
- :param proc_list: The process list to kill
+ :param processes: An iterable of processes to kill
"""
-
- def on_terminate(proc):
- print(f"process '{proc.name()}' with id '{proc.pid}' terminated with exit code {proc.returncode}")
-
- for proc in proc_list:
+ for proc in processes:
try:
logger.info(f"Terminating process '{proc.name()}' with id '{proc.pid}'")
proc.kill()
@@ -360,12 +380,14 @@ def _safe_kill_process_list(proc_list):
except psutil.NoSuchProcess:
logger.debug("Termination request ignored, process was already terminated during iteration", exc_info=True)
except Exception: # purposefully broad
- logger.warning("Unexpected exception while terminating process", exc_info=True)
+ logger.warning("Unexpected exception ignored while terminating process", exc_info=True)
+ def on_terminate(proc):
+ logger.info(f"process '{proc.name()}' with id '{proc.pid}' terminated with exit code {proc.returncode}")
try:
- psutil.wait_procs(proc_list, timeout=30, callback=on_terminate)
+ psutil.wait_procs(processes, timeout=30, callback=on_terminate)
except Exception: # purposefully broad
- logger.warning("Unexpected exception while waiting for process to terminate", exc_info=True)
+ logger.warning("Unexpected exception while waiting for processes to terminate", exc_info=True)
def _terminate_and_confirm_dead(proc):
@@ -383,7 +405,7 @@ def _terminate_and_confirm_dead(proc):
def _remove_extension(filename):
"""
- Returns a file name without its extension
+ Returns a file name without its extension, if any is present
:param filename: The name of a file
:return: The name of the file without the extension
@@ -465,3 +487,17 @@ def close_windows_process(pid, timeout=20, raise_on_missing=False):
# Wait for asyncronous termination
waiter.wait_for(lambda: pid not in psutil.pids(), timeout=timeout,
exc=TimeoutError(f"Process {pid} never terminated"))
+
+
+def get_display_env():
+ """
+ Fetches environment variables with an appropriate display (monitor) configured,
+ useful for subprocess calls to UI applications
+ :return: A dictionary containing environment variables (per os.environ)
+ """
+ env = os.environ.copy()
+ if not ly_test_tools.WINDOWS:
+ if 'DISPLAY' not in env.keys():
+ # assume Display 1 is available in another session
+ env['DISPLAY'] = ':1'
+ return env
diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py
index 42adee91ea..75eaa65e94 100755
--- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py
+++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/android/launcher.py
@@ -208,13 +208,6 @@ class AndroidLauncher(Launcher):
with self.android_vfs_setreg_path.open('w') as android_vfs_setreg:
json.dump(vfs_settings, android_vfs_setreg, indent=4)
- self.workspace.settings.modify_platform_setting('r_AssetProcessorShaderCompiler', 1)
- self.workspace.settings.modify_platform_setting('r_ShadersAsyncCompiling', 0)
- self.workspace.settings.modify_platform_setting('r_ShadersRemoteCompiler', 1)
- self.workspace.settings.modify_platform_setting('r_ShadersAllowCompilation', 1)
- self.workspace.settings.modify_platform_setting('r_ShadersAsyncActivation', 0)
- self.workspace.settings.modify_platform_setting('r_ShaderCompilerServer', '127.0.0.1')
- self.workspace.settings.modify_platform_setting('r_ShaderCompilerPort', '61453')
self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", '127.0.0.1')
def launch(self):
diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py
index 210519d197..112629b349 100644
--- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py
+++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/linux/launcher.py
@@ -13,6 +13,7 @@ import subprocess
import ly_test_tools.environment.waiter
import ly_test_tools.launchers.exceptions
+import ly_test_tools.environment.process_utils as process_utils
from ly_test_tools.launchers.platforms.base import Launcher
from ly_test_tools.launchers.exceptions import TeardownError, ProcessNotStartedError
@@ -68,7 +69,7 @@ class LinuxLauncher(Launcher):
"""
command = [self.binary_path()] + self.args
self._tmpout = TemporaryFile()
- self._proc = subprocess.Popen(command, stdout=self._tmpout, stderr=self._tmpout, universal_newlines=True)
+ self._proc = subprocess.Popen(command, stdout=self._tmpout, stderr=self._tmpout, universal_newlines=True, env=process_utils.get_display_env())
log.debug(f"Started Linux Launcher with command: {command}")
def get_output(self, encoding="utf-8"):
@@ -172,7 +173,6 @@ class LinuxLauncher(Launcher):
self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"')
self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"')
- self.workspace.settings.modify_platform_setting("r_AssetProcessorShaderCompiler", 1)
self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip)
self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", host_ip)
@@ -222,3 +222,28 @@ class LinuxEditor(LinuxLauncher):
"""
assert self.workspace.project is not None
return os.path.join(self.workspace.paths.build_directory(), "Editor")
+
+
+class LinuxGenericLauncher(LinuxLauncher):
+
+ def __init__(self, build, exe_file_name, args=None):
+ super(LinuxLauncher, self).__init__(build, args)
+ self.exe_file_name = exe_file_name
+ self.expected_executable_path = os.path.join(
+ self.workspace.paths.build_directory(), f"{self.exe_file_name}")
+
+ if not os.path.exists(self.expected_executable_path):
+ raise ProcessNotStartedError(
+ f"Unable to locate executable '{self.exe_file_name}' "
+ f"in path: '{self.expected_executable_path}'")
+
+ def binary_path(self):
+ """
+ Return full path to the executable file for this build's configuration and project
+ Relies on the build_directory() in self.workspace.paths to be accurate
+
+ :return: full path to the given exe file
+ """
+ assert self.workspace.project is not None, (
+ 'Project cannot be NoneType - please specify a project name string.')
+ return self.expected_executable_path
diff --git a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py
index 4f904b0a40..d18431ba82 100755
--- a/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py
+++ b/Tools/LyTestTools/ly_test_tools/launchers/platforms/win/launcher.py
@@ -172,8 +172,6 @@ class WinLauncher(Launcher):
self.args.append('--regset="/Amazon/AzCore/Bootstrap/wait_for_connect=1"')
self.args.append(f'--regset="/Amazon/AzCore/Bootstrap/allowed_list={host_ip}"')
- self.workspace.settings.modify_platform_setting("r_AssetProcessorShaderCompiler", 1)
- self.workspace.settings.modify_platform_setting("r_ShaderCompilerServer", host_ip)
self.workspace.settings.modify_platform_setting("log_RemoteConsoleAllowedAddresses", host_ip)
diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py
index 57454930eb..0623715350 100644
--- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py
+++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor.py
@@ -7,21 +7,22 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
A class to control functionality of Lumberyard's asset processor.
The class manages a workspace's asset processor and asset configurations.
"""
-import os
-import datetime
import logging
-import subprocess
-import socket
-import time
-import tempfile
-import shutil
-import stat
-from typing import List, Tuple
+import os
import psutil
+import shutil
+import socket
+import stat
+import subprocess
+import tempfile
+import time
+
+from typing import List, Tuple
import ly_test_tools
-import ly_test_tools.environment.waiter as waiter
import ly_test_tools.environment.file_system as file_system
+import ly_test_tools.environment.process_utils as process_utils
+import ly_test_tools.environment.waiter as waiter
import ly_test_tools.o3de.pipeline_utils as utils
from ly_test_tools.o3de.ap_log_parser import APLogParser
@@ -177,24 +178,26 @@ class AssetProcessor(object):
"""
Read the a port chosen by AP from the log
"""
- start_time = time.time()
- read_port_timeout = 10
- while (time.time() - start_time) < read_port_timeout:
+ port = None
+
+ def _get_port_from_log():
+ nonlocal port
if not os.path.exists(self._workspace.paths.ap_gui_log()):
- logger.debug(f"Log at {self._workspace.paths.ap_gui_log()} doesn't exist, sleeping")
- else:
- log = APLogParser(self._workspace.paths.ap_gui_log())
- if len(log.runs):
- try:
- port = log.runs[-1][port_type]
- if port:
- logger.info(f"Read port type {port_type} : {port}")
- return port
- except Exception: # intentionally broad
- pass
- time.sleep(1)
- logger.warning(f"Failed to read port type {port_type}")
- return 0
+ return False
+
+ log = APLogParser(self._workspace.paths.ap_gui_log())
+ if len(log.runs):
+ try:
+ port = log.runs[-1][port_type]
+ logger.debug(f"Read port type {port_type} : {port}")
+ return True
+ except Exception as ex: # intentionally broad
+ logger.debug("Failed to read port from file", exc_info=ex)
+ return False
+
+ err = AssetProcessorError(f"Failed to read port type {port_type} from {self._workspace.paths.ap_gui_log()}")
+ waiter.wait_for(_get_port_from_log, timeout=10, exc=err)
+ return port
def set_control_connection(self, connection):
self._control_connection = connection
@@ -206,13 +209,8 @@ class AssetProcessor(object):
"""
if not self._control_connection:
control_timeout = 60
- try:
- return self.connect_socket("Control Connection", self.read_control_port,
- set_port_method=self.set_control_connection, timeout=control_timeout)
- except AssetProcessorError as e:
- # We dont want a failure of our test socket connection to fail the entire test automatically.
- logger.error(f"Failed to connect control socket with error {e}")
- pass
+ return self.connect_socket("Control Connection", self.read_control_port,
+ set_port_method=self.set_control_connection, timeout=control_timeout)
return True, None
def using_temp_workspace(self):
@@ -227,34 +225,40 @@ class AssetProcessor(object):
:param set_port_method: If set, method to call with the established connection
:param timeout: Max seconds to attempt connection for
"""
-
- connection_timeout = timeout
connect_port = read_port_method()
- logger.debug(f"Waiting for connection to AP {port_name}: {host}:{connect_port}, "
- f"{connection_timeout} seconds remaining")
- start_time = time.time()
- while (time.time() - start_time) < connection_timeout:
+ logger.debug(f"Attempting to for connect to AP {port_name}: {host}:{connect_port} for {timeout} seconds")
+
+ def _attempt_connection():
+ nonlocal connect_port
+ if self._ap_proc.poll() is not None:
+ raise AssetProcessorError(f"Asset processor exited early with errorcode: {self._ap_proc.returncode}")
+
connection_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- connection_socket.settimeout(10.0)
+ connection_socket.settimeout(timeout)
try:
connection_socket.connect((host, connect_port))
logger.debug(f"Connection to AP {port_name} was successful")
if set_port_method is not None:
set_port_method(connection_socket)
- return True, None
- except Exception: # Purposefully broad
- # Short delay to prevent immediate failure due to slower starting applications such as debug builds
- time.sleep(0.01)
+ return True
+ except Exception as ex: # Purposefully broad
+ logger.debug(f"Failed to connect to {host}:{connect_port}", exc_info=ex)
if not connect_port or not self.using_temp_workspace():
# If we're not using a temp workspace with a fresh log it's possible we're reading a port from
# a previous run and the log just hasn't written yet, we need to keep checking the log for a new
# port to use
- new_connect_port = read_port_method()
- if new_connect_port != connect_port:
- logger.debug(
- f"Read new connect port for {port_name}: {host}:{new_connect_port}")
- connect_port = new_connect_port
- raise AssetProcessorError(f"Could not connect to AP {port_name}")
+ try:
+ new_connect_port = read_port_method()
+ if new_connect_port != connect_port:
+ logger.debug(f"Found new connect port for {port_name}: {host}:{new_connect_port}")
+ connect_port = new_connect_port
+ except Exception as read_exception: # Purposefully broad
+ logger.debug(f"Failed to read port data", exc_info=read_exception)
+ return False
+
+ err = AssetProcessorError(f"Could not connect to AP {port_name} on {host}:{connect_port}")
+ waiter.wait_for(_attempt_connection, timeout=timeout, exc=err)
+ return True, None
def stop(self, timeout=60):
"""
@@ -436,15 +440,14 @@ class AssetProcessor(object):
extra_params=None, add_gem_scan_folders=None, add_config_scan_folders=None, decode=True,
expect_failure=False, quitonidle=False, connect_to_ap=False, accept_input=True, run_until_idle=True,
scan_folder_pattern=None):
- ap_path = self._workspace.paths.asset_processor()
+ ap_path = os.path.abspath(self._workspace.paths.asset_processor())
+ ap_exe_path = os.path.dirname(ap_path)
extra_gui_params = []
if quitonidle:
extra_gui_params.append("--quitonidle")
if accept_input:
extra_gui_params.append("--acceptInput")
- ap_exe_path = os.path.dirname(self._workspace.paths.asset_processor())
-
logger.info("Starting asset processor")
if self.process_exists():
logger.error("Asset processor already started. Stop first")
@@ -483,20 +486,30 @@ class AssetProcessor(object):
logger.warning(f"Cannot capture output when leaving AP connection open.")
logger.info(f"Launching AP with command: {command}")
- self._ap_proc = subprocess.Popen(command, cwd=ap_exe_path)
+ try:
+ self._ap_proc = subprocess.Popen(command, cwd=ap_exe_path, env=process_utils.get_display_env())
- if accept_input and not quitonidle:
- self.connect_control()
+ if accept_input:
+ self.connect_control()
- if connect_to_ap:
- self.connect_listen()
+ if connect_to_ap:
+ self.connect_listen()
- if quitonidle:
- waiter.wait_for(lambda: not self.process_exists(), timeout=timeout)
- elif run_until_idle and accept_input:
- if not self.wait_for_idle():
- return False, None
- return True, None
+ if quitonidle:
+ waiter.wait_for(lambda: not self.process_exists(), timeout=timeout,
+ exc=AssetProcessorError(f"Failed to quit on idle within {timeout} seconds"))
+ elif run_until_idle and accept_input:
+ if not self.wait_for_idle():
+ return False, None
+ return True, None
+ except BaseException as be: # purposefully broad
+ logger.exception("Exception while starting Asset Processor", be)
+ # clean up to avoid leaking open AP process to future tests
+ try:
+ self._ap_proc.kill()
+ except Exception as ex:
+ logger.exception("Ignoring exception while trying to terminate Asset Processor", ex)
+ raise # raise whatever prompted us to clean up
def connect_listen(self, timeout=DEFAULT_TIMEOUT_SECONDS):
# Wait for the AP we launched to be ready to accept a connection
@@ -574,21 +587,17 @@ class AssetProcessor(object):
expect_failure=False):
"""
In case of a timeout, the asset processor and associated processes are killed and the function returns False.
-
+
:param timeout: seconds to wait before aborting
:param capture_output = Capture output which will be returned in the second of the return pair
:param decode: decode byte strings from captured output to utf-8
:param expect_failure: asset processing is expected to fail, so don't error on a failure, and assert on no failure.
"""
logger.info(f"Launching AP with command: {command}")
- start = datetime.datetime.now()
- try:
- duration = datetime.timedelta(seconds=timeout)
- except TypeError:
- logger.warning("Cannot set timeout value of '{}' seconds, defaulting to {} hours".format(
- timeout, DEFAULT_TIMEOUT_HOURS))
- duration = datetime.timedelta(hours=DEFAULT_TIMEOUT_HOURS)
- timeout = duration.total_seconds()
+ start = time.time()
+ if type(timeout) not in [int, float] or timeout < 1:
+ logger.warning(f"Invalid timeout {timeout} - defaulting to {DEFAULT_TIMEOUT_SECONDS} seconds")
+ timeout = DEFAULT_TIMEOUT_SECONDS
run_result = subprocess.run(command, close_fds=True, timeout=timeout, capture_output=capture_output)
output_list = None
@@ -609,8 +618,7 @@ class AssetProcessor(object):
elif expect_failure:
logger.error(f"{command} was expected to fail, but instead ran without failure.")
return True, output_list
- logger.info(
- f"{command} completed successfully in {(datetime.datetime.now() - start).seconds} seconds")
+ logger.info(f"{command} completed successfully in {time.time() - start} seconds")
return True, output_list
def set_failure_log_folder(self, log_root):
@@ -743,14 +751,14 @@ class AssetProcessor(object):
:return: Absolute path of added scan folder
"""
if os.path.isabs(folder_name):
- if not folder_name in self._override_scan_folders:
+ if folder_name not in self._override_scan_folders:
self._override_scan_folders.append(folder_name)
logger.info(f'Adding override scan folder {folder_name}')
return folder_name
else:
if not self._temp_asset_root:
- logger.warning(f"Can't create scan folder, no temporary asset workspace has been created")
- return
+ logger.warning(f"Can not create scan folder, no temporary asset workspace has been created")
+ return ""
scan_folder = os.path.join(self._temp_asset_root if self._temp_asset_root else self._workspace.paths.engine_root(),
folder_name)
if not os.path.isdir(scan_folder):
@@ -802,9 +810,9 @@ class AssetProcessor(object):
if not use_current_root:
self.create_temp_asset_root()
test_asset_root = os.path.join(self._temp_asset_root, self._workspace.project if relative_asset_root is None
- else relative_asset_root)
+ else relative_asset_root)
test_folder = os.path.join(test_asset_root, function_name if existing_function_name is None
- else existing_function_name)
+ else existing_function_name)
if not os.path.isdir(test_folder):
os.makedirs(test_folder)
if add_scan_folder:
diff --git a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py
index 34ea5f4eb8..f30ed2f233 100644
--- a/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py
+++ b/Tools/LyTestTools/ly_test_tools/o3de/asset_processor_utils.py
@@ -9,8 +9,7 @@ import logging
import os
import subprocess
-import ly_test_tools
-from ly_test_tools.environment.process_utils import kill_processes_named as kill_processes_named
+import ly_test_tools.environment.process_utils as process_utils
logger = logging.getLogger(__name__)
@@ -23,7 +22,7 @@ def start_asset_processor(bin_dir):
:return: A subprocess.Popen object for the AssetProcessor process.
"""
os.chdir(bin_dir)
- asset_processor = subprocess.Popen(['AssetProcessor.exe'])
+ asset_processor = subprocess.Popen(['AssetProcessor'], env=process_utils.get_display_env())
return_code = asset_processor.poll()
if return_code is not None and return_code != 0:
@@ -40,11 +39,9 @@ def kill_asset_processor():
:return: None
"""
-
- kill_processes_named('AssetProcessor_tmp', ignore_extensions=True)
- kill_processes_named('AssetProcessor', ignore_extensions=True)
- kill_processes_named('AssetProcessorBatch', ignore_extensions=True)
- kill_processes_named('AssetBuilder', ignore_extensions=True)
- kill_processes_named('rc', ignore_extensions=True)
- kill_processes_named('Lua Editor', ignore_extensions=True)
-
+ process_utils.kill_processes_named('AssetProcessor_tmp', ignore_extensions=True)
+ process_utils.kill_processes_named('AssetProcessor', ignore_extensions=True)
+ process_utils.kill_processes_named('AssetProcessorBatch', ignore_extensions=True)
+ process_utils.kill_processes_named('AssetBuilder', ignore_extensions=True)
+ process_utils.kill_processes_named('rc', ignore_extensions=True)
+ process_utils.kill_processes_named('Lua Editor', ignore_extensions=True)
diff --git a/Tools/LyTestTools/tests/integ/sanity_tests.py b/Tools/LyTestTools/tests/integ/sanity_tests.py
index e27398c477..2e46d822c7 100755
--- a/Tools/LyTestTools/tests/integ/sanity_tests.py
+++ b/Tools/LyTestTools/tests/integ/sanity_tests.py
@@ -63,7 +63,6 @@ class TestAutomatedTestingProject(object):
# Clean up processes after the test is finished
process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True)
- @pytest.mark.skipif(not ly_test_tools.WINDOWS, reason="Editor currently only functions on Windows")
def test_StartEditor_Sanity(self, project):
"""
The `test_StartEditor_Sanity` test function is similar to the previous example with minor adjustments. A
@@ -86,7 +85,7 @@ class TestAutomatedTestingProject(object):
# Call the Editor executable
with editor.start():
# Wait for the process to exist
- waiter.wait_for(lambda: process_utils.process_exists("Editor", ignore_extensions=True))
+ waiter.wait_for(lambda: process_utils.process_exists("Editor.exe", ignore_extensions=True))
finally:
# Clean up processes after the test is finished
process_utils.kill_processes_named(names=process_utils.LY_PROCESS_KILL_LIST, ignore_extensions=True)
diff --git a/Tools/LyTestTools/tests/unit/test_asset_processor.py b/Tools/LyTestTools/tests/unit/test_asset_processor.py
index f487cc8537..aabbf2f2f5 100755
--- a/Tools/LyTestTools/tests/unit/test_asset_processor.py
+++ b/Tools/LyTestTools/tests/unit/test_asset_processor.py
@@ -58,10 +58,8 @@ class TestAssetProcessor(object):
under_test.start(connect_to_ap=True)
assert under_test._ap_proc is not None
- mock_popen.assert_called_once_with([mock_ap_path, '--zeroAnalysisMode',
- f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"',
- '--logDir', under_test.log_root(),
- '--acceptInput', '--platforms', 'bar'], cwd=os.path.dirname(mock_ap_path))
+ mock_popen.assert_called_once()
+ assert '--zeroAnalysisMode' in mock_popen.call_args[0][0]
mock_connect.assert_called()
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
@@ -114,7 +112,7 @@ class TestAssetProcessor(object):
assert result
mock_run.assert_called_once_with([apb_path,
- f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"',
+ f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"',
'--logDir', under_test.log_root()],
close_fds=True, capture_output=False,
timeout=1)
@@ -150,10 +148,8 @@ class TestAssetProcessor(object):
result, _ = under_test.batch_process(None, False)
assert not result
- mock_run.assert_called_once_with([apb_path,
- f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"',
- '--logDir', under_test.log_root()],
- close_fds=True, capture_output=False, timeout=28800.0)
+ mock_run.assert_called_once()
+ assert f'--regset="/Amazon/AzCore/Bootstrap/project_path={mock_project_path}"' in mock_run.call_args[0][0]
@mock.patch('ly_test_tools._internal.managers.workspace.AbstractWorkspaceManager')
diff --git a/Tools/LyTestTools/tests/unit/test_launcher_android.py b/Tools/LyTestTools/tests/unit/test_launcher_android.py
index d2f700e35e..d1adccb096 100755
--- a/Tools/LyTestTools/tests/unit/test_launcher_android.py
+++ b/Tools/LyTestTools/tests/unit/test_launcher_android.py
@@ -238,7 +238,7 @@ class TestAndroidLauncher:
launcher = ly_test_tools.launchers.AndroidLauncher(mock_workspace, ["dummy"])
launcher.configure_settings()
- assert mock_workspace.settings.modify_platform_setting.call_count == 8
+ assert mock_workspace.settings.modify_platform_setting.call_count == 1
@mock.patch('ly_test_tools.launchers.platforms.base.Launcher._config_ini_to_dict')
@mock.patch('ly_test_tools.environment.process_utils.check_output')
diff --git a/Tools/LyTestTools/tests/unit/test_process_utils.py b/Tools/LyTestTools/tests/unit/test_process_utils.py
index de40fb8e34..bd6a79fb09 100755
--- a/Tools/LyTestTools/tests/unit/test_process_utils.py
+++ b/Tools/LyTestTools/tests/unit/test_process_utils.py
@@ -223,7 +223,7 @@ class TestCloseWindowsProcess(unittest.TestCase):
mock_enum.assert_called_once()
-class Test(unittest.TestCase):
+class TestProcessMatching(unittest.TestCase):
@mock.patch("ly_test_tools.environment.process_utils._safe_get_processes")
def test_ProcExists_HasExtension_Found(self, mock_get_proc):
@@ -261,18 +261,55 @@ class Test(unittest.TestCase):
self.assertTrue(result)
proc_mock.name.assert_called()
- @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes')
@mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
- def test_KillProcNamed_MockKill_SilentSuccess(self, mock_get_proc):
+ def test_KillProcNamed_ExactMatch_Killed(self, mock_get_proc, mock_kill_proc):
+ name = "dummy.exe"
+ proc_mock = mock.MagicMock()
+ proc_mock.name.return_value = name
+ mock_get_proc.return_value = [proc_mock]
+
+ process_utils.kill_processes_named("dummy.exe", ignore_extensions=False)
+ mock_kill_proc.assert_called()
+ proc_mock.name.assert_called()
+
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes')
+ @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
+ def test_KillProcNamed_NearMatch_Ignore(self, mock_get_proc, mock_kill_proc):
+ name = "dummy.exe"
+ proc_mock = mock.MagicMock()
+ proc_mock.name.return_value = name
+ mock_get_proc.return_value = [proc_mock]
+
+ process_utils.kill_processes_named("dummy", ignore_extensions=False)
+ mock_kill_proc.assert_not_called()
+ proc_mock.name.assert_called()
+
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes')
+ @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
+ def test_KillProcNamed_NearMatchIgnoreExtension_Kill(self, mock_get_proc, mock_kill_proc):
name = "dummy.exe"
proc_mock = mock.MagicMock()
proc_mock.name.return_value = name
mock_get_proc.return_value = [proc_mock]
process_utils.kill_processes_named("dummy", ignore_extensions=True)
+ mock_kill_proc.assert_called()
proc_mock.name.assert_called()
- @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes')
+ @mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
+ def test_KillProcNamed_ExactMatchIgnoreExtension_Killed(self, mock_get_proc, mock_kill_proc):
+ name = "dummy.exe"
+ proc_mock = mock.MagicMock()
+ proc_mock.name.return_value = name
+ mock_get_proc.return_value = [proc_mock]
+
+ process_utils.kill_processes_named("dummy.exe", ignore_extensions=True)
+ mock_kill_proc.assert_called()
+ proc_mock.name.assert_called()
+
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes', mock.MagicMock)
@mock.patch('ly_test_tools.environment.process_utils._safe_get_processes')
@mock.patch('os.path.exists')
def test_KillProcFrom_MockKill_SilentSuccess(self, mock_path, mock_get_proc):
@@ -293,7 +330,7 @@ class Test(unittest.TestCase):
mock_kill.assert_called()
- @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes', mock.MagicMock)
@mock.patch('psutil.Process')
def test_KillProcPid_NoProc_SilentPass(self, mock_psutil):
mock_proc = mock.MagicMock()
@@ -302,7 +339,7 @@ class Test(unittest.TestCase):
process_utils.kill_process_with_pid(1)
- @mock.patch('ly_test_tools.environment.process_utils._safe_kill_process', mock.MagicMock)
+ @mock.patch('ly_test_tools.environment.process_utils._safe_kill_processes', mock.MagicMock)
@mock.patch('psutil.Process')
def test_KillProcPidRaiseOnMissing_NoProc_Raises(self, mock_psutil):
mock_proc = mock.MagicMock()
@@ -339,7 +376,7 @@ class Test(unittest.TestCase):
mock_wait_procs.side_effect = psutil.PermissionError()
proc_mock = mock.MagicMock()
- process_utils._safe_kill_process_list(proc_mock)
+ process_utils._safe_kill_processes(proc_mock)
mock_wait_procs.assert_called()
mock_log_warn.assert_called()
diff --git a/cmake/Tools/layout_tool.py b/cmake/Tools/layout_tool.py
index 62e3922770..8093f72e44 100755
--- a/cmake/Tools/layout_tool.py
+++ b/cmake/Tools/layout_tool.py
@@ -120,10 +120,7 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ
warning_count += _warn(f"'system_{platform_name_lower}_{asset_type}.cfg' is missing from {str(layout_path)}")
system_config_values = None
else:
- system_config_values = common.get_config_file_values(str(platform_system_cfg_file), ['r_ShadersRemoteCompiler',
- 'r_ShadersAllowCompilation',
- 'r_AssetProcessorShaderCompiler',
- 'r_ShaderCompilerServer'])
+ system_config_values = common.get_config_file_values(str(platform_system_cfg_file), [])
if bootstrap_values:
@@ -146,24 +143,23 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ
elif system_config_values is not None:
- shaders_remote_compiler = system_config_values.get('r_ShadersRemoteCompiler') or '0'
+ shaders_remote_compiler = '0'
asset_processor_shader_compiler = system_config_values.get('r_AssetProcessorShaderCompiler') or '0'
- shader_compiler_server = system_config_values.get('r_ShaderCompilerServer') or LOCAL_HOST
+ shader_compiler_server = LOCAL_HOST
shaders_allow_compilation = system_config_values.get('r_ShadersAllowCompilation')
def _validate_remote_shader_settings():
- if shader_compiler_server == LOCAL_HOST:
- if asset_processor_shader_compiler != '1':
- return _warn(f"Connection to the remote shader compiler (r_ShaderCompilerServer) is not properly "
- f"set in system_{platform_name_lower}_{asset_type}.cfg. If it is set to {LOCAL_HOST}, then "
- f"r_AssetProcessorShaderCompiler must be set to 1.")
+ if asset_processor_shader_compiler != '1':
+ return _warn(f"Connection to the remote shader compiler (r_ShaderCompilerServer) is not properly "
+ f"set in system_{platform_name_lower}_{asset_type}.cfg. If it is set to {LOCAL_HOST}, then "
+ f"r_AssetProcessorShaderCompiler must be set to 1.")
- else:
- if _validate_remote_ap(remote_ip, remote_connect, False) > 0:
- return _warn(f"The system_{platform_name_lower}_{asset_type}.cfg file is configured to connect to the"
- f" shader compiler server through the remote connection to the Asset Processor.")
+ else:
+ if _validate_remote_ap(remote_ip, remote_connect, False) > 0:
+ return _warn(f"The system_{platform_name_lower}_{asset_type}.cfg file is configured to connect to the"
+ f" shader compiler server through the remote connection to the Asset Processor.")
return 0
# Validation steps based on the asset mode
@@ -181,16 +177,9 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ
warning_count += _warn("No pak files found for PAK mode deployment")
# Check if the shader paks are set
if has_shader_pak:
- # If the shader paks are set, make sure that the remote shader compiler connection settings are set
- # or that it is going through AP
- if shaders_remote_compiler == '1':
- warning_count += _warn(f"Shader paks are set for project {project_name} but remote shader compiling "
- f"(r_ShadersRemoteCompiler) is still enabled "
- f"for it in system_{platform_name_lower}_{asset_type}.cfg.")
- else:
- # Since we are not connecting to the shader compiler, also make sure bootstrap is not configured to
- # connect to Asset Processor remotely
- warning_count += _validate_remote_ap(remote_ip, remote_connect, False)
+ # Since we are not connecting to the shader compiler, also make sure bootstrap is not configured to
+ # connect to Asset Processor remotely
+ warning_count += _validate_remote_ap(remote_ip, remote_connect, False)
if shaders_allow_compilation is not None and shaders_allow_compilation == '1':
warning_count += _warn(f"Shader paks are set for project {project_name} but shader compiling "
diff --git a/editor.cfg b/editor.cfg
index 843a52824d..a8719590c5 100644
--- a/editor.cfg
+++ b/editor.cfg
@@ -1,33 +1,12 @@
-- Settings stored here are only used in the Editor
--- Disable the Missing Asset Resolver by default
-ed_MissingAssetResolver = 0
-e_ShadowsCache=0
-r_MotionBlur=0
-r_HDRVignetting=0
--- For feature-test compatibility
-mn_FatalErrorOnInvalidEntity=0
-
-- Do not warn on Pak file access issues
sys_PakWarnOnPakAccessFailures=0
--- By default, disable any possible stereo output that might have been enabled via a GEM/other config file so that
--- the editor does not startup in stereo mode (which prevents actually editing the environment)
-r_StereoMode=0
-r_StereoOutput=0
-
-- When editing terrain in the editor, the highest-detail octree nodes for any edited sector will be rendered until
-- the level is exported and saved, which can cause an artificial increase in the number of nodes that can get
-- queued for visibility checks. These numbers need to be set high enough to account for those increases.
--- The CheckOcclusionQueueSize should be at least (terrain height * terrain width) / (32 * 32) in size.
--- (Each queue entry is 64 bytes of RAM)
-e_CheckOcclusionQueueSize=32768
-
--- The CheckOcclusionOutputQueueSize should be at least double the above queue size for safety.
--- (Each queue entry is 64 bytes of RAM)
-e_CheckOcclusionOutputQueueSize=65536
-
-- Enable warnings when asset loads take longer than the given millisecond threshold
cl_assetLoadWarningEnable=true
cl_assetLoadWarningMsThreshold=100
diff --git a/scripts/o3de/o3de/manifest.py b/scripts/o3de/o3de/manifest.py
index 7e504d29cd..b665727a4e 100644
--- a/scripts/o3de/o3de/manifest.py
+++ b/scripts/o3de/o3de/manifest.py
@@ -13,8 +13,10 @@ import json
import logging
import os
import pathlib
+import shutil
+import hashlib
-from o3de import validation
+from o3de import validation, utils
logger = logging.getLogger()
logging.basicConfig()
@@ -135,12 +137,12 @@ def get_o3de_manifest() -> pathlib.Path:
json_data.update({'default_restricted_folder': default_restricted_folder.as_posix()})
json_data.update({'default_third_party_folder': default_third_party_folder.as_posix()})
+ json_data.update({'engines': []})
json_data.update({'projects': []})
json_data.update({'external_subdirectories': []})
json_data.update({'templates': []})
json_data.update({'restricted': []})
json_data.update({'repos': []})
- json_data.update({'engines': []})
default_restricted_folder_json = default_restricted_folder / 'restricted.json'
if not default_restricted_folder_json.is_file():
@@ -197,11 +199,11 @@ def load_o3de_manifest(manifest_path: pathlib.Path = None) -> dict:
def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> bool:
"""
- Save the json dictionary to the supplied manifest file or ~/.o3de/o3de_manifest.json if manifest_path is None
+ Save the json dictionary to the supplied manifest file or ~/.o3de/o3de_manifest.json if None
- :param json_data: dictionary to save in json format at the file path
- :param manifest_path: optional path to manifest file to save
- """
+ :param json_data: dictionary to save in json format at the file path
+ :param manifest_path: optional path to manifest file to save
+ """
if not manifest_path:
manifest_path = get_o3de_manifest()
with manifest_path.open('w') as s:
@@ -213,7 +215,6 @@ def save_o3de_manifest(json_data: dict, manifest_path: pathlib.Path = None) -> b
return False
-
def get_gems_from_subdirectories(external_subdirs: list) -> list:
'''
Helper Method for scanning a set of external subdirectories for gem.json files
@@ -235,7 +236,6 @@ def get_gems_from_subdirectories(external_subdirs: list) -> list:
return gem_directories
-# Data query methods
def get_engines() -> list:
json_data = load_o3de_manifest()
engine_list = json_data['engines'] if 'engines' in json_data else []
@@ -421,6 +421,48 @@ def get_templates_for_generic_creation(): # temporary until we have a better wa
return list(filter(filter_project_and_gem_templates_out, get_all_templates()))
+def get_json_file_path(object_typename: str,
+ object_path: str or pathlib.Path) -> pathlib.Path:
+ if not object_typename or not object_path:
+ logger.error('Must specify an object typename and object path.')
+ return None
+
+ object_path = pathlib.Path(object_path).resolve()
+ return object_path / f'{object_typename}.json'
+
+
+def get_json_data_file(object_json: pathlib.Path,
+ object_typename: str,
+ object_validator: callable) -> dict or None:
+ if not object_typename:
+ logger.error('Missing object typename.')
+ return None
+
+ if not object_json or not object_json.is_file():
+ logger.error(f'Invalid {object_typename} json {object_json} supplied or file missing.')
+ return None
+
+ if not object_validator or not object_validator(object_json):
+ logger.error(f'{object_typename} json {object_json} is not valid or could not be validated.')
+ return None
+
+ with object_json.open('r') as f:
+ try:
+ object_json_data = json.load(f)
+ except json.JSONDecodeError as e:
+ logger.warn(f'{object_json} failed to load: {e}')
+ else:
+ return object_json_data
+
+ return None
+
+def get_json_data(object_typename: str,
+ object_path: str or pathlib.Path,
+ object_validator: callable) -> dict or None:
+ object_json = get_json_file_path(object_typename, object_path)
+
+ return get_json_data_file(object_json, object_typename, object_validator)
+
def get_engine_json_data(engine_name: str = None,
engine_path: str or pathlib.Path = None) -> dict or None:
@@ -431,28 +473,7 @@ def get_engine_json_data(engine_name: str = None,
if engine_name and not engine_path:
engine_path = get_registered(engine_name=engine_name)
- if not engine_path:
- logger.error(f'Engine Path {engine_path} has not been registered.')
- return None
-
- engine_path = pathlib.Path(engine_path).resolve()
- engine_json = engine_path / 'engine.json'
- if not engine_json.is_file():
- logger.error(f'Engine json {engine_json} is not present.')
- return None
- if not validation.valid_o3de_engine_json(engine_json):
- logger.error(f'Engine json {engine_json} is not valid.')
- return None
-
- with engine_json.open('r') as f:
- try:
- engine_json_data = json.load(f)
- except json.JSONDecodeError as e:
- logger.warn(f'{engine_json} failed to load: {str(e)}')
- else:
- return engine_json_data
-
- return None
+ return get_json_data('engine', engine_path, validation.valid_o3de_engine_json)
def get_project_json_data(project_name: str = None,
@@ -464,28 +485,7 @@ def get_project_json_data(project_name: str = None,
if project_name and not project_path:
project_path = get_registered(project_name=project_name)
- if not project_path:
- logger.error(f'Project Path {project_path} has not been registered.')
- return None
-
- project_path = pathlib.Path(project_path).resolve()
- project_json = project_path / 'project.json'
- if not project_json.is_file():
- logger.error(f'Project json {project_json} is not present.')
- return None
- if not validation.valid_o3de_project_json(project_json):
- logger.error(f'Project json {project_json} is not valid.')
- return None
-
- with project_json.open('r') as f:
- try:
- project_json_data = json.load(f)
- except json.JSONDecodeError as e:
- logger.warn(f'{project_json} failed to load: {str(e)}')
- else:
- return project_json_data
-
- return None
+ return get_json_data('project', project_path, validation.valid_o3de_project_json)
def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None,
@@ -497,28 +497,7 @@ def get_gem_json_data(gem_name: str = None, gem_path: str or pathlib.Path = None
if gem_name and not gem_path:
gem_path = get_registered(gem_name=gem_name, project_path=project_path)
- if not gem_path:
- logger.error(f'Gem Path {gem_path} has not been registered.')
- return None
-
- gem_path = pathlib.Path(gem_path).resolve()
- gem_json = gem_path / 'gem.json'
- if not gem_json.is_file():
- logger.error(f'Gem json {gem_json} is not present.')
- return None
- if not validation.valid_o3de_gem_json(gem_json):
- logger.error(f'Gem json {gem_json} is not valid.')
- return None
-
- with gem_json.open('r') as f:
- try:
- gem_json_data = json.load(f)
- except json.JSONDecodeError as e:
- logger.warn(f'{gem_json} failed to load: {str(e)}')
- else:
- return gem_json_data
-
- return None
+ return get_json_data('gem', gem_path, validation.valid_o3de_gem_json)
def get_template_json_data(template_name: str = None, template_path: str or pathlib.Path = None,
@@ -530,28 +509,7 @@ def get_template_json_data(template_name: str = None, template_path: str or path
if template_name and not template_path:
template_path = get_registered(template_name=template_name, project_path=project_path)
- if not template_path:
- logger.error(f'Template Path {template_path} has not been registered.')
- return None
-
- template_path = pathlib.Path(template_path).resolve()
- template_json = template_path / 'template.json'
- if not template_json.is_file():
- logger.error(f'Template json {template_json} is not present.')
- return None
- if not validation.valid_o3de_template_json(template_json):
- logger.error(f'Template json {template_json} is not valid.')
- return None
-
- with template_json.open('r') as f:
- try:
- template_json_data = json.load(f)
- except json.JSONDecodeError as e:
- logger.warn(f'{template_json} failed to load: {str(e)}')
- else:
- return template_json_data
-
- return None
+ return get_json_data('template', template_path, validation.valid_o3de_template_json)
def get_restricted_json_data(restricted_name: str = None, restricted_path: str or pathlib.Path = None,
@@ -563,29 +521,23 @@ def get_restricted_json_data(restricted_name: str = None, restricted_path: str o
if restricted_name and not restricted_path:
restricted_path = get_registered(restricted_name=restricted_name, project_path=project_path)
- if not restricted_path:
- logger.error(f'Restricted Path {restricted_path} has not been registered.')
+ return get_json_data('restricted', restricted_path, validation.valid_o3de_restricted_json)
+
+def get_repo_json_data(repo_uri: str) -> dict or None:
+ if not repo_uri:
+ logger.error('Must specify a Repo Uri.')
return None
- restricted_path = pathlib.Path(restricted_path).resolve()
- restricted_json = restricted_path / 'restricted.json'
- if not restricted_json.is_file():
- logger.error(f'Restricted json {restricted_json} is not present.')
- return None
- if not validation.valid_o3de_restricted_json(restricted_json):
- logger.error(f'Restricted json {restricted_json} is not valid.')
- return None
+ repo_json = get_repo_path(repo_uri=repo_uri)
- with restricted_json.open('r') as f:
- try:
- restricted_json_data = json.load(f)
- except json.JSONDecodeError as e:
- logger.warn(f'{restricted_json} failed to load: {str(e)}')
- else:
- return restricted_json_data
+ return get_json_data_file(repo_json, "Repo", validation.valid_o3de_repo_json)
- return None
+def get_repo_path(repo_uri: str, cache_folder: str = None) -> pathlib.Path:
+ if not cache_folder:
+ cache_folder = get_o3de_cache_folder()
+ repo_sha256 = hashlib.sha256(repo_uri.encode())
+ return cache_folder / str(repo_sha256.hexdigest() + '.json')
def get_registered(engine_name: str = None,
project_name: str = None,
@@ -721,9 +673,7 @@ def get_registered(engine_name: str = None,
elif isinstance(repo_name, str):
cache_folder = get_o3de_cache_folder()
for repo_uri in json_data['repos']:
- repo_uri = pathlib.Path(repo_uri).resolve()
- repo_sha256 = hashlib.sha256(repo_uri.encode())
- cache_file = cache_folder / str(repo_sha256.hexdigest() + '.json')
+ cache_file = get_repo_path(repo_uri=repo_uri, cache_folder=cache_folder)
if cache_file.is_file():
repo = pathlib.Path(cache_file).resolve()
with repo.open('r') as f:
diff --git a/scripts/o3de/o3de/validation.py b/scripts/o3de/o3de/validation.py
index 8fcc0d7e7d..5c683f0667 100644
--- a/scripts/o3de/o3de/validation.py
+++ b/scripts/o3de/o3de/validation.py
@@ -27,7 +27,6 @@ def valid_o3de_repo_json(file_name: str or pathlib.Path) -> bool:
test = json_data['origin']
except (json.JSONDecodeError, KeyError) as e:
return False
-
return True
diff --git a/system_android_android.cfg b/system_android_android.cfg
index d5bfddeb73..10ab95abc4 100644
--- a/system_android_android.cfg
+++ b/system_android_android.cfg
@@ -6,40 +6,14 @@ sys_PakLogInvalidFileAccess=1
r_WidthAndHeightAsFractionOfScreenSize=1.0
r_MaxWidth=1280
r_MaxHeight=1080
-
r_fullscreen=0
+r_ShadersAllowCompilation=1
-- Enable to prevent log spam, can cause missed messages
-- log_spamdelay=1
--- DXGL
---r_Batching=0
-
--- Enabling aync shader compiling causes a hang on some Android devices.
-r_ShadersAsyncCompiling=0
-r_ShadersRemoteCompiler=1
-r_ShadersAllowCompilation=1
-r_ShadersAsyncActivation=0
-
--- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor
--- to forward the request to the real shader compiler server. Your device is no
--- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor:
-r_AssetProcessorShaderCompiler=1
-
--- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1.
--- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port):
-r_ShaderCompilerServer=127.0.0.1
-
--- For Shader Compiler server running on other machines - 61453 is the default port
-r_ShaderCompilerPort=61453
-
--- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high.
-r_GraphicsQuality = 2
-
-s_FileCacheManagerSize=262144
-
-- Remote console inclusion list
log_RemoteConsoleAllowedAddresses=127.0.0.1
-- Localization Settings
-sys_localization_format=0
\ No newline at end of file
+sys_localization_format=0
diff --git a/system_ios_ios.cfg b/system_ios_ios.cfg
index 190ad4a121..abf08d0209 100644
--- a/system_ios_ios.cfg
+++ b/system_ios_ios.cfg
@@ -3,26 +3,7 @@
------------------------
r_FullScreen=1
-
r_ShadersAllowCompilation=1
-r_ShadersAsyncActivation=0
-r_ShadersAsyncCompiling=0
-r_ShadersRemoteCompiler=1
-r_ShadersUseLLVMDirectXCompiler=1
-
--- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high.
-r_GraphicsQuality = 0
-
--- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor
--- to forward the request to the real shader compiler server. Your device is no
--- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor:
-r_AssetProcessorShaderCompiler=1
-
--- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1.
--- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port):
-r_ShaderCompilerServer=127.0.0.1
-
---r_ShaderCompilerPort=61453
------------------------
-- System
@@ -39,16 +20,6 @@ sys_physics_CPU=0
-- log_spamdelay=1
log_IncludeTime=1
-------------------------
--- Audio
-------------------------
-s_FileCacheManagerSize=262144
-------------------------
--- Auxiliary Geometry
-------------------------
-r_enableAuxGeom=0
-r_auxGeom=0
-
-- Remote console inclusion list
log_RemoteConsoleAllowedAddresses=127.0.0.1
diff --git a/system_linux_pc.cfg b/system_linux_pc.cfg
index 614bc44b49..5fec6b8dfd 100644
--- a/system_linux_pc.cfg
+++ b/system_linux_pc.cfg
@@ -10,8 +10,6 @@ sys_PakLogInvalidFileAccess = 0
-- Remote console inclusion list
log_RemoteConsoleAllowedAddresses=127.0.0.1
-gm_disconnectDetection = 1
-
-- Localization Settings
sys_localization_format=0
@@ -20,27 +18,7 @@ r_width = 1280
r_height = 720
r_fullscreen = 0
-r_ShadersAsyncCompiling = 3
-r_ShadersAsyncActivation = 3
-r_ShadersAsyncMaxThreads = 16
-r_ShadersRemoteCompiler = 1
r_ShadersAllowCompilation = 1
--- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor
--- to forward the request to the real shader compiler server. Your device is no
--- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor:
-r_AssetProcessorShaderCompiler=0
-
--- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1.
--- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port):
---r_ShaderCompilerServer=127.0.0.1
---r_ShaderCompilerPort = 61453
-
--- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. Autodetection not yet implemented for this platform.
-r_GraphicsQuality = 1
-
--- Texture streaming not supported on opengl
-r_TexturesStreaming=0
-
-- Display FPS
r_displayInfo = 3
diff --git a/system_mac_mac.cfg b/system_mac_mac.cfg
index 22fbca6e1e..ef145c890e 100644
--- a/system_mac_mac.cfg
+++ b/system_mac_mac.cfg
@@ -3,9 +3,6 @@ sys_float_exceptions=0
log_IncludeTime=1
sys_PakLogInvalidFileAccess=0
--- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. Currently overwritten by hardcoded value for this platform.
-r_GraphicsQuality = 0
-
r_width=1280
r_height=720
r_fullscreen=0
@@ -13,25 +10,7 @@ r_fullscreen=0
-- Enable to prevent log spam, can cause missed messages
-- log_spamdelay=1
--- DXGL
-r_Batching=0
-
-r_ShadersAsyncCompiling=0
-r_ShadersRemoteCompiler=1
r_ShadersAllowCompilation=1
-r_ShadersAsyncActivation=0
-r_ShadersUseLLVMDirectXCompiler=1
-
--- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor
--- to forward the request to the real shader compiler server. Your device is no
--- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor:
-r_AssetProcessorShaderCompiler=1
-
--- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1.
--- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port):
-r_ShaderCompilerServer=127.0.0.1
-
---r_ShaderCompilerPort=61453
-- Remote console inclusion list
log_RemoteConsoleAllowedAddresses=127.0.0.1
diff --git a/system_windows_pc.cfg b/system_windows_pc.cfg
index 05210e02e0..aa53ed9323 100644
--- a/system_windows_pc.cfg
+++ b/system_windows_pc.cfg
@@ -11,27 +11,7 @@ r_fullscreen = 0
-- Enable to prevent log spam, can cause missed messages
-- log_spamdelay=1
-r_ShadersAsyncCompiling = 3
-r_ShadersAsyncActivation = 3
-r_ShadersAsyncMaxThreads = 16
-r_ShadersRemoteCompiler = 0
r_ShadersAllowCompilation = 1
--- Use the Asset Processor to route requests to compile shaders. This enables the Asset Processor
--- to forward the request to the real shader compiler server. Your device is no
--- longer required to be on the same network as the shader compiler server, as long as the device can contact the Asset Processor:
-r_AssetProcessorShaderCompiler=0
-
--- If you run your device locally on the same computer as the shader compiler server, you can use 127.0.0.1.
--- To connect to a shader compiler server that runs on another computer, change localhost to the IP address of that computer (61453 is the default port):
-r_ShaderCompilerServer=127.0.0.1
---r_ShaderCompilerPort = 61453
-
--- Spec level: 0 = auto, 1 = low, 2 = medium, 3 = high, 4 = very high. Autodetection not yet implemented for this platform.
-r_GraphicsQuality = 4
-
---r_driver=GL
---r_ShadersGL4=1
-
-- Localization Settings
sys_localization_format=0