Răsfoiți Sursa

Initial commit

alexpete 4 ani în urmă
comite
a10351f38d
100 a modificat fișierele cu 9264 adăugiri și 0 ștergeri
  1. 57 0
      .clang-format
  2. 9 0
      .editorconfig
  3. 119 0
      .gitattributes
  4. 18 0
      .gitignore
  5. 2 0
      .lfsconfig
  6. 30 0
      .p4ignore
  7. 591 0
      AssetProcessorPlatformConfig.ini
  8. 530 0
      AutomatedReview/Jenkinsfile
  9. 15 0
      AutomatedReview/lumberyard.json
  10. 55 0
      BuildAtomSampleViewer_Paks_PC.bat
  11. 55 0
      BuildAtomTest_Paks_PC.bat
  12. 56 0
      BuildCMakeTestbed_Paks_PC.bat
  13. 111 0
      BuildReleaseAuxiliaryContent.py
  14. 109 0
      Build_AssetBundler_AuxiliaryContent_PC.bat
  15. 114 0
      CMakeLists.txt
  16. 12 0
      CMakeTestbed/CMakeLists.txt
  17. 97 0
      CMakeTestbed/Config/Editor.xml
  18. 91 0
      CMakeTestbed/Config/Game.xml
  19. 91 0
      CMakeTestbed/Config/Server.xml
  20. 12 0
      CMakeTestbed/Gem/CMakeLists.txt
  21. 65 0
      CMakeTestbed/Gem/Code/CMakeLists.txt
  22. 31 0
      CMakeTestbed/Gem/Code/Include/CMakeTestbed/CMakeTestbedBus.h
  23. 13 0
      CMakeTestbed/Gem/Code/Platform/Android/cmaketestbed_android_files.cmake
  24. 13 0
      CMakeTestbed/Gem/Code/Platform/Linux/cmaketestbed_linux_files.cmake
  25. 14 0
      CMakeTestbed/Gem/Code/Platform/Mac/cmaketestbed_mac_files.cmake
  26. 13 0
      CMakeTestbed/Gem/Code/Platform/Windows/cmaketestbed_windows_files.cmake
  27. 14 0
      CMakeTestbed/Gem/Code/Platform/iOS/cmaketestbed_ios_files.cmake
  28. 51 0
      CMakeTestbed/Gem/Code/Source/CMakeTestbedModule.cpp
  29. 73 0
      CMakeTestbed/Gem/Code/Source/CMakeTestbedSystemComponent.cpp
  30. 47 0
      CMakeTestbed/Gem/Code/Source/CMakeTestbedSystemComponent.h
  31. 19 0
      CMakeTestbed/Gem/Code/cmaketestbed_files.cmake
  32. 14 0
      CMakeTestbed/Gem/Code/cmaketestbed_ios_files.cmake
  33. 20 0
      CMakeTestbed/Gem/Code/game_dependencies.cmake
  34. 20 0
      CMakeTestbed/Gem/Code/runtime_dependencies.cmake
  35. 22 0
      CMakeTestbed/Gem/Code/tool_dependencies.cmake
  36. 3 0
      CMakeTestbed/Gem/Resources/CryEngineLogoLauncher.bmp
  37. 3 0
      CMakeTestbed/Gem/Resources/GameSDK.ico
  38. 116 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/Contents.json
  39. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadAppIcon152x152.png
  40. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadAppIcon76x76.png
  41. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadProAppIcon167x167.png
  42. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSettingsIcon29x29.png
  43. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSettingsIcon58x58.png
  44. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSpotlightIcon40x40.png
  45. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSpotlightIcon80x80.png
  46. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneAppIcon120x120.png
  47. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneAppIcon180x180.png
  48. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSettingsIcon58x58.png
  49. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSettingsIcon87x87.png
  50. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSpotlightIcon120x120.png
  51. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSpotlightIcon80x80.png
  52. 6 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/Contents.json
  53. 169 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/Contents.json
  54. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1024x768.png
  55. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1536x2048.png
  56. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage2048x1536.png
  57. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage768x1024.png
  58. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x1136.png
  59. 3 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x960.png
  60. 45 0
      CMakeTestbed/Gem/Resources/IOSLauncher/Info.plist
  61. 68 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/Contents.json
  62. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_128 _2x.png
  63. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_128.png
  64. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_16.png
  65. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_16_2x.png
  66. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_256 _2x.png
  67. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_256.png
  68. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_32.png
  69. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_32_2x.png
  70. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_512.png
  71. 3 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_512_2x.png
  72. 6 0
      CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/Contents.json
  73. 24 0
      CMakeTestbed/Gem/Resources/MacLauncher/Info.plist
  74. 16 0
      CMakeTestbed/Gem/gem.json
  75. 3 0
      CMakeTestbed/Gem/preview.png
  76. 3 0
      CMakeTestbed/Levels/default/default.ly
  77. 6 0
      CMakeTestbed/Levels/default/filelist.xml
  78. 3 0
      CMakeTestbed/Levels/default/level.pak
  79. 14 0
      CMakeTestbed/Levels/default/leveldata/Environment.xml
  80. 5 0
      CMakeTestbed/Levels/default/leveldata/GameTokens.xml
  81. 3 0
      CMakeTestbed/Levels/default/leveldata/Heightmap.dat
  82. 7 0
      CMakeTestbed/Levels/default/leveldata/TerrainTexture.xml
  83. 356 0
      CMakeTestbed/Levels/default/leveldata/TimeOfDay.xml
  84. 3 0
      CMakeTestbed/Levels/default/leveldata/VegetationMap.dat
  85. 12 0
      CMakeTestbed/Levels/default/tags.txt
  86. 3 0
      CMakeTestbed/Levels/default/terrain/cover.ctc
  87. 3 0
      CMakeTestbed/Levels/default/terraintexture.pak
  88. 1 0
      CMakeTestbed/autoexec.cfg
  89. 7 0
      CMakeTestbed/game.cfg
  90. 53 0
      CMakeTestbed/gems.json
  91. 3 0
      CMakeTestbed/preview.png
  92. 14 0
      CMakeTestbed/project.json
  93. 6 0
      Code/.p4ignore
  94. 16 0
      Code/CMakeLists.txt
  95. 17 0
      Code/CryEngine/CMakeLists.txt
  96. 733 0
      Code/CryEngine/Cry3DEngine/3DEngineLight.cpp
  97. 30 0
      Code/CryEngine/Cry3DEngine/3DEngineMemory.cpp
  98. 286 0
      Code/CryEngine/Cry3DEngine/3DEngineMemory.h
  99. 3957 0
      Code/CryEngine/Cry3DEngine/3DEngineRender.cpp
  100. 574 0
      Code/CryEngine/Cry3DEngine/3DEngine_Jobs.cpp

+ 57 - 0
.clang-format

@@ -0,0 +1,57 @@
+BasedOnStyle: Microsoft
+
+Language: Cpp
+Standard: c++17
+
+AccessModifierOffset: -4
+AlignAfterOpenBracket: AlwaysBreak
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Right
+AlignOperands: false
+AlignTrailingComments: false
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortFunctionsOnASingleLine: None
+AllowShortLambdasOnASingleLine: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakTemplateDeclarations: true
+BraceWrapping:
+    AfterClass: true
+    AfterEnum: true
+    AfterFunction: true
+    AfterNamespace: true
+    AfterStruct: true
+    SplitEmptyFunction: true
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeComma
+BreakInheritanceList: BeforeComma
+ColumnLimit: 140
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+FixNamespaceComments: true
+IncludeBlocks: Preserve
+IndentCaseLabels: false
+IndentPPDirectives: None
+IndentWidth: 4
+KeepEmptyLinesAtTheStartOfBlocks: false
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: All
+PenaltyReturnTypeOnItsOwnLine: 1000
+PointerAlignment: Left
+SortIncludes: true
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyParentheses: false
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+UseTab: Never

+ 9 - 0
.editorconfig

@@ -0,0 +1,9 @@
+root = true
+
+# all c++ files
+[*.{h,hpp,c,cpp,inl,hxx}]
+indent_style = space
+indent_size = 4
+charset = utf-8
+insert_final_newline = true
+trim_trailing_whitespace = true

+ 119 - 0
.gitattributes

@@ -0,0 +1,119 @@
+
+#
+# Git LFS (see https://git-lfs.github.com/)
+#
+*.3ds filter=lfs diff=lfs merge=lfs -text
+*.DLL filter=lfs diff=lfs merge=lfs -text
+*.FBX filter=lfs diff=lfs merge=lfs -text
+*.PDB filter=lfs diff=lfs merge=lfs -text
+*.PNG filter=lfs diff=lfs merge=lfs -text
+*.TGA filter=lfs diff=lfs merge=lfs -text
+*.TIF filter=lfs diff=lfs merge=lfs -text
+*.a filter=lfs diff=lfs merge=lfs -text
+*.abc filter=lfs diff=lfs merge=lfs -text
+*.actor filter=lfs diff=lfs merge=lfs -text
+*.adb filter=lfs diff=lfs merge=lfs -text
+*.akd filter=lfs diff=lfs merge=lfs -text
+*.animevents filter=lfs diff=lfs merge=lfs -text
+*.animgraph filter=lfs diff=lfs merge=lfs -text
+*.anm filter=lfs diff=lfs merge=lfs -text
+*.bin filter=lfs diff=lfs merge=lfs -text
+*.bmp filter=lfs diff=lfs merge=lfs -text
+*.bnk filter=lfs diff=lfs merge=lfs -text
+*.bspace filter=lfs diff=lfs merge=lfs -text
+*.cab filter=lfs diff=lfs merge=lfs -text
+*.caf filter=lfs diff=lfs merge=lfs -text
+*.cal filter=lfs diff=lfs merge=lfs -text
+*.cdf filter=lfs diff=lfs merge=lfs -text
+*.cfi filter=lfs diff=lfs merge=lfs -text
+*.cfr filter=lfs diff=lfs merge=lfs -text
+*.cfx filter=lfs diff=lfs merge=lfs -text
+*.cgf filter=lfs diff=lfs merge=lfs -text
+*.chr filter=lfs diff=lfs merge=lfs -text
+*.chrparams filter=lfs diff=lfs merge=lfs -text
+*.cld filter=lfs diff=lfs merge=lfs -text
+*.comb filter=lfs diff=lfs merge=lfs -text
+*.cry filter=lfs diff=lfs merge=lfs -text
+*.ctc filter=lfs diff=lfs merge=lfs -text
+*.dat filter=lfs diff=lfs merge=lfs -text
+*.dba filter=lfs diff=lfs merge=lfs -text
+*.dds filter=lfs diff=lfs merge=lfs -text
+*.dds.[0-9] filter=lfs diff=lfs merge=lfs -text
+*.dlg filter=lfs diff=lfs merge=lfs -text
+*.dll filter=lfs diff=lfs merge=lfs -text
+*.dmg filter=lfs diff=lfs merge=lfs -text
+*.dylib filter=lfs diff=lfs merge=lfs -text
+*.emfxrecording filter=lfs diff=lfs merge=lfs -text
+*.ent filter=lfs diff=lfs merge=lfs -text
+*.exe filter=lfs diff=lfs merge=lfs -text
+*.exr filter=lfs diff=lfs merge=lfs -text
+*.fbx filter=lfs diff=lfs merge=lfs -text
+*.fdp filter=lfs diff=lfs merge=lfs -text
+*.font filter=lfs diff=lfs merge=lfs -text
+*.fontfamily filter=lfs diff=lfs merge=lfs -text
+*.fsq filter=lfs diff=lfs merge=lfs -text
+*.fxl filter=lfs diff=lfs merge=lfs -text
+*.gfx filter=lfs diff=lfs merge=lfs -text
+*.gif filter=lfs diff=lfs merge=lfs -text
+*.grd filter=lfs diff=lfs merge=lfs -text
+*.i_caf filter=lfs diff=lfs merge=lfs -text
+*.icns filter=lfs diff=lfs merge=lfs -text
+*.ico filter=lfs diff=lfs merge=lfs -text
+*.ik filter=lfs diff=lfs merge=lfs -text
+*.img filter=lfs diff=lfs merge=lfs -text
+*.jar filter=lfs diff=lfs merge=lfs -text
+*.jpeg filter=lfs diff=lfs merge=lfs -text
+*.jpg filter=lfs diff=lfs merge=lfs -text
+*.lib filter=lfs diff=lfs merge=lfs -text
+*.lmg filter=lfs diff=lfs merge=lfs -text
+*.lut filter=lfs diff=lfs merge=lfs -text
+*.ly filter=lfs diff=lfs merge=lfs -text
+*.ma filter=lfs diff=lfs merge=lfs -text
+*.max filter=lfs diff=lfs merge=lfs -text
+*.mb filter=lfs diff=lfs merge=lfs -text
+*.mkv filter=lfs diff=lfs merge=lfs -text
+*.motion filter=lfs diff=lfs merge=lfs -text
+*.motionset filter=lfs diff=lfs merge=lfs -text
+*.mov filter=lfs diff=lfs merge=lfs -text
+*.mp2 filter=lfs diff=lfs merge=lfs -text
+*.mp3 filter=lfs diff=lfs merge=lfs -text
+*.mp4 filter=lfs diff=lfs merge=lfs -text
+*.msi filter=lfs diff=lfs merge=lfs -text
+*.node filter=lfs diff=lfs merge=lfs -text
+*.npz filter=lfs diff=lfs merge=lfs -text
+*.ocm filter=lfs diff=lfs merge=lfs -text
+*.ogg filter=lfs diff=lfs merge=lfs -text
+*.otf filter=lfs diff=lfs merge=lfs -text
+*.pak filter=lfs diff=lfs merge=lfs -text
+*.pcm filter=lfs diff=lfs merge=lfs -text
+*.pdb filter=lfs diff=lfs merge=lfs -text
+*.pdf filter=lfs diff=lfs merge=lfs -text
+*.pkat filter=lfs diff=lfs merge=lfs -text
+*.pkfx filter=lfs diff=lfs merge=lfs -text
+*.pkmm filter=lfs diff=lfs merge=lfs -text
+*.png filter=lfs diff=lfs merge=lfs -text
+*.ppm filter=lfs diff=lfs merge=lfs -text
+*.prototype filter=lfs diff=lfs merge=lfs -text
+*.psd filter=lfs diff=lfs merge=lfs -text
+*.pxheightfield filter=lfs diff=lfs merge=lfs -text
+*.pxmesh filter=lfs diff=lfs merge=lfs -text
+*.sbs filter=lfs diff=lfs merge=lfs -text
+*.sbsar filter=lfs diff=lfs merge=lfs -text
+*.sfo filter=lfs diff=lfs merge=lfs -text
+*.skin filter=lfs diff=lfs merge=lfs -text
+*.smtl filter=lfs diff=lfs merge=lfs -text
+*.so filter=lfs diff=lfs merge=lfs -text
+*.sprite filter=lfs diff=lfs merge=lfs -text
+*.sub filter=lfs diff=lfs merge=lfs -text
+*.tga filter=lfs diff=lfs merge=lfs -text
+*.tif filter=lfs diff=lfs merge=lfs -text
+*.tiff filter=lfs diff=lfs merge=lfs -text
+*.trp filter=lfs diff=lfs merge=lfs -text
+*.ttf filter=lfs diff=lfs merge=lfs -text
+*.usm filter=lfs diff=lfs merge=lfs -text
+*.veg filter=lfs diff=lfs merge=lfs -text
+*.wav filter=lfs diff=lfs merge=lfs -text
+*.webm filter=lfs diff=lfs merge=lfs -text
+*.wem filter=lfs diff=lfs merge=lfs -text
+*.wxs filter=lfs diff=lfs merge=lfs -text
+*.zip filter=lfs diff=lfs merge=lfs -text

+ 18 - 0
.gitignore

@@ -0,0 +1,18 @@
+.idea/
+.vscode/
+__pycache__
+AssetProcessorTemp/**
+build/**
+Cache/**
+Editor/EditorEventLog.xml
+Editor/EditorLayout.xml
+Tools/**/*egg-info/**
+Tools/**/*egg-link
+UserSettings.xml
+.idea/
+user/Registry/**
+FrameCapture/**
+.DS_Store
+
+#Output folder for test results when running Automated Tests
+TestResults/**

+ 2 - 0
.lfsconfig

@@ -0,0 +1,2 @@
+[lfs]
+url=https://d111jhwumogxnd.cloudfront.net/api/v1

+ 30 - 0
.p4ignore

@@ -0,0 +1,30 @@
+*.ilk
+*.suo
+*.user
+*.o
+*.temp
+*.bootstrap.digests
+*.log
+*.exp
+*.vssettings
+*.exportlog
+*.mayaSwatches
+*.ma.swatches
+*.bak
+*.bak2
+*.akd
+Solutions
+BinTemp
+*.options
+*.pyc
+*.db
+Cache
+AssetProcessor_tmp.exe
+Builders_Temp
+Bin64vc*
+$tmp*
+.pytest_cache
+__pycache__
+# Python Module egg file
+*.egg
+*.egg-link

+ 591 - 0
AssetProcessorPlatformConfig.ini

@@ -0,0 +1,591 @@
+; ---- Enable/Disable platforms for the entire project. AssetProcessor will automatically add the current platform by default. 
+
+; PLATFORM DEFINITIONS
+; [Platform (unique identifier)]
+; tags=(comma-seperated-tags)
+;
+; note:  the 'identifier' of a platform is the word(s) following the "Platform" keyword (so [Platform pc] means identifier
+;        is 'pc' for example.  This is used to name its assets folder in the cache and should be used in your bootstrap.cfg
+;        or your main.cpp to choose what assets to load for that particular platform.
+;        Its primary use is to enable additional non-host platforms (Ios, android...) that are not the current platform.
+; note:  'tags' is a comma-seperated list of tags to tag the platform with that builders can inspect to decide what to do.
+
+; while builders can accept any tags you add in order to make decisions, common tags are
+; tools - this platform can host the tools and editor and such
+; renderer - this platform runs the client engine and renders on a GPU.  If missing we could be on a server-only platform
+; mobile - a mobile platform such as a set top box or phone with limited resources
+; console - a console platform
+; server - a server platform of some kind, usually headless, no renderer.
+
+[Platform pc]
+tags=tools,renderer,dx12,vulkan
+
+[Platform es3]
+tags=android,mobile,renderer,vulkan
+
+[Platform ios]
+tags=mobile,renderer,metal
+
+[Platform osx_gl]
+tags=tools,renderer,metal
+
+; this is an example of a headless platform that has no renderer.   
+; To use this you would still need to make sure 'assetplatform' in your startup params in your main() chooses this 'server' platform as your server 'assets' flavor
+[Platform server]
+tags=server,dx12,vulkan
+
+; this section allows you to turn on various platforms in addition to the host platform you're running on
+; 'enabled' is AUTOMATICALLY TRUE for the current platform that you are running on, so it is not necessary to force it to true for that platform
+; To enable any additional platform, just uncomment the appropriate line below.
+
+[Platforms]
+;pc=enabled
+;es3=enabled
+;ios=enabled
+;osx_gl=enabled
+;xenia=enabled
+;jasper=enabled
+;provo=enabled
+;salem=enabled
+;server=enabled
+
+; ---- The number of worker jobs, 0 means use the number of Logical Cores
+[Jobs]
+minJobs=1
+maxJobs=0
+
+; cacheServerAddress is the location of the asset server cache.
+; Currently for a network share server this would be the absolute file path to the network share folder.  
+[Server]
+;cacheServerAddress=
+
+; ---- add any metadata file type here that needs to be monitored by the AssetProcessor.
+; Modifying these meta file will cause the source asset to re-compile again.
+; They are specified in the following format
+; metadata extension=original extension to replace
+; if the metadata extension does not replace the original, then the original can be blank
+; so for example if your normal file is blah.tif and your metafile for that file is blah.tif.exportsettings
+; then your declaration would be exportsettings=   ; ie, it would be blank
+; however if your metafile REPLACES the extension (for example, if you have the file blah.i_caf and its metafile is blah.exportsettings)
+; then you specify the original extension here to narrow the scope.
+; If a relative path to a specific file is provided instead of an extension, a change to the file will change all files
+; with the associated extension (e.g. Animations/SkeletonList.xml=i_caf will cause all i_caf files to recompile when 
+; Animations/SkeletonList.xml within the current game project changes)
+
+[MetaDataTypes]
+exportsettings=
+animsettings=i_caf
+Animations/SkeletonList.xml=i_caf
+cbc=abc
+fbx.assetinfo=fbx
+
+; ---- add any folders to scan here.  The priority order is the order they appear here
+; available macros are 
+; @ROOT@ - the location of engineroot.txt
+; @GAMENAME@ - the name of the current game project, for example 'RPGSample' 
+; note that they are sorted by their 'order' value, and the lower the order the more important an asset is
+; lower order numbers override higher ones.
+; If specified, output will be prepended to every path found in that recognizer's watch folder.
+; Note that you can also make the scan folder platform specific by using the keywords include and exclude.
+; Both include and exclude can contain either platform tags, platform identifiers or both.
+; if no include is specified, all currently enabled platforms are included by default.
+; If includes ARE specified, it will be filtered down by the list of currently enabled platforms. 
+; [ScanFolder (unique identifier)]
+; include = (comma seperated platform tags or identifiers)
+; exclude = (comma seperated platform tags or identifiers)
+; For example if you want to include a scan folder only for platforms that have the platform tags tools and renderer 
+; but omit it for platform osx_gl, you will have a scanfolder rule like
+; [ScanFolder (unique identifier)]
+; watch=@ROOT@/foo
+; include = tools, renderer
+; exclude = osx_gl 
+
+[ScanFolder Game]
+watch=@ROOT@/@GAMENAME@
+display=@GAMENAME@
+recursive=1
+order=0
+
+; gems will be auto-added from 100 onwards
+
+[ScanFolder Root]
+watch=@ROOT@
+recursive=0
+order=10000
+
+[ScanFolder Engine]
+watch=@ENGINEROOT@/Engine
+recursive=1
+order=20000
+
+[ScanFolder Editor]
+watch=@ENGINEROOT@/Editor
+output=editor
+recursive=1
+order=30000
+include=tools,renderer
+
+
+;Excludes files that match the pattern or glob 
+; if you use a pattern, remember to escape your backslashes (\\)
+[Exclude _LevelBackups]
+pattern=.*\\/Levels\\/.*\\/_savebackup\\/.*
+
+[Exclude _LevelAutoBackups]
+pattern=.*\\/Levels\\/.*\\/_autobackup\\/.*
+
+[Exclude HoldFiles]
+pattern=.*\\/Levels\\/.*_hold\\/.*
+
+[Exclude TempFiles]
+; note that $ has meaning to regex, so we escape it.
+pattern=.*\\/\\$tmp[0-9]*_.*
+
+[Exclude AlembicCompressionTemplates]
+pattern=.*\\/Presets\\/GeomCache\\/.*
+
+[Exclude TmpAnimationCompression]
+pattern=.*\\/Editor\\/Tmp\\/AnimationCompression\\/.*
+
+[Exclude EventLog]
+pattern=.*\\/Editor\\/.*eventlog\\.xml
+
+[Exclude GameGemsCode]
+pattern=.*\\/Gem\\/Code\\/.*
+
+[Exclude GameGemsResources]
+pattern=.*\\/Gem\\/Resources\\/.*
+
+[Exclude Private Certs]
+pattern=.*\DynamicContent\\/Certificates\\/Private\\/.*
+
+[Exclude CMakeLists]
+pattern=.*\\/CMakeLists.txt
+
+[Exclude CMakeFiles]
+pattern=.*\\/.*\\.cmake
+
+;------------------------------------------------------------------------------
+; Large Worlds Test
+;------------------------------------------------------------------------------
+
+[Exclude Work In Progress Folders]
+pattern=.*\\/WIP\\/.*
+
+[Exclude Content Source Folders]
+pattern=.*\\/CONTENT_SOURCE\\/.*
+
+[Exclude Art Source Folders]
+pattern=.*\\/ArtSource\\/.*
+
+;------------------------------------------------------------------------------
+; RC params mapping examples
+;------------------------------------------------------------------------------
+
+; note that productAssetType is a means of setting the output asset Type (as in AZ::Data::AssetType) of a simple job
+; and is the recommended way to specify that a certain kind of file (such as '*.myextension') becomes registered as the
+; actual UUID of that type in the engine itself.
+
+; Use a regex for matching files, same params for all platforms
+;[RC TGAs]
+;pattern=.+\\.tga$
+;params=/tga /texture
+
+; Use a glob, have special params for es3 platform
+;[RC TIFFs]
+;glob=*.tif
+;params=/texture
+;es3=/pvrt
+
+; You can also modify a version to compile all matching files again
+; By default the version is empty
+;[RC tif]
+;glob=*.tif
+;params = \\someparams
+;version =1.0
+; This will make the AssetProcessor compile all the .tif files again
+
+; you can also optionally supply a priority.
+; this is used to sort jobs when no other external circumstance sorts them
+; for example, copy jobs will be higher in priority than other jobs that are not copy jobs
+; however if they're both copy jobs or both not, and no other circumstances apply, then priority will be used.
+; default priority is zero if not specified
+
+; you can specify an option to skip processing for a file type based on the platform.
+; for example, if you dont want to process tif files for ios, you can make tif files
+; process on any platform except for ios:
+;[RC tif]
+;glob=*.tif
+;params = \\someparams
+;ios=skip
+
+; you can specify an option to output product dependencies for a copy job.
+; please note that you only need to set this option when cry code is required to parse the asset.
+; otherwise product dependencies will be output automatically by the CopyDependencyBuilder.
+; for example, if you want to output the product dependencies for font assets:
+;[RC font]
+;glob=*.font
+;params=copy
+;outputProductDependencies=true
+
+; you can also specify an option to make all jobs critical that matches some pattern/glob.
+; for example, if you want to make all png files critical than set critical to true.
+; Note that by default all copy jobs are critical.
+; Critical jobs are processed before non critical jobs and also prevent the runtime or editor from starting until they are all complete.
+;[RC png]
+;glob=*.png
+;params = \\someparams
+;critical=true
+
+; you can also specify an option to make all the job store in the asset server cache location if you are running AP in server mode. 
+; For example, if you want to store all png jobs in the asset server cache location including their logs, you can set checkServer = true.
+; The client(i.e if you are running AP in non-server mode) will also check for this flag to know which jobs to fetch from the asset server cache location.
+; if unsucessful, it will process the job locally as usual.
+;[RC png]
+;glob=*.png
+;params = \\someparams
+;critical=true
+;checkServer=true
+
+; note that the FULL PATH to the file will be used as the match, not the relative path
+; so ensure start your patterns with .* or as appropriate.
+; Also, any rules which match will apply - so if you have two rules which both apply to PNG files for example
+; but you only want one, you might want to use exclusion patterns:
+ 
+;Example: process everything EXCEPT the ones in the libs/ui folder with these params
+;[RC png-normal]
+;pattern=(?!.*libs\\/ui\\/).*\\.png
+;params=/imagecompressor=CTSquish /streaming=0
+;lockSource=true
+
+;Example:  Process everything in the libs/ui folder with linear color space
+;[RC png-ui]
+;pattern=(.*libs\\/ui\\/).*\\.png
+;params=/imagecompressor=CTSquish /streaming=0 /colorspace=linear,linear
+;lockSource=true
+
+; More example Regexes:
+; pattern=(?!(.*libs\\/ui\\/)|(.*editor\\/).*\\.png
+; This pattern will not match anything with editor/ or libs/ui/ in it
+; pattern=((.*libs\\/ui\\/)|(.*editor\\/).*\\.png
+; This pattern will only match anything with editor/ or libs/ui/ in it
+
+;Give every [Section Name] its own unique Name or else they will overwrite each other!
+
+[RC i_caf]
+glob=*.i_caf
+params=/cafAlignTracks=1 /animConfigFolder=Animations /skipdba=1 /refresh=1
+; force server to send the 'pc' platform to RC.EXE so it compiles the same as PC.
+server=/cafAlignTracks=1 /animConfigFolder=Animations /skipdba=1 /refresh=1 /p=pc
+priority=5
+productAssetType={6023CFF8-FCBA-4528-A8BF-6E0E10B9AB9C}
+
+[RC caf]
+glob=*.caf
+params=copy
+productAssetType={6023CFF8-FCBA-4528-A8BF-6E0E10B9AB9C}
+; same as above
+
+[RC mp4]
+glob=*.mp4
+params=copy
+productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF}
+
+[RC mkv]
+glob=*.mkv
+params=copy
+productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF}
+; same as above
+
+[RC webm]
+glob=*.webm
+params=copy
+productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF}
+; same as above
+
+[RC mov]
+glob=*.mov
+params=copy
+productAssetType={DDFEE0B2-9E5A-412C-8C77-AB100E24C1DF}
+; same as above
+
+[RC bk2]
+glob=*.bk2
+params=copy
+productAssetType={BF4879B9-B893-41D2-80E9-24A7BDCD2B50}
+
+[RC img]
+glob=*.img
+params=copy
+
+[RC dba]
+glob=*.dba
+params=copy
+productAssetType={511562BE-65A5-4538-A5F1-AC685366243E}
+version=2
+
+[RC cgf]
+glob=*.cgf
+params=/VertexPositionFormat=exporter /VertexIndexFormat=u32
+; on server, feed rc.exe the param /p=pc to force it to compile assets for server platform in pc format.
+server=/VertexPositionFormat=exporter /VertexIndexFormat=u32 /p=pc
+lockSource=true
+priority=10
+; allow CGF files to compile first, so untextured models appear before their textures for faster startup
+; other available params: /SplitLODs=1
+
+[RC surfaceTagNameList]
+glob=*.surfaceTagNameList
+params=copy
+productAssetType={A471B2A9-85FC-4993-842D-1881CBC03A2B}
+
+[RC gradImageSettings]
+glob=*.gradimagesettings
+params=copy
+productAssetType={B36FEB5C-41B6-4B58-A212-21EF5AEF523C}
+
+[RC fbx]
+glob=*.fbx
+; Priority set to 9 so its "before" things like materials but after things like actors and motions (which build using a proper AssetBuilderSDK builder and thus are not in this file)
+priority=9
+version=5
+
+[RC chr]
+glob=*.chr
+params=copy
+productAssetType={60161B46-21F0-4396-A4F0-F2CCF0664CDE}
+version=2
+
+[RC skin]
+glob=*.skin
+params=copy
+
+[RC cfi]
+glob=*.cfi
+params=copy
+
+[RC cfx]
+glob=*.cfx
+params=copy
+
+[RC cfr]
+glob=*.cfr
+params=copy
+
+; Warning: If you change the VertexIndexFormat, make sure you update the vtx_idx typedef in Code\CryEngine\CryCommon\ProjectDefines.h
+[RC abc]
+glob=*.abc
+params=/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u32
+console=/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u32
+mobile=/SkipFilesWithoutBuildConfig=0 /VertexIndexFormat=u16
+version=3
+server=skip
+
+[RC png-entityicon]
+pattern=(.*EntityIcons\\/).*\\.png
+productAssetType={3436C30E-E2C5-4C3B-A7B9-66C94A28701B}
+params=skip ; only tools-supporting platforms should copy this file.  Everyone else can skip.
+tools=copy
+
+[RC usm]
+glob=*.usm
+params=copy
+server=skip
+
+[RC animevents]
+glob=*.animevents
+params=copy
+productAssetType={C1D209C1-F81A-4586-A34E-1615995F9F3F}
+version=2
+
+[RC adb]
+glob=*.adb
+params=copy
+productAssetType={50908273-CA36-4668-9828-15DD5092F973}
+
+[RC bspace]
+glob=*.bspace
+params=copy
+
+[RC cdf]
+glob=*.cdf
+params=copy
+productAssetType={DF036C63-9AE6-4AC3-A6AC-8A1D76126C01}
+; note - this used to be skinnedMeshAsset but its now Character Definition File specific.
+; .skin has its own type.
+
+[RC chrparams]
+glob=*.chrparams
+params=copy
+productAssetType={4BBB785A-6824-4803-A607-F9323E7BEEF1}
+version=2
+
+[RC comb]
+glob=*.comb
+params=copy
+
+[RC dlg]
+glob=*.dlg
+params=copy
+
+[RC csv]
+glob=*.csv
+params=copy
+
+[RC json]
+glob=*.json
+params=copy
+
+[RC lmg]
+glob=*.lmg
+params=copy
+
+[RC smtl]
+glob=*.smtl
+params=copy
+
+[RC sub]
+glob=*.sub
+params=copy
+productAssetType={71F9D30E-13F7-40D6-A3C9-E5358004B31F}
+version=2
+
+[RC sbsar]
+glob=*.sbsar
+params=copy
+
+[RC loc.agsxml]
+glob=*.loc.agsxml
+params=copy
+version=1
+
+[RC node]
+glob=*.node
+params=copy
+
+[RC veg]
+glob=*.veg
+params=copy
+
+[RC dat]
+glob=*.dat
+params=copy
+
+[RC lut]
+glob=*.lut
+params=copy
+
+[RC txt]
+pattern=^(?!.*PreloadLibs.txt).*\\.txt
+params=copy
+
+[RC cal]
+glob=*.cal
+params=copy
+
+[RC grp]
+glob=*.grp
+params=copy
+productAssetType={7629EDD3-A361-49A2-B271-252127097D81}
+version=2
+
+[RC xls]
+glob=*.xls
+params=copy
+
+[RC ini]
+glob=*.ini
+params=copy
+
+[RC ttf]
+glob=*.ttf
+params=copy
+
+[RC otf]
+glob=*.otf
+params=copy
+
+[RC ext]
+glob=*.ext
+params=copy
+
+[RC pak]
+; Copy all pak files except level.pak, level.pak has its own builder.
+pattern=^((?!\\/level\\.pak).)*\\.pak$
+params=copy
+
+[RC ctc]
+glob=*.ctc
+params=copy
+
+[RC uiprefab]
+glob=*.uiprefab
+params=copy
+server=skip
+
+[RC sprite]
+glob=*.sprite
+params=copy
+server=skip
+
+[RC bin]
+glob=*.bin
+params=copy
+
+[RC inputbindings]
+glob=*.inputbindings
+params=copy
+productAssetType={25971C7A-26E2-4D08-A146-2EFCC1C36B0C}
+
+[RC physmaterial]
+glob=*.physmaterial
+params=copy
+productAssetType={9E366D8C-33BB-4825-9A1F-FA3ADBE11D0F}
+
+[RC ocm]
+glob=*.ocm
+params=copy
+
+; Feature tests use the raw .tif files for the golden image comparison
+[RC goldenimages]
+pattern=.*GoldenImages\\/.*\\.tif
+params=copy 
+server=skip
+
+; Copy over certificates for use with FileDataSource
+[RC CertificatePEM]
+glob=*.pem
+params=copy
+
+; Copy over certificates for use with Dynamic Content
+[RC CertificateDER]
+glob=*.der
+params=copy
+
+[RC PhysXMeshAsset]
+glob=*.pxmesh
+params=copy
+productAssetType={7A2871B9-5EAB-4DE0-A901-B0D2C6920DDB}
+
+; Copy over cooked PhysX heightfield
+[RC PhysX HeightField]
+glob=*.pxheightfield
+params=copy
+productAssetType={B61189FE-B2D7-4AF1-8951-CB5C0F7834FC}
+
+[RC filetag]
+glob=*.filetag
+params=copy
+productAssetType={F3BE5CAB-85B7-44B7-9495-863863F6B267}
+
+; Precompiled shader srg
+[RC azsrg]
+glob=*.azsrg
+params=copy
+productAssetType={F8C9F4AE-3F6A-45AD-B4FB-0CA415FCC2E1}
+
+; Precompiled shader variant
+[RC azshadervariant]
+glob=*.azshadervariant
+params=copy
+productAssetType={9F4D654B-4439-4C61-8DCD-F1C7C5560768}

+ 530 - 0
AutomatedReview/Jenkinsfile

@@ -0,0 +1,530 @@
+#!/usr/bin/env groovy
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+
+PIPELINE_CONFIG_FILE = 'AutomatedReview/lumberyard.json'
+INCREMENTAL_BUILD_SCRIPT_PATH = "scripts/build/bootstrap/incremental_build_util.py"
+
+def pipelineProperties = []
+
+def pipelineParameters = [
+    // Build/clean Parameters
+    // The CLEAN_OUTPUT_DIRECTORY is used by ci_build scripts. Creating the parameter here passes it as an environment variable to jobs and is consumed that way
+    booleanParam(defaultValue: false, description: 'Deletes the contents of the output directory before building. This will cause a \"clean\" build', name: 'CLEAN_OUTPUT_DIRECTORY'),
+    booleanParam(defaultValue: false, description: 'Deletes the contents of the workspace and forces a complete pull.', name: 'CLEAN_WORKSPACE'),
+    booleanParam(defaultValue: false, description: 'Recreates the volume used for the workspace. The volume will be created out of a snapshot taken from main.', name: 'RECREATE_VOLUME'),  
+    string(defaultValue: '', description: 'Filters and overrides the list of jobs to run for each of the below platforms (comma-separated). Can\'t be used during a pull request.', name: "JOB_LIST_OVERRIDE"),
+
+    // Pull Request Parameters
+    string(defaultValue: '', description: '', name: 'DESTINATION_BRANCH'),
+    string(defaultValue: '', description: '', name: 'DESTINATION_COMMIT'),
+    string(defaultValue: '', description: '', name: 'PULL_REQUEST_ID'),
+    string(defaultValue: '', description: '', name: 'REPOSITORY_NAME'),
+    string(defaultValue: '', description: '', name: 'SOURCE_BRANCH'),
+    string(defaultValue: '', description: '', name: 'SOURCE_COMMIT')
+]
+
+def palSh(cmd, lbl = '') {
+    if (env.IS_UNIX) {
+        sh label: lbl,
+           script: cmd
+    } else { 
+        bat label: lbl,
+            script: cmd.replace('/','\\')
+    }
+}
+
+def palMkdir(path) {
+    if (env.IS_UNIX) {
+        sh label: "Making directories ${path}",
+           script: "mkdir -p ${path}"
+    } else {
+        def win_path = path.replace('/','\\')
+        bat label: "Making directories ${win_path}",
+            script: "mkdir ${win_path}."
+    }
+}
+
+def palRm(path) {
+    if (env.IS_UNIX) {
+        sh label: "Removing ${path}",
+           script: "rm ${path}"
+    } else {
+        def win_path = path.replace('/','\\')
+        bat label: "Removing ${win_path}",
+            script: "del ${win_path}"
+    }
+}
+
+def palRmDir(path) {
+    if (env.IS_UNIX) {
+        sh label: "Removing ${path}",
+           script: "rm -rf ${path}"
+    } else {
+        def win_path = path.replace('/','\\')
+        bat label: "Removing ${win_path}",
+            script: "rd /s /q ${win_path}"
+    }
+}
+
+def GetJobListOverride() {
+    if(params.PULL_REQUEST_ID) {
+        return ''
+    } else {
+        return params.JOB_LIST_OVERRIDE
+    }
+}
+
+def GetRunningPipelineName(JENKINS_JOB_NAME) {
+    // If the job name has an underscore
+    def job_parts = JENKINS_JOB_NAME.tokenize('/')[0].tokenize('_')
+    if (job_parts.size() > 1) {
+        return job_parts[job_parts.size()-1]
+    }
+    return "default"
+}
+
+def LoadPipelineConfig(String pipelineConfigFile, String branchName) {
+    echo 'Loading pipeline config'
+    PullFilesFromGit(pipelineConfigFile, branchName)
+    def pipelineConfig = readJSON file: "${pipelineConfigFile}"
+    // Load the pipeline configs per platform
+    pipelineConfig.PIPELINE_CONFIGS.each { pipeline_config ->
+        def platform_regex = pipeline_config.replace('.','\\.').replace('*', '(.*)')
+        if (!env.IS_UNIX) {
+            platform_regex = platform_regex.replace('/','\\\\')
+        }
+        echo "Downloading platform pipeline configs ${pipeline_config}"
+        PullFilesFromGit(pipeline_config, branchName)
+        echo "Searching platform pipeline configs in ${pipeline_config} using ${platform_regex}"
+        for (pipeline_config_path in findFiles(glob: pipeline_config)) {
+            echo "\tFound platform pipeline config ${pipeline_config_path}"
+            def platform = RegexMatcher(pipeline_config_path, platform_regex)
+            if(platform) {
+                pipelineConfig.platforms[platform] = readJSON file: "${pipeline_config_path}"
+            }
+        }
+    }
+    return pipelineConfig
+}
+
+def GetPipelineRegion() {
+    def gitUrl = scm.getUserRemoteConfigs()[0].getUrl()
+    def gitUrlList = gitUrl.tokenize('.') as String[]
+    def pipelineRegion = gitUrlList[1]
+    return pipelineRegion
+}
+
+def SetBuildEnvVars(Map platformConfig, String type, String branchName) {
+    // Returns list of build env vars
+    def envVarList = []
+    platformConfig.each { config ->
+        envVarList.add("${config.key}=${config.value}")
+    }
+    envVarList.add("JOB_NAME=${branchName}_${platformConfig.JOB_NAME}_${type}")
+    if(isUnix()) {
+        envVarList.add("IS_UNIX=1")
+    }
+    return envVarList
+}
+
+@NonCPS
+def RegexMatcher(str, regex) {
+    def matcher = (str =~ "${regex}")
+    return matcher ? matcher.group(1) : null
+}
+
+def LoadPlatformBuildConfigs(Map options, String pipelineName, String branchName) {
+    echo 'Loading build configs'
+    def buildTypes = [:]
+    options.BUILD_CONFIGS.each { build_config ->
+        def platform_regex = build_config.replace('.','\\.').replace('*', '(.*)')
+        if (!env.IS_UNIX) {
+            platform_regex = platform_regex.replace('/','\\\\')
+        }
+        echo "Downloading configs ${build_config}"
+        PullFilesFromGit(build_config, branchName)
+        echo "Searching configs in ${build_config} using ${platform_regex}"
+        for (build_config_path in findFiles(glob: build_config)) {
+            echo "\tFound config ${build_config_path}"
+            def platform = RegexMatcher(build_config_path, platform_regex)
+            if(platform) {
+                def buildConfig = readJSON file: "${build_config_path}"
+                def types = []
+                buildConfig.each { type ->
+                    if(GetJobListOverride()) {
+                        echo "\t\tAdding build type \"${type.key}\" to \"${pipelineName}\" because JOB_LIST_OVERRIDE was defined"
+                        types.add(type.key)
+                    } else if(type.value.TAGS) {
+                        type.value.TAGS.each { tag ->
+                            if(tag == pipelineName) {
+                                echo "\t\tAdding build type \"${type.key}\" to \"${tag}\""
+                                types.add(type.key)
+                            }
+                        }
+                    }
+                }
+                buildTypes[platform] = types
+            }
+        }
+    }
+    return buildTypes
+}
+
+// Pulls/downloads files from the repo through codecommit. Despite Glob matching is NOT supported, '*' is supported
+// as a folder or filename (not a portion, it has to be the whole folder or filename)
+def PullFilesFromGit(String filenamePath, String branchName, boolean failIfNotFound = true, String repositoryName = env.DEFAULT_REPOSITORY_NAME) {
+    echo "PullFilesFromGit filenamePath=${filenamePath} branchName=${branchName}"
+    def folderPathParts = filenamePath.tokenize('/')
+    def filename = folderPathParts[folderPathParts.size()-1]
+    folderPathParts.remove(folderPathParts.size()-1) // remove the filename
+    def folderPath = folderPathParts.join('/')
+    if (folderPath.contains('*')) {
+        
+        def currentPath = ""
+        for (int i = 0; i < folderPathParts.size(); i++) {
+            if (folderPathParts[i] == '*') {
+                palMkdir(currentPath)
+                retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${currentPath} > ${currentPath}/.codecommit", "GetFolder ${currentPath}") }
+                def folderInfo = readJSON file: "${currentPath}/.codecommit"
+                folderInfo.subFolders.each { folder ->
+                    def newSubPath = currentPath + '/' + folder.relativePath
+                    for (int j = i+1; j < folderPathParts.size(); j++) {
+                        newSubPath = newSubPath + '/' + folderPathParts[j]
+                    }
+                    newSubPath = newSubPath + '/' + filename
+                    PullFilesFromGit(newSubPath, branchName, false, repositoryName)
+                }
+                palRm("${currentPath}/.codecommit")
+            }
+            if (i == 0) {
+                currentPath = folderPathParts[i]
+            } else {
+                currentPath = currentPath + '/' + folderPathParts[i]
+            }
+        }
+
+    } else if (filename.contains('*')) {
+
+        palMkdir(folderPath)
+        retry(3) { palSh("aws codecommit get-folder --repository-name ${repositoryName} --commit-specifier ${branchName} --folder-path ${folderPath} > ${folderPath}/.codecommit", "GetFolder ${folderPath}") }
+        def folderInfo = readJSON file: "${folderPath}/.codecommit"
+        folderInfo.files.each { file ->
+            PullFilesFromGit("${folderPath}/${filename}", branchName, false, repositoryName)
+        }
+        palRm("${folderPath}/.codecommit")
+
+    } else {
+
+        def errorFile = "${folderPath}/error.txt" 
+        palMkdir(folderPath)
+        retry(3) {
+            try {
+                if(env.IS_UNIX) {
+                    sh label: "Downloading ${filenamePath}",
+                       script: "aws codecommit get-file --repository-name ${repositoryName} --commit-specifier ${branchName} --file-path ${filenamePath} --query fileContent --output text 2>${errorFile} > ${filenamePath}_encoded"
+                    sh label: "Decoding",
+                       script: "base64 --decode ${filenamePath}_encoded > ${filenamePath}"
+                } else {
+                    errorFile = errorFile.replace('/','\\')
+                    win_filenamePath = filenamePath.replace('/', '\\')
+                    bat label: "Downloading ${win_filenamePath}",
+                        script: "aws codecommit get-file --repository-name ${repositoryName} --commit-specifier ${branchName} --file-path ${filenamePath} --query fileContent --output text 2>${errorFile} > ${win_filenamePath}_encoded"
+                    bat label: "Decoding",                            
+                        script: "certutil -decode ${win_filenamePath}_encoded ${win_filenamePath}"
+                }
+                palRm("${filenamePath}_encoded")
+            } catch (Exception ex) {
+                def error = ''
+                if(fileExists(errorFile)) {
+                    error = readFile errorFile
+                }
+                if (!error || !(!failIfNotFound && error.contains("FileDoesNotExistException"))) {
+                    palRm("${errorFile} ${filenamePath}.encoded ${filenamePath}")
+                    throw new Exception("Could not get file: ${filenamePath}, ex: ${ex}, stderr: ${error}")
+                }
+            }
+            palRm(errorFile)
+        }
+    }
+}
+
+def CheckoutRepo(boolean disableSubmodules = false) {
+    def random = new Random()
+    def retryAttempt = 0
+    retry(5) {
+        if (retryAttempt > 0) {
+            sleep random.nextInt(60 * retryAttempt)  // Stagger checkouts to prevent HTTP 429 (Too Many Requests) response from CodeCommit
+        }
+        retryAttempt = retryAttempt + 1
+        if(params.PULL_REQUEST_ID) {
+            // This is a pull request build. Perform merge with destination branch before building.
+            checkout scm: [
+                $class: 'GitSCM',
+                branches: scm.branches,
+                extensions: [
+                    [$class: 'PreBuildMerge', options: [mergeRemote: 'origin', mergeTarget: params.DESTINATION_BRANCH]],
+                    [$class: 'SubmoduleOption', disableSubmodules: disableSubmodules, recursiveSubmodules: true],
+                    [$class: 'CheckoutOption', timeout: 60]
+                ],
+                userRemoteConfigs: scm.userRemoteConfigs
+            ]
+        } else {
+            checkout scm: [
+                $class: 'GitSCM',
+                branches: scm.branches,
+                extensions: [
+                    [$class: 'SubmoduleOption', disableSubmodules: disableSubmodules, recursiveSubmodules: true],
+                    [$class: 'CheckoutOption', timeout: 60]
+                ],
+                userRemoteConfigs: scm.userRemoteConfigs
+            ]
+        }
+    }
+}
+
+def SendEmailNotification() {
+    // Email notification
+    node('controller') {
+        step([
+            $class: 'Mailer',
+            notifyEveryUnstableBuild: true,
+            sendToIndividuals: true,
+            recipients: emailextrecipients([
+                [$class: 'CulpritsRecipientProvider'],
+                [$class: 'RequesterRecipientProvider']
+            ])
+        ])
+    }
+}
+
+def PreBuildCommonSteps(String pipeline, String branchName, String platform, String buildType, String workspace, boolean mount = true, boolean disableSubmodules = false) {
+    echo 'Starting pre-build common steps...'
+
+    if (mount) {
+        PullFilesFromGit(INCREMENTAL_BUILD_SCRIPT_PATH, branchName)
+
+        def pythonCmd = ""
+        if(env.IS_UNIX) pythonCmd = "sudo -E python -u "
+        else pythonCmd = "python -u "
+
+        if(params.RECREATE_VOLUME) {
+            palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action delete --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Deleting volume')
+        }
+        timeout(5) {
+            palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action mount --pipeline ${pipeline} --branch ${branchName} --platform ${platform} --build_type ${buildType}", 'Mounting volume')
+        }
+
+        if(env.IS_UNIX) {
+            sh label: 'Setting volume\'s ownership',
+               script: """
+                if sudo test ! -d "${workspace}"; then
+                    sudo mkdir -p ${workspace} 
+                    cd ${workspace}/..
+                    sudo chown -R lybuilder:root .
+                fi
+               """
+        }
+    }
+    if(params.CLEAN_WORKSPACE) {
+        palRmDir("${workspace}")
+    }
+
+    dir(workspace) {
+    
+        if(fileExists(".git")) {
+            palSh("""
+                git remote prune origin
+                git reset --hard HEAD
+                """, 'Git reset')
+        }
+
+        CheckoutRepo(disableSubmodules)
+
+        // If the repository after checkout is locked, likely we took a snapshot while git was running,
+        // to leave the repo in a usable state, garbagecollect
+        if(fileExists(".git/index.lock")) {
+            palSh('git gc', 'Git GarbageCollect')
+        }
+
+        palSh('git rev-parse HEAD > commitid', 'Getting commit id')
+        env.CHANGE_ID = readFile file: 'commitid'
+        env.CHANGE_ID = env.CHANGE_ID.trim()
+        palRm('commitid')
+
+        // Get python
+        if(env.IS_UNIX) {
+            sh label: 'Getting python',
+               script: 'python/get_python.sh'
+        } else {
+            bat label: 'Getting python',
+                script: 'python/get_python.bat'
+        }
+    }
+}
+
+def Build(Map options, String platform, String type, String workspace) {
+    def command = "${options.BUILD_ENTRY_POINT} --platform ${platform} --type ${type}"
+    dir(workspace) {
+        if (env.IS_UNIX) {
+            sh label: "Running ${platform} ${type}",
+               script: "${options.PYTHON_DIR}/python.sh -u ${command}"
+        } else {
+            bat label: "Running ${platform} ${type}",
+                script: "${options.PYTHON_DIR}/python.cmd -u ${command}".replace('/','\\')
+        }
+    }
+}
+
+def PostBuildCommonSteps(String workspace, boolean mount = true) {
+    echo 'Starting post-build common steps...'
+
+    if(params.PULL_REQUEST_ID) {
+        dir(workspace) {
+            if(fileExists(".git")) {
+                palSh('git reset --hard HEAD', 'Discard PR merge, git reset')
+            }
+        }
+    }
+
+    if (mount) {
+        def pythonCmd = ""
+        if(env.IS_UNIX) pythonCmd = "sudo -E python -u "
+        else pythonCmd = "python -u "
+
+        try {
+            timeout(5) {
+                palSh("${pythonCmd} ${INCREMENTAL_BUILD_SCRIPT_PATH} --action unmount", 'Unmounting volume')
+            }
+        }
+        catch (e) {
+            // Incremental build script will reboot the node if the EBS detach fails
+            echo 'Node disconnected, error: \"${e}\", continuing...'
+        }
+    }
+}
+
+def pipelineName = ""
+def pipelineRegion = ""
+def branchName = ""
+def pipelineConfig = {}
+def buildTypes = {}
+
+// Start Pipeline
+try {
+    stage('Setup Pipeline') {
+        node('controller') {
+            def envVarList = []
+            if(isUnix()) {
+                envVarList.add("IS_UNIX=1")
+            }
+            withEnv(envVarList) {
+                timestamps {
+                    pipelineName = GetRunningPipelineName(env.JOB_NAME)
+                    pipelineRegion = GetPipelineRegion()
+
+                    if(env.BRANCH_NAME) {
+                        branchName = env.BRANCH_NAME
+                    } else {
+                        branchName = scm.branches[0].name // for non-multibranch pipelines
+                        env.BRANCH_NAME = branchName // so scripts that read this environment have it (e.g. incremental_build_util.py)
+                    }
+                    pipelineProperties.add(disableConcurrentBuilds())
+
+                    echo "Running \"${pipelineName}\" for \"${branchName}\", region: \"${pipelineRegion}\"..."
+
+                    // Load configs
+                    pipelineConfig = LoadPipelineConfig(PIPELINE_CONFIG_FILE, branchName)
+                    buildTypes = LoadPlatformBuildConfigs(pipelineConfig, pipelineName, branchName)
+     
+                    // Add each platform as a parameter that the user can disable if needed
+                    buildTypes.each { platform ->
+                        pipelineParameters.add(booleanParam(defaultValue: true, description: '', name: "${platform.key}"))
+                    }
+                    pipelineProperties.add(parameters(pipelineParameters))
+                    properties(pipelineProperties)
+                }    
+            }
+        }
+    }
+
+    if(env.BUILD_NUMBER == '1') {
+        // Exit pipeline early on the intial build. This allows Jenkins to load the pipeline for the branch and enables users 
+        // to select build parameters on their first actual build. See https://issues.jenkins.io/browse/JENKINS-41929
+        currentBuild.result = 'SUCCESS'
+        return
+    }
+
+    // Build and Post-Build Testing Stage
+    def buildConfigs = [:]
+    def job_list_override = GetJobListOverride().tokenize(',')
+
+    // Platform Builds run on EC2
+    buildTypes.each { platform ->
+        if (params["${platform.key}"]) {
+            def pipelinePlatformConfig = pipelineConfig.platforms["${platform.key}"]
+            if(pipelinePlatformConfig) {
+                platform.value.each { build_type ->
+                    if (job_list_override.isEmpty() || job_list_override.contains(build_type)) {
+                        buildConfigs["${pipelinePlatformConfig.JOB_NAME} [${build_type}]"] = {
+                            node("${pipelinePlatformConfig.LABEL}-${pipelineRegion}") {
+                                stage("${pipelinePlatformConfig.JOB_NAME} [${build_type}]") {
+                                    def envVars = SetBuildEnvVars(pipelinePlatformConfig, build_type, branchName)
+                                    withEnv(envVars) {
+                                        timeout(time: pipelinePlatformConfig.TIMEOUT, unit: 'MINUTES', activity: true) {
+                                            try {
+                                                PreBuildCommonSteps(pipelineName, branchName, platform.key, build_type,  pipelinePlatformConfig.WORKSPACE, pipelinePlatformConfig.MOUNT_VOLUME)
+                                                Build(pipelineConfig, platform.key, build_type, pipelinePlatformConfig.WORKSPACE)
+                                            }
+                                            catch (e) {
+                                                currentBuild.result = 'FAILURE'
+                                                throw e
+                                            }
+                                            finally {
+                                                PostBuildCommonSteps(pipelinePlatformConfig.WORKSPACE, pipelinePlatformConfig.MOUNT_VOLUME)
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }    
+            } else {
+                echo "[WARN] Could not find pipeline config for ${platform.key}, skipping platform"
+            }
+        }
+    }
+
+    timestamps {
+        stage('Build') {
+            parallel buildConfigs // Run parallel builds
+        }
+
+        echo 'All builds successful'
+        currentBuild.result = 'SUCCESS'
+    }
+}
+catch (e) {
+    currentBuild.result = 'FAILURE'
+    throw e
+}
+finally {
+    if(env.SNS_TOPIC) {
+        snsPublish(
+            topicArn:"${env.SNS_TOPIC}", 
+            subject:'Build Result', 
+            message:"${currentBuild.currentResult}:${params.REPOSITORY_NAME}:${params.SOURCE_BRANCH}:${params.SOURCE_COMMIT}:${params.DESTINATION_COMMIT}:${params.PULL_REQUEST_ID}:${BUILD_URL}:${params.RECREATE_VOLUME}:${params.CLEAN_OUTPUT_DIRECTORY}"
+        )
+    }
+    SendEmailNotification()
+}

+ 15 - 0
AutomatedReview/lumberyard.json

@@ -0,0 +1,15 @@
+{
+    "BUILD_ENTRY_POINT": "Tools/build/JenkinsScripts/build/ci_build.py",
+    "PIPELINE_CONFIGS": [
+        "Tools/build/JenkinsScripts/build/Platform/*/pipeline.json",
+        "restricted/*/Tools/build/JenkinsScripts/build/pipeline.json"
+    ],
+    "BUILD_CONFIGS": [
+        "Tools/build/JenkinsScripts/build/Platform/*/build_config.json",
+        "restricted/*/Tools/build/JenkinsScripts/build/build_config.json"
+    ],
+    "PYTHON_DIR": "python",
+    "SCRUBBING_PATH": "Tools/build/JenkinsScripts/build/scrubbing_job.py",
+    "VALIDATOR_PATH": "scripts/commit_validation/git_validate_branch.py",
+    "platforms": {}
+}

+ 55 - 0
BuildAtomSampleViewer_Paks_PC.bat

@@ -0,0 +1,55 @@
+@echo off
+
+REM 
+REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+REM its licensors.
+REM
+REM For complete copyright and license terms please see the LICENSE at the root of this
+REM distribution (the "License"). All use of this software is governed by the License,
+REM or, if provided, by the license below or the license accompanying this file. Do not
+REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM
+
+setlocal enabledelayedexpansion 
+
+set ORIGINALDIRECTORY=%cd%
+set MYBATCHFILEDIRECTORY=%~dp0
+cd "%MYBATCHFILEDIRECTORY%"
+
+REM Attempt to determine the best BinFolder for rc.exe and AssetProcessorBatch.exe
+call "%MYBATCHFILEDIRECTORY%\DetermineRCandAP.bat" SILENT
+
+REM If a bin folder was registered, validate the presence of the binfolder/rc/rc.exe
+IF ERRORLEVEL 1 (
+    ECHO unable to determine the locations of AssetProcessor and rc.exe.  Make sure that they are available or rebuild from source
+    EXIT /b 1
+)
+ECHO Detected binary folder at %MYBATCHFILEDIRECTORY%%BINFOLDER%
+
+echo ----- Processing Assets Using Asset Processor Batch ----
+.\%BINFOLDER%\AssetProcessorBatch.exe /gamefolder=AtomSampleViewer /platforms=pc
+IF ERRORLEVEL 1 GOTO AssetProcessingFailed
+
+echo ----- Creating Packages ----
+rem lowercase is intentional, since cache folders are lowercase on some platforms
+.\%BINFOLDER%\rc\rc.exe /job=%BINFOLDER%\rc\RCJob_Generic_MakePaks.xml /p=pc /game=atomsampleviewer
+IF ERRORLEVEL 1 GOTO RCFailed
+
+echo ----- Done -----
+cd "%ORIGINALDIRECTORY%"
+exit /b 0
+
+:RCFailed
+echo ---- RC PAK failed ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+:AssetProcessingFailed
+echo ---- ASSET PROCESSING FAILED ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+
+
+

+ 55 - 0
BuildAtomTest_Paks_PC.bat

@@ -0,0 +1,55 @@
+@echo off
+
+REM 
+REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+REM its licensors.
+REM
+REM For complete copyright and license terms please see the LICENSE at the root of this
+REM distribution (the "License"). All use of this software is governed by the License,
+REM or, if provided, by the license below or the license accompanying this file. Do not
+REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM
+
+setlocal enabledelayedexpansion 
+
+set ORIGINALDIRECTORY=%cd%
+set MYBATCHFILEDIRECTORY=%~dp0
+cd "%MYBATCHFILEDIRECTORY%"
+
+REM Attempt to determine the best BinFolder for rc.exe and AssetProcessorBatch.exe
+call "%MYBATCHFILEDIRECTORY%\DetermineRCandAP.bat" SILENT
+
+REM If a bin folder was registered, validate the presence of the binfolder/rc.exe
+IF ERRORLEVEL 1 (
+    ECHO unable to determine the locations of AssetProcessor and rc.exe.  Make sure that they are available or rebuild from source
+    EXIT /b 1
+)
+ECHO Detected binary folder at %MYBATCHFILEDIRECTORY%%BINFOLDER%
+
+echo ----- Processing Assets Using Asset Processor Batch ----
+.\%BINFOLDER%\AssetProcessorBatch.exe /gamefolder=AtomTest /platforms=pc
+IF ERRORLEVEL 1 GOTO AssetProcessingFailed
+
+echo ----- Creating Packages ----
+rem lowercase is intentional, since cache folders are lowercase on some platforms
+.\%BINFOLDER%\rc.exe /job=%MYBATCHFILEDIRECTORY%Code\Tools\RC\Config\rc\RCJob_Generic_MakePaks.xml /p=pc /game=atomtest
+IF ERRORLEVEL 1 GOTO RCFailed
+
+echo ----- Done -----
+cd "%ORIGINALDIRECTORY%"
+exit /b 0
+
+:RCFailed
+echo ---- RC PAK failed ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+:AssetProcessingFailed
+echo ---- ASSET PROCESSING FAILED ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+
+
+

+ 56 - 0
BuildCMakeTestbed_Paks_PC.bat

@@ -0,0 +1,56 @@
+@echo off
+
+REM 
+REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+REM its licensors.
+REM
+REM For complete copyright and license terms please see the LICENSE at the root of this
+REM distribution (the "License"). All use of this software is governed by the License,
+REM or, if provided, by the license below or the license accompanying this file. Do not
+REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM
+
+setlocal enabledelayedexpansion 
+
+set ORIGINALDIRECTORY=%cd%
+set MYBATCHFILEDIRECTORY=%~dp0
+cd "%MYBATCHFILEDIRECTORY%"
+
+REM Attempt to determine the best BinFolder for rc.exe and AssetProcessorBatch.exe
+call "%MYBATCHFILEDIRECTORY%\DetermineRCandAP.bat" SILENT
+
+REM If a bin folder was registered, validate the presence of the binfolder/rc.exe
+IF ERRORLEVEL 1 (
+    ECHO unable to determine the locations of AssetProcessor and rc.exe.  Make sure that they are available or rebuild from source
+    EXIT /b 1
+)
+ECHO Detected binary folder at %MYBATCHFILEDIRECTORY%%BINFOLDER%
+
+echo ----- Processing Assets Using Asset Processor Batch ----
+.\%BINFOLDER%\AssetProcessorBatch.exe /gamefolder=CMakeTestbed /platforms=pc
+IF ERRORLEVEL 1 GOTO AssetProcessingFailed
+
+echo ----- Creating Packages ----
+rem lowercase is intentional, since cache folders are lowercase on some platforms
+.\%BINFOLDER%\rc.exe /job=%MYBATCHFILEDIRECTORY%Code\Tools\RC\Config\rc\RCJob_Generic_MakePaks.xml /p=pc /game=cmaketestbed /trg="paks/${game}_${p}_paks"
+IF ERRORLEVEL 1 GOTO RCFailed
+
+echo ----- Done -----
+cd "%ORIGINALDIRECTORY%"
+exit /b 0
+
+:RCFailed
+echo ---- RC PAK failed ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+:AssetProcessingFailed
+echo ---- ASSET PROCESSING FAILED ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+
+
+
+

+ 111 - 0
BuildReleaseAuxiliaryContent.py

@@ -0,0 +1,111 @@
+"""
+All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+its licensors.
+
+For complete copyright and license terms please see the LICENSE at the root of this
+distribution (the "License"). All use of this software is governed by the License,
+or, if provided, by the license below or the license accompanying this file. Do not
+remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+
+Config file for pytest & PythonTestTools. Warns user if the packaged Python is not
+being used.
+"""
+import argparse
+import os
+import re
+import subprocess
+
+
+def printMessage(message):
+    print(message)
+
+
+def getCurrentProject():
+    bootstrap = open("bootstrap.cfg", "r")
+
+    gameProjectRegex = re.compile("^sys_game_folder\s*=\s*(.*)")
+
+    for line in bootstrap:
+        gameFolderMatch = gameProjectRegex.match(line)
+        if gameFolderMatch:
+            return gameFolderMatch.group(1)
+    return None
+
+
+def getCommandLineArgs():
+    # Game project override is not taken because it's generally not safe to process assets for the non-active project. DLLs may be out of date.
+    parser = argparse.ArgumentParser(
+        description='Lumberyard game project release build automation tool, generates auxiliary content for the current game project specified in bootstrap.cfg'
+                    'or --project override if provided.')
+    parser.add_argument('--platforms', required=True,
+                        help='Required: The comma separated platform list to generate auxiliary content for.')
+    parser.add_argument('--buildFolder', required=True,
+                        help='Required: The build folder for your engine, containing AssetProcessorBatch.exe')
+    parser.add_argument('--recompress', action='store_true',
+                        help='If present, the ResourceCompiler (RC.exe) will decompress and compress back each PAK file found as they are transferred from the cache folder to the game_pc_pak folder.')
+    parser.add_argument('--use_fastest', action='store_true',
+                        help='As each file is being added to its PAK file, they will be compressed across all available codecs (ZLIB, ZSTD and LZ4) and the one with the fastest decompression time will be chosen. The default is to always use ZLIB.')
+    parser.add_argument('--skipAssetProcessing', action='store_true',
+                        help='If present, assetprocessorbatch will not be launched before creating the auxiliary content for the current game project specified in the bootstrap.cfg file. The default behavior of processing assets first helps you make sure your auxiliary content will always be generated from the most up to date data for your game.')
+    parser.add_argument('--skiplevelPaks', action='store_true',
+                        help='If present, the ResourceCompiler (RC.exe) will skip putting any level related pak files for e.g level.pak and terraintexture.pak in the auxiliary contents. Consider using this option if your levels are being packaged through some other system, such as the AssetBundler.')
+    parser.add_argument('--project', help='If present, project to use instead of the bootstrap project')
+    return parser.parse_args()
+
+
+def subprocessWithPrint(command):
+    printMessage(command)
+    subprocess.check_call(command)
+
+
+def main():
+    args = getCommandLineArgs()
+
+    gameProject = args.project or getCurrentProject()
+    if not gameProject:
+        printMessage(
+            "Game project could not be read from bootstrap.cfg, please verify it is set correctly and run this again.")
+        return
+    printMessage("Generating auxiliary content for project {} from build folder {} for platforms {}".format(gameProject,
+                                                                                                            args.buildFolder,
+                                                                                                            args.platforms))
+    # Build paths to tools
+    apBatchExe = os.path.join(args.buildFolder, "AssetProcessorBatch.exe")
+    rcFolder = args.buildFolder
+    rcExe = os.path.join(rcFolder, "rc.exe")
+
+    rc_script_name = 'RCJob_Generic_MakeAuxiliaryContent.xml'
+    rc_script_path = os.path.join(rcFolder, rc_script_name)
+    this_script_folder = os.path.dirname(os.path.abspath(__file__))
+    if not os.path.exists(rc_script_path):
+        rc_script_path = os.path.join(this_script_folder, 'Code', 'Tools', 'rc', 'Config', 'rc',
+                                      rc_script_name)
+    if not os.path.exists(rc_script_path):
+        printMessage(f"Could not find {rc_script_name} at {rcFolder} or {this_script_folder}")
+        return
+
+    # Make sure all assets are up to date.
+    if not args.skipAssetProcessing:
+        printMessage("Updating game assets")
+        # Asset processor will read the current project from bootstrap.
+        subprocessWithPrint("{} /platforms={}".format(apBatchExe, args.platforms))
+    else:
+        printMessage("Skipping asset processing")
+
+    platformsSplit = args.platforms.split(',')
+    for platform in platformsSplit:
+        printMessage("Generating auxiliary content for platform {}".format(platform))
+        # Call RC to generate the auxiliary content.
+        recompressArg = 1 if args.recompress else 0
+        useFastestArg = 1 if args.use_fastest else 0
+        skiplevelPaksArg = 1 if args.skiplevelPaks else 0
+        rc_cmd = f"{rcExe} /job={rc_script_path} /p={platform} /game={gameProject.lower()} " \
+                 f"/recompress={recompressArg}" \
+                 f" /use_fastest={useFastestArg} /skiplevelPaks={skiplevelPaksArg}"
+
+        subprocessWithPrint(rc_cmd)
+
+
+if __name__ == "__main__":
+    main()

+ 109 - 0
Build_AssetBundler_AuxiliaryContent_PC.bat

@@ -0,0 +1,109 @@
+@echo off
+
+REM 
+REM All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+REM its licensors.
+REM
+REM For complete copyright and license terms please see the LICENSE at the root of this
+REM distribution (the "License"). All use of this software is governed by the License,
+REM or, if provided, by the license below or the license accompanying this file. Do not
+REM remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+REM
+
+setlocal enabledelayedexpansion 
+
+set ORIGINALDIRECTORY=%cd%
+set MYBATCHFILEDIRECTORY=%~dp0
+cd "%MYBATCHFILEDIRECTORY%"
+
+REM Parse command line arguments for OPTIONAL parameters. Looking for --recompress or --use_fastest.
+set RECOMPRESS_NAME=--recompress
+set /A RECOMPRESS_VALUE=0
+set USE_FASTEST_NAME=--use_fastest
+set /A USE_FASTEST_VALUE=0
+set GAME_NAME_CMD=--game
+set "BINFOLDER_HINT_NAME=--binfolder-hint"
+set "BINFOLDER_HINT="
+:CmdLineArgumentsParseLoop
+if "%1"=="" goto CmdLineArgumentsParsingDone
+    if "%1"=="%RECOMPRESS_NAME%" (
+        set /A RECOMPRESS_VALUE=1
+        goto GotValidArgument
+    )
+    if "%1"=="%USE_FASTEST_NAME%" (
+        set /A USE_FASTEST_VALUE=1
+        goto GotValidArgument
+    )
+    if "%1"=="%GAME_NAME_CMD%" (
+        set GAME_NAME=%2
+        shift
+        set GAME_NAME
+        CALL :lowercase GAME_NAME GAME_NAME_LOWER
+        set GAME_NAME_LOWER
+        goto GotValidArgument
+    )
+    if "%1"=="%BINFOLDER_HINT_NAME%" (
+        REM The next parameter is the hint directory
+        set BINFOLDER_HINT=%2%
+        shift
+        goto GotValidArgument
+    )
+:InvalidCommandArgument
+    REM If we are here, the user gave us an unexpected argument. Let them know and quit.
+    echo "%1" is an invalid argument, "%GAME_NAME_CMD%" is required, optional arguments are "%RECOMPRESS_NAME%", "%USE_FASTEST_NAME%" or "%BINFOLDER_HINT_NAME%"
+    echo --game: The name of the game to generate the auxiliary content for.
+    echo --recompress: If present, the ResourceCompiler (RC.exe) will decompress and compress back each
+    echo               PAK file found as they are transferred from the cache folder to the game_pc_pak folder.
+    echo --use_fastest: As each file is being added to its PAK file, they will be compressed across all
+    echo                available codecs (ZLIB, ZSTD and LZ4) and the one with the fastest decompression time
+    echo                will be chosen. The default is to always use ZLIB.
+    echo %BINFOLDER_HINT_NAME%^=^<folder_name^>: A hint to indicate the folder name to use for finding the windows binaries i.e Bin64vc142
+    exit /b 1
+:GotValidArgument
+    shift
+goto CmdLineArgumentsParseLoop
+:CmdLineArgumentsParsingDone
+
+if "%GAME_NAME%"=="" goto InvalidCommandArgument
+
+REM Attempt to determine the best BinFolder for rc.exe and AssetProcessorBatch.exe
+call "%MYBATCHFILEDIRECTORY%\DetermineRCandAP.bat" SILENT %BINFOLDER_HINT%
+
+REM If a bin folder was registered, validate the presence of the binfolder/rc.exe
+IF ERRORLEVEL 1 (
+    ECHO unable to determine the locations of AssetProcessor and rc.exe.  Make sure that they are available or rebuild from source
+    EXIT /b 1
+)
+ECHO Detected binary folder at %MYBATCHFILEDIRECTORY%%BINFOLDER%
+
+echo ----- Processing Assets Using Asset Processor Batch ----
+.\%BINFOLDER%\AssetProcessorBatch.exe /gamefolder=%GAME_NAME% /platforms=pc
+IF ERRORLEVEL 1 GOTO AssetProcessingFailed
+
+echo ----- Creating Packages ----
+rem lowercase is intentional, since cache folders are lowercase on some platforms
+.\%BINFOLDER%\rc.exe /job=%MYBATCHFILEDIRECTORY%Code\Tools\RC\Config\rc\RCJob_Generic_MakeAuxiliaryContent.xml /p=pc /game=%GAME_NAME_LOWER% /recompress=%RECOMPRESS_VALUE% /use_fastest=%USE_FASTEST_VALUE%
+IF ERRORLEVEL 1 GOTO RCFailed
+echo ----- Done -----
+cd "%ORIGINALDIRECTORY%"
+exit /b 0
+
+:RCFailed
+echo ---- RC PAK failed ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+:AssetProcessingFailed
+echo ---- ASSET PROCESSING FAILED ----
+cd "%ORIGINALDIRECTORY%"
+exit /b 1
+
+:lowercase
+SET _UCase=A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+SET _LCase=a b c d e f g h i j k l m n o p q r s t u v w x y z
+SET _Lib_UCase_Tmp=!%1!
+SET _Abet=%_LCase%
+FOR %%Z IN (%_Abet%) DO SET _Lib_UCase_Tmp=!_Lib_UCase_Tmp:%%Z=%%Z!
+SET %2=%_Lib_UCase_Tmp%
+GOTO:EOF

+ 114 - 0
CMakeLists.txt

@@ -0,0 +1,114 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+# Cmake version 3.17 is the minimum version needed for all of lumberyard's supported platforms
+cmake_minimum_required(VERSION 3.17)
+
+# CMP0111 introduced in 3.19 has a bug that produces the policy to warn every time there is an
+# INTERFACE IMPORTED library. We use this type of libraries for handling 3rdParty. The rest of
+# the documentation states that INTERFACE IMPORTED libraries do not require to set locations, but
+# the policy still warns about it. Issue: https://gitlab.kitware.com/cmake/cmake/-/issues/21470
+# The issue was fixed in 3.19.1 so we just disable the policy for 3.19
+if(CMAKE_VERSION VERSION_EQUAL 3.19)
+    cmake_policy(SET CMP0111 OLD)
+endif()
+
+project(Lumberyard LANGUAGES C CXX)
+
+# Turn on the ability to create folders to organize projects (.vcproj)
+# It creates "CMakePredefinedTargets" folder by default and adds CMake
+# defined projects like INSTALL.vcproj and ZERO_CHECK.vcproj
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+set(CMAKE_WARN_DEPRECATED ON)
+
+# Set output directories
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib CACHE PATH "Build directory for static libraries and import libraries")
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build directory for shared libraries")
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build directory for executables")
+set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "Installation prefix")
+
+include(cmake/FileUtil.cmake)
+include(cmake/PAL.cmake)
+include(cmake/PALTools.cmake)
+include(cmake/Configurations.cmake) # Requires to be after PAL so we get platform variable definitions
+include(cmake/Dependencies.cmake)
+include(cmake/Deployment.cmake)
+include(cmake/3rdParty.cmake)
+include(cmake/LYPython.cmake)
+include(cmake/LYWrappers.cmake)
+include(cmake/UnitTest.cmake)
+include(cmake/LYTestWrappers.cmake)
+include(cmake/Version.cmake)
+include(cmake/Monolithic.cmake)
+include(cmake/SettingsRegistry.cmake)
+include(cmake/TestImpactFramework/LYTestImpactFramework.cmake)
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake)
+
+# Add all cmake files in a project so they can be handled from within the IDE
+ly_include_cmake_file_list(cmake/cmake_files.cmake)
+add_custom_target(CMakeFiles SOURCES ${ALLFILES})
+ly_source_groups_from_folders("${ALLFILES}")
+unset(ALLFILES)
+
+# Add the projects first so the Launcher can find them
+include(cmake/Projects.cmake)
+
+# Add the rest of the targets
+add_subdirectory(Code)
+add_subdirectory(Gems)
+
+set(enabled_platforms
+    ${PAL_PLATFORM_NAME}
+    ${LY_PAL_TOOLS_ENABLED})
+
+foreach(restricted_platform ${PAL_RESTRICTED_PLATFORMS})
+    if(restricted_platform IN_LIST enabled_platforms)
+        add_subdirectory(restricted/${restricted_platform})
+    endif()
+endforeach()
+
+# The following steps have to be done after all targets were registered:
+# 1. link targets where the dependency was yet not declared, we need to have the declaration so we do different
+#    linking logic depending on the type of target
+ly_delayed_target_link_libraries()
+# 2. generate a settings registry .setreg file for all ly_add_project_dependencies() and ly_add_target_dependencies() calls
+#    to provide applications with the filenames of gem modules to load
+ly_delayed_generate_settings_registry()
+# 3. generate a registry file for unit testing for platforms that support unit testing
+if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
+    ly_delayed_generate_unit_test_module_registry()
+endif()
+# 4. inject runtime dependencies to the targets. We need to do this after (1) since we are going to walk through
+#    the dependencies
+include(cmake/RuntimeDependencies.cmake)
+
+################################################################################
+# Tests
+################################################################################
+# Recurse into directory of general python test scripts
+# specific python test registration can be specified within the CMakeLists.txt that is associated with the test(i.e Gem/<Foo>/CMakeLists.txt)
+add_subdirectory(ctest_scripts)
+
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/scripts/CMakeLists.txt")
+    add_subdirectory(scripts)
+endif()
+
+# SPEC-1417 will investigate and fix this
+if(NOT PAL_PLATFORM_NAME STREQUAL "Mac")
+    add_subdirectory(Tools/LyTestTools/tests/)
+    add_subdirectory(Tools/RemoteConsole/ly_remote_console/tests/)
+endif()
+
+################################################################################
+# Test Impact Framework
+################################################################################
+# Perform test impact framework post steps once all of the targets have been enumerated
+ly_test_impact_post_step()

+ 12 - 0
CMakeTestbed/CMakeLists.txt

@@ -0,0 +1,12 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+add_subdirectory(Gem)

+ 97 - 0
CMakeTestbed/Config/Editor.xml

@@ -0,0 +1,97 @@
+<ObjectStream version="3">
+	<Class name="ComponentApplication::Descriptor" version="2" type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
+		<Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="allocationRecordsSaveNames" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="allocationRecordsAttemptDecodeImmediately" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="int" field="recordingMode" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
+		<Class name="AZ::u64" field="stackRecordLevels" value="5" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="unsigned int" field="pageSize" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+		<Class name="unsigned int" field="poolPageSize" value="4096" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+		<Class name="unsigned int" field="blockAlignment" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+		<Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="bool" field="enableDrilling" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="useOverrunDetection" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="useMalloc" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="AZStd::vector" field="allocatorRemappings" type="{82897F6E-6389-5BEF-B427-761DB35AC1CC}"/>
+		<Class name="AZStd::vector" field="modules" type="{8E779F80-AEAA-565B-ABB1-DE10B18CF995}">
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Maestro.Editor.3b9a978ed6f742a1acb99f74379a342c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LmbrCentral.Editor.ff06785f7145416b9d46fde39098cb0c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShine.Editor.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.SceneProcessing.Editor.7c2578f634df4345aca98d671e39b8ab.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CMakeTestbed.e111dee500ed4812a7905093a73d3837.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.ImageProcessing.Editor.eeffbd9211cf4ce0b5cc73696b427cbe.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Camera.Editor.f910686b6725452fbfc4671f95f733c6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+		</Class>
+	</Class>
+	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
+		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
+			<Class name="AZ::u64" field="id" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		</Class>
+		<Class name="AZStd::string" field="Name" value="SystemEntity" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}"/>
+		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="AZStd::vector" field="Components" type="{2BADE35A-6F1B-4698-B2BC-3373D010020C}">
+			<Class name="PhysicsSystemComponent" field="element" value="" version="1" type="{1586DBA1-F5F0-49AB-9F59-AE62C0E60AE0}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="5881970355815182227" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="NavigationSystemComponent" field="element" value="" version="1" type="{3D27484B-00C4-4F3F-9605-2BF3E5C317FF}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="3408791856679455729" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="EditorSelectionAccentSystemComponent" field="element" value="" type="{6E0F0E2C-1FE5-4AFB-9672-DC92B3D2D844}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="4281709857282575192" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="CharacterAnimationManagerComponent" field="element" value="" version="1" type="{ABD0848C-0CFC-43D3-AEFB-7EEED64AF164}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="14551426789008678714" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="LyShineSystemComponent" field="element" value="" type="{B0C78B8D-1E5B-47D7-95D0-EC69C0513804}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="13584318858523138243" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="LyEditorMetricsSystemComponent" field="element" value="" type="{B8C74085-F6B7-4E2F-8135-78C991CC53C5}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="8970396848016072155" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="StereoRendererComponent" field="element" version="1" type="{BBFE0965-5564-4739-8219-AFE8209A5E57}"/>
+			<Class name="CryLegacySystemComponent" field="element" value="" type="{D2051F81-6B46-4B23-A7F6-C19F814E63F0}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="6582303238962293590" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+		</Class>
+	</Class>
+</ObjectStream>
+

+ 91 - 0
CMakeTestbed/Config/Game.xml

@@ -0,0 +1,91 @@
+<ObjectStream version="3">
+	<Class name="ComponentApplication::Descriptor" version="2" type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
+		<Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="allocationRecordsSaveNames" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="allocationRecordsAttemptDecodeImmediately" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="int" field="recordingMode" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
+		<Class name="AZ::u64" field="stackRecordLevels" value="5" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="unsigned int" field="pageSize" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+		<Class name="unsigned int" field="poolPageSize" value="4096" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+		<Class name="unsigned int" field="blockAlignment" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+		<Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		<Class name="bool" field="enableDrilling" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="useOverrunDetection" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="bool" field="useMalloc" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="AZStd::vector" field="allocatorRemappings" type="{82897F6E-6389-5BEF-B427-761DB35AC1CC}"/>
+		<Class name="AZStd::vector" field="modules" type="{8E779F80-AEAA-565B-ABB1-DE10B18CF995}">
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Maestro.3b9a978ed6f742a1acb99f74379a342c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShine.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CMakeTestbed.e111dee500ed4812a7905093a73d3837.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+			<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+				<Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Camera.f910686b6725452fbfc4671f95f733c6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+			</Class>
+		</Class>
+	</Class>
+	<Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
+		<Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
+			<Class name="AZ::u64" field="id" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+		</Class>
+		<Class name="AZStd::string" field="Name" value="SystemEntity" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}"/>
+		<Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+		<Class name="AZStd::vector" field="Components" type="{2BADE35A-6F1B-4698-B2BC-3373D010020C}">
+			<Class name="PhysicsSystemComponent" field="element" value="" version="1" type="{1586DBA1-F5F0-49AB-9F59-AE62C0E60AE0}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="14545574550664822512" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="NavigationSystemComponent" field="element" value="" version="1" type="{3D27484B-00C4-4F3F-9605-2BF3E5C317FF}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="9809863829757322975" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="CharacterAnimationManagerComponent" field="element" value="" version="1" type="{ABD0848C-0CFC-43D3-AEFB-7EEED64AF164}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="14876423501541688146" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="LyShineSystemComponent" field="element" value="" type="{B0C78B8D-1E5B-47D7-95D0-EC69C0513804}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="3706545825063126910" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="StereoRendererComponent" field="element" version="1" type="{BBFE0965-5564-4739-8219-AFE8209A5E57}"/>
+			<Class name="LmbrCentralSystemComponent" field="element" value="" version="1" type="{CE249D37-C1D6-4A64-932D-C937B0EC2B8C}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="17265313386362322770" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="CryLegacySystemComponent" field="element" value="" type="{D2051F81-6B46-4B23-A7F6-C19F814E63F0}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="7245198359882572378" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+			<Class name="AssetDatabaseComponent" field="element" value="" version="1" type="{D5A73BCC-0098-4D1E-8FE4-C86101E374AC}">
+				<Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+					<Class name="AZ::u64" field="Id" value="18338415854038604706" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+				</Class>
+			</Class>
+		</Class>
+	</Class>
+</ObjectStream>
+

+ 91 - 0
CMakeTestbed/Config/Server.xml

@@ -0,0 +1,91 @@
+<ObjectStream version="3">
+    <Class name="ComponentApplication::Descriptor" version="2" type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
+        <Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="allocationRecordsSaveNames" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="allocationRecordsAttemptDecodeImmediately" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="int" field="recordingMode" value="2" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
+        <Class name="AZ::u64" field="stackRecordLevels" value="5" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+        <Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="unsigned int" field="pageSize" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+        <Class name="unsigned int" field="poolPageSize" value="4096" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+        <Class name="unsigned int" field="blockAlignment" value="65536" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
+        <Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+        <Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+        <Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+        <Class name="bool" field="enableDrilling" value="true" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="useOverrunDetection" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="bool" field="useMalloc" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="AZStd::vector" field="allocatorRemappings" type="{82897F6E-6389-5BEF-B427-761DB35AC1CC}"/>
+        <Class name="AZStd::vector" field="modules" type="{8E779F80-AEAA-565B-ABB1-DE10B18CF995}">
+            <Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+                <Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LyShine.0fefab3f13364722b2eab3b96ce2bf20.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+            </Class>
+            <Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+                <Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.TextureAtlas.5a149b6b3c964064bd4970f0e92f72e2.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+            </Class>
+            <Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+                <Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Maestro.3b9a978ed6f742a1acb99f74379a342c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+            </Class>
+            <Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+                <Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.CMakeTestbed.e111dee500ed4812a7905093a73d3837.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+            </Class>
+            <Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+                <Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.LmbrCentral.ff06785f7145416b9d46fde39098cb0c.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+            </Class>
+            <Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-A703-2E750F57C003}">
+                <Class name="AZStd::string" field="dynamicLibraryPath" value="Gem.Camera.f910686b6725452fbfc4671f95f733c6.v0.1.0" type="{189CC2ED-FDDE-5680-91D4-9F630A79187F}"/>
+            </Class>
+        </Class>
+    </Class>
+    <Class name="AZ::Entity" version="2" type="{75651658-8663-478D-9090-2432DFCAFA44}">
+        <Class name="EntityId" field="Id" version="1" type="{6383F1D3-BB27-4E6B-A49A-6409B2059EAA}">
+            <Class name="AZ::u64" field="id" value="0" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+        </Class>
+        <Class name="AZStd::string" field="Name" value="SystemEntity" type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}"/>
+        <Class name="bool" field="IsDependencyReady" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
+        <Class name="AZStd::vector" field="Components" type="{2BADE35A-6F1B-4698-B2BC-3373D010020C}">
+            <Class name="PhysicsSystemComponent" field="element" value="" version="1" type="{1586DBA1-F5F0-49AB-9F59-AE62C0E60AE0}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="14545574550664822512" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+            <Class name="NavigationSystemComponent" field="element" value="" version="1" type="{3D27484B-00C4-4F3F-9605-2BF3E5C317FF}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="9809863829757322975" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+            <Class name="CharacterAnimationManagerComponent" field="element" value="" version="1" type="{ABD0848C-0CFC-43D3-AEFB-7EEED64AF164}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="14876423501541688146" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+            <Class name="LyShineSystemComponent" field="element" value="" type="{B0C78B8D-1E5B-47D7-95D0-EC69C0513804}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="3706545825063126910" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+            <Class name="StereoRendererComponent" field="element" version="1" type="{BBFE0965-5564-4739-8219-AFE8209A5E57}"/>
+            <Class name="LmbrCentralSystemComponent" field="element" value="" version="1" type="{CE249D37-C1D6-4A64-932D-C937B0EC2B8C}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="17265313386362322770" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+            <Class name="CryLegacySystemComponent" field="element" value="" type="{D2051F81-6B46-4B23-A7F6-C19F814E63F0}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="7245198359882572378" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+            <Class name="AssetDatabaseComponent" field="element" value="" version="1" type="{D5A73BCC-0098-4D1E-8FE4-C86101E374AC}">
+                <Class name="AZ::Component" field="BaseClass1" type="{EDFCB2CF-F75D-43BE-B26B-F35821B29247}">
+                    <Class name="AZ::u64" field="Id" value="18338415854038604706" type="{D6597933-47CD-4FC8-B911-63F3E2B0993A}"/>
+                </Class>
+            </Class>
+        </Class>
+    </Class>
+</ObjectStream>
+

+ 12 - 0
CMakeTestbed/Gem/CMakeLists.txt

@@ -0,0 +1,12 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+add_subdirectory(Code)

+ 65 - 0
CMakeTestbed/Gem/Code/CMakeLists.txt

@@ -0,0 +1,65 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
+
+ly_add_target(
+    NAME CMakeTestbed ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
+    NAMESPACE Gem
+    FILES_CMAKE
+        cmaketestbed_files.cmake
+        ${pal_dir}/cmaketestbed_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
+    INCLUDE_DIRECTORIES
+        PUBLIC
+            Include
+    BUILD_DEPENDENCIES
+        PRIVATE
+            AZ::AzGameFramework
+)
+
+################################################################################
+# Gem dependencies
+################################################################################
+ly_add_project_dependencies(
+    PROJECT_NAME
+        CMakeTestbed
+    TARGETS 
+        CMakeTestbed.GameLauncher
+    DEPENDENCIES_FILES
+        runtime_dependencies.cmake
+)
+
+if(PAL_TRAIT_BUILD_HOST_TOOLS)
+    ly_add_project_dependencies(
+        PROJECT_NAME
+            CMakeTestbed
+        TARGETS
+            AssetBuilder
+            AssetProcessor
+            AssetProcessorBatch
+            Editor
+        DEPENDENCIES_FILES
+            tool_dependencies.cmake
+    )
+endif()
+
+if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
+    ly_add_project_dependencies(
+        PROJECT_NAME
+            CMakeTestbed
+        TARGETS
+            CMakeTestbed.ServerLauncher
+        DEPENDENCIES_FILES
+            runtime_dependencies.cmake
+    )
+    set_property(GLOBAL APPEND PROPERTY LY_LAUNCHER_SERVER_PROJECTS CMakeTestbed)
+
+endif()

+ 31 - 0
CMakeTestbed/Gem/Code/Include/CMakeTestbed/CMakeTestbedBus.h

@@ -0,0 +1,31 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+#pragma once
+
+#include <AzCore/EBus/EBus.h>
+
+namespace CMakeTestbed
+{
+    class CMakeTestbedRequests
+        : public AZ::EBusTraits
+    {
+    public:
+        //////////////////////////////////////////////////////////////////////////
+        // EBusTraits overrides
+        static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
+        static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
+        //////////////////////////////////////////////////////////////////////////
+
+        // Put your public methods here
+    };
+    using CMakeTestbedRequestBus = AZ::EBus<CMakeTestbedRequests>;
+} // namespace CMakeTestbed

+ 13 - 0
CMakeTestbed/Gem/Code/Platform/Android/cmaketestbed_android_files.cmake

@@ -0,0 +1,13 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+)

+ 13 - 0
CMakeTestbed/Gem/Code/Platform/Linux/cmaketestbed_linux_files.cmake

@@ -0,0 +1,13 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+)

+ 14 - 0
CMakeTestbed/Gem/Code/Platform/Mac/cmaketestbed_mac_files.cmake

@@ -0,0 +1,14 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    ../../../Resources/MacLauncher/Info.plist
+)

+ 13 - 0
CMakeTestbed/Gem/Code/Platform/Windows/cmaketestbed_windows_files.cmake

@@ -0,0 +1,13 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+)

+ 14 - 0
CMakeTestbed/Gem/Code/Platform/iOS/cmaketestbed_ios_files.cmake

@@ -0,0 +1,14 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    ../../../Resources/IOSLauncher/Info.plist
+)

+ 51 - 0
CMakeTestbed/Gem/Code/Source/CMakeTestbedModule.cpp

@@ -0,0 +1,51 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Memory/SystemAllocator.h>
+#include <AzCore/Module/Module.h>
+
+#include "CMakeTestbedSystemComponent.h"
+
+namespace CMakeTestbed
+{
+    class CMakeTestbedModule
+        : public AZ::Module
+    {
+    public:
+        AZ_RTTI(CMakeTestbedModule, "{41E747FA-DBF8-4E5A-B843-132584989953}", AZ::Module);
+        AZ_CLASS_ALLOCATOR(CMakeTestbedModule, AZ::SystemAllocator, 0);
+
+        CMakeTestbedModule()
+            : AZ::Module()
+        {
+            // Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
+            m_descriptors.insert(m_descriptors.end(), {
+                CMakeTestbedSystemComponent::CreateDescriptor(),
+            });
+        }
+
+        /**
+         * Add required SystemComponents to the SystemEntity.
+         */
+        AZ::ComponentTypeList GetRequiredSystemComponents() const override
+        {
+            return AZ::ComponentTypeList{
+                azrtti_typeid<CMakeTestbedSystemComponent>(),
+            };
+        }
+    };
+}
+
+// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
+// The first parameter should be GemName_GemIdLower
+// The second should be the fully qualified name of the class above
+AZ_DECLARE_MODULE_CLASS(Gem_CMakeTestbed, CMakeTestbed::CMakeTestbedModule)

+ 73 - 0
CMakeTestbed/Gem/Code/Source/CMakeTestbedSystemComponent.cpp

@@ -0,0 +1,73 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+
+#include <AzCore/Serialization/SerializeContext.h>
+#include <AzCore/Serialization/EditContext.h>
+#include <AzCore/Serialization/EditContextConstants.inl>
+
+#include "CMakeTestbedSystemComponent.h"
+
+namespace CMakeTestbed
+{
+    void CMakeTestbedSystemComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serialize->Class<CMakeTestbedSystemComponent, AZ::Component>()
+                ->Version(0)
+                ;
+
+            if (AZ::EditContext* ec = serialize->GetEditContext())
+            {
+                ec->Class<CMakeTestbedSystemComponent>("CMakeTestbed", "[Description of functionality provided by this System Component]")
+                    ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
+                        ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
+                        ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
+                    ;
+            }
+        }
+    }
+
+    void CMakeTestbedSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
+    {
+        provided.push_back(AZ_CRC("CMakeTestbedService"));
+    }
+
+    void CMakeTestbedSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
+    {
+        incompatible.push_back(AZ_CRC("CMakeTestbedService"));
+    }
+
+    void CMakeTestbedSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
+    {
+        AZ_UNUSED(required);
+    }
+
+    void CMakeTestbedSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
+    {
+        AZ_UNUSED(dependent);
+    }
+
+    void CMakeTestbedSystemComponent::Init()
+    {
+    }
+
+    void CMakeTestbedSystemComponent::Activate()
+    {
+        CMakeTestbedRequestBus::Handler::BusConnect();
+    }
+
+    void CMakeTestbedSystemComponent::Deactivate()
+    {
+        CMakeTestbedRequestBus::Handler::BusDisconnect();
+    }
+}

+ 47 - 0
CMakeTestbed/Gem/Code/Source/CMakeTestbedSystemComponent.h

@@ -0,0 +1,47 @@
+/*
+ * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+ * its licensors.
+ *
+ * For complete copyright and license terms please see the LICENSE at the root of this
+ * distribution (the "License"). All use of this software is governed by the License,
+ * or, if provided, by the license below or the license accompanying this file. Do not
+ * remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *
+ */
+#pragma once
+
+#include <AzCore/Component/Component.h>
+
+#include <CMakeTestbed/CMakeTestbedBus.h>
+
+namespace CMakeTestbed
+{
+    class CMakeTestbedSystemComponent
+        : public AZ::Component
+        , protected CMakeTestbedRequestBus::Handler
+    {
+    public:
+        AZ_COMPONENT(CMakeTestbedSystemComponent, "{CD11E7A7-6F0C-4346-B296-4928673712B8}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
+        static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
+        static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
+        static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
+
+    protected:
+        ////////////////////////////////////////////////////////////////////////
+        // CMakeTestbedRequestBus interface implementation
+
+        ////////////////////////////////////////////////////////////////////////
+
+        ////////////////////////////////////////////////////////////////////////
+        // AZ::Component interface implementation
+        void Init() override;
+        void Activate() override;
+        void Deactivate() override;
+        ////////////////////////////////////////////////////////////////////////
+    };
+}

+ 19 - 0
CMakeTestbed/Gem/Code/cmaketestbed_files.cmake

@@ -0,0 +1,19 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    Include/CMakeTestbed/CMakeTestbedBus.h
+    Source/CMakeTestbedModule.cpp
+    Source/CMakeTestbedSystemComponent.cpp
+    Source/CMakeTestbedSystemComponent.h
+    runtime_dependencies.cmake
+    tool_dependencies.cmake
+)

+ 14 - 0
CMakeTestbed/Gem/Code/cmaketestbed_ios_files.cmake

@@ -0,0 +1,14 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+set(FILES
+    ../Resources/IOSLauncher/Info.plist
+)

+ 20 - 0
CMakeTestbed/Gem/Code/game_dependencies.cmake

@@ -0,0 +1,20 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+# Extracted from Game.xml
+set(GEM_DEPENDENCIES
+    Gem::LyShine
+    Gem::TextureAtlas
+    Gem::Maestro
+    Gem::CMakeTestbed
+    Gem::LmbrCentral
+    Gem::Camera
+)

+ 20 - 0
CMakeTestbed/Gem/Code/runtime_dependencies.cmake

@@ -0,0 +1,20 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+# Extracted from Game.xml
+set(GEM_DEPENDENCIES
+    Gem::LyShine
+    Gem::TextureAtlas
+    Gem::Maestro
+    Gem::CMakeTestbed
+    Gem::LmbrCentral
+    Gem::Camera
+)

+ 22 - 0
CMakeTestbed/Gem/Code/tool_dependencies.cmake

@@ -0,0 +1,22 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+# Extracted from Editor.xml
+set(GEM_DEPENDENCIES
+    Gem::LyShine.Editor
+    Gem::Maestro.Editor
+    Gem::SceneProcessing.Editor
+    Gem::ImageProcessing.Editor
+    Gem::CMakeTestbed
+    Gem::LmbrCentral.Editor
+    Gem::TextureAtlas
+    Gem::Camera.Editor
+)

+ 3 - 0
CMakeTestbed/Gem/Resources/CryEngineLogoLauncher.bmp

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:cf6d56fe4c367d39bd78500dd34332fcad57ad41241768b52781dbdb60ddd972
+size 347568

+ 3 - 0
CMakeTestbed/Gem/Resources/GameSDK.ico

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:61efd8df621780af995fc1250918df5e00364ff00f849bef67702cd4b0a152e1
+size 65537

+ 116 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/Contents.json

@@ -0,0 +1,116 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "iPhoneNotificationIcon40x40.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "iPhoneNotificationIcon60x60.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "iPhoneSettingsIcon58x58.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "iPhoneSettingsIcon87x87.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "iPhoneSpotlightIcon80x80.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "iPhoneSpotlightIcon120x120.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "iPhoneAppIcon120x120.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "iPhoneAppIcon180x180.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "iPadNotificationIcon20x20.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "iPadNotificationIcon40x40.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "iPadSettingsIcon29x29.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "iPadSettingsIcon58x58.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "iPadSpotlightIcon40x40.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "iPadSpotlightIcon80x80.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "iPadAppIcon76x76.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "iPadAppIcon152x152.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "iPadProAppIcon167x167.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "iOSAppStoreIcon1024x1024.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadAppIcon152x152.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e4901093fa6190bf37291b0fb6de23fba1be8ebbd742775a8565a4106722fbb6
+size 31942

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadAppIcon76x76.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e4ae97c4f44910121a61686862c8342ce598db4cdf9d46b29e96d3cb9e43bd06
+size 22158

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadProAppIcon167x167.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:061e2d0ce8dc852dd298c80f2aed5fee8ea4b87511c00662aa2d00922c0ba3c2
+size 30162

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSettingsIcon29x29.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0fb4b4b77620d99dae7473b7bd8affe14630419835bd5719167ed200e657fa4f
+size 17504

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSettingsIcon58x58.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8aa9b1194f3244025578225a6a87cbc2dd12c70955ff615c8af640ea7f1334f1
+size 19619

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSpotlightIcon40x40.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0c25ffb1af8160b3202977de8c32aaa235e22c643ffd8004e4546c96868ef3b9
+size 18317

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPadSpotlightIcon80x80.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:2db961b8f922a552d8ad374fdb56029efd4049a6cde10399b3d961242c82ce53
+size 22571

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneAppIcon120x120.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f39d897a57d4da0a70ede7c91339660b28e9d8c57b3e7d749807b13baa4b85f3
+size 28559

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneAppIcon180x180.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:263b75d58328499eef1f8fa2e64c30706f546badcc0c4464a043b231da93cd0d
+size 34969

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSettingsIcon58x58.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:33522ad8a8e826b22dd9ad214f56e63e24bf55c00bd8c845925d848b855dfb48
+size 19619

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSettingsIcon87x87.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f405c9f3d908d038aea26049e533b0d10955adfac370c7b3b80209997ea706d0
+size 24407

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSpotlightIcon120x120.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d110f6e151799a2327bcdf5ef94d6fc82b114783a8cc973a8915896679ba4a80
+size 28559

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/iPhoneSpotlightIcon80x80.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:db8f00568fad4e49b05249aaa7a48c9fbf85c8b7a78489c83dc9b8161778bcef
+size 22571

+ 6 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 169 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/Contents.json

@@ -0,0 +1,169 @@
+{
+  "images" : [
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "2436h",
+      "filename" : "iPhoneLaunchImage1125x2436.png",
+      "minimum-system-version" : "11.0",
+      "orientation" : "portrait",
+      "scale" : "3x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "2436h",
+      "filename" : "iPhoneLaunchImage2436x1125.png",
+      "minimum-system-version" : "11.0",
+      "orientation" : "landscape",
+      "scale" : "3x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "736h",
+      "filename" : "iPhoneLaunchImage1242x2208.png",
+      "minimum-system-version" : "8.0",
+      "orientation" : "portrait",
+      "scale" : "3x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "736h",
+      "filename" : "iPhoneLaunchImage2208x1242.png",
+      "minimum-system-version" : "8.0",
+      "orientation" : "landscape",
+      "scale" : "3x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "667h",
+      "filename" : "iPhoneLaunchImage750x1334.png",
+      "minimum-system-version" : "8.0",
+      "orientation" : "portrait",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "filename" : "iPhoneLaunchImage640x960.png",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "extent" : "full-screen",
+      "idiom" : "iphone",
+      "subtype" : "retina4",
+      "filename" : "iPhoneLaunchImage640x1136.png",
+      "minimum-system-version" : "7.0",
+      "orientation" : "portrait",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "filename" : "iPadLaunchImage768x1024.png",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "filename" : "iPadLaunchImage1024x768.png",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "filename" : "iPadLaunchImage1536x2048.png",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "filename" : "iPadLaunchImage2048x1536.png",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "subtype" : "retina4",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "to-status-bar",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "to-status-bar",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "to-status-bar",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "to-status-bar",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1024x768.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:31afa7ed44c5d9844c8d6ce08beccac482c3f43590869a3d190d06e2df377ccc
+size 137472

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage1536x2048.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0aac8ef9899442820bec0df8bf6434a46cc787d57c5d6d38a04727b8dc310048
+size 338281

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage2048x1536.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c07495891f15b138ba09f142777b0f43217bf8be05cbb74ba938319f3425980c
+size 321125

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPadLaunchImage768x1024.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d6bf6acb92421a453a36fc143ab6cefda14d631ea5e6dbf95c6e252a445fcbac
+size 144797

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x1136.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e9ad650fda925b1c076a67d1ef70315fe4f14db888c9fd36ee4eba1d18c1e7d1
+size 166749

+ 3 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Images.xcassets/LaunchImage.launchimage/iPhoneLaunchImage640x960.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:16f6e9d7bd15fc528d934c252213de8792812e708b1810191c5f1767f7165852
+size 142331

+ 45 - 0
CMakeTestbed/Gem/Resources/IOSLauncher/Info.plist

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>CMakeTestbed</string>
+	<key>CFBundleExecutable</key>
+	<string>CMakeTestbed.GameLauncher</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.amazon.lumberyard.CMakeTestbed</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>CMakeTestbed</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>arm64</string>
+		<string>metal</string>
+	</array>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+	<key>UIStatusBarHidden</key>
+	<true/>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+	</array>
+</dict>
+</plist>

+ 68 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/Contents.json

@@ -0,0 +1,68 @@
+{
+  "images" : [
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "icon_16_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "icon_32_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "icon_128 _2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "icon_256 _2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "icon_512_2x.png",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_128 _2x.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e38257b6917cdf5d73e90e6009f10c8736d62b20c4e785085305075c7e6320e2
+size 32037

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_128.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9f41a37d2347a617e93bd97adaf6d4c161c471ca3ef7e04b98c65ddda52396dc
+size 27833

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_16.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b07984494059bf827bc485cbea06d12e0283811face1a18799495f9ba7ae8af1
+size 20779

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_16_2x.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e645142d284de40aafb7a4a858f3df92b6a5ba9b03fa5f1a2d3cb25211597926
+size 21857

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_256 _2x.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:07631f41b8dea80713d2463f81a713a9a93798975b6fb50afbeeb13d26c57fa2
+size 48899

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_256.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e38257b6917cdf5d73e90e6009f10c8736d62b20c4e785085305075c7e6320e2
+size 32037

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_32.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e645142d284de40aafb7a4a858f3df92b6a5ba9b03fa5f1a2d3cb25211597926
+size 21857

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_32_2x.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ad83faf98b49f4e37112baedeae726f4f8d71bcdd1961d9cdad31f043f8ca666
+size 24003

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_512.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:68529a6c11d5ffa7ecd9d5bbb11ceea28e6852bd45946b525af09602c9a1e1bf
+size 48899

+ 3 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/CMakeTestbedAppIcon.appiconset/icon_512_2x.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8a70003840b418848b2ce6c18ed7cbbfcd6fcf76598a6601dca8b98d9b6c1a2f
+size 114706

+ 6 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Images.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}

+ 24 - 0
CMakeTestbed/Gem/Resources/MacLauncher/Info.plist

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<false/>
+	<key>CFBundleDisplayName</key>
+	<string>CMakeTestbed</string>
+	<key>CFBundleExecutable</key>
+	<string>CMakeTestbed.GameLauncher</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.amazon.CMakeTestbed</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.5</string>
+	<key>CFBundleSignature</key>
+	<string>LMBR</string>
+	<key>CFBundleVersion</key>
+	<string>1.5</string>
+	<key>LSApplicationCategoryType</key>
+	<string>public.app-category.puzzle-games</string>
+</dict>
+</plist>

+ 16 - 0
CMakeTestbed/Gem/gem.json

@@ -0,0 +1,16 @@
+{
+    "GemFormatVersion": 4,
+    "Uuid": "e111dee500ed4812a7905093a73d3837",
+    "Name": "CMakeTestbed",
+    "DisplayName": "CMakeTestbed",
+    "Version": "0.1.0",
+    "Summary": "A short description of my Gem.",
+    "Tags": ["Game"],
+    "IconPath": "preview.png",
+    "IsGameGem": true,
+    "Modules": [
+        {
+            "Type": "GameModule"
+        }
+    ]
+}

+ 3 - 0
CMakeTestbed/Gem/preview.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6d6204c6730e5675791765ca194e9b1cbec282208e280507de830afc2805e5fa
+size 41127

+ 3 - 0
CMakeTestbed/Levels/default/default.ly

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:365efed3e5d9493b93938bbddf0f585e8ab97bdf8345b600eb62e1d1a83d06a2
+size 4976

+ 6 - 0
CMakeTestbed/Levels/default/filelist.xml

@@ -0,0 +1,6 @@
+<download name="default" type="Map">
+ <index src="filelist.xml" dest="filelist.xml"/>
+ <files>
+  <file src="level.pak" dest="level.pak" size="40248" md5="bd89c3b7a18fc0e72f66692d003252c8"/>
+ </files>
+</download>

+ 3 - 0
CMakeTestbed/Levels/default/level.pak

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:83049d899728ece361dec0bab708c7f35f5fd749c0d7050784d1e3d343f23834
+size 40573

+ 14 - 0
CMakeTestbed/Levels/default/leveldata/Environment.xml

@@ -0,0 +1,14 @@
+<Environment>
+ <Fog ViewDistance="8000" ViewDistanceLowSpec="1000"/>
+ <Terrain DetailLayersViewDistRatio="1.0" HeightMapAO="0"/>
+ <EnvState WindVector="1,0,0" BreezeGeneration="0" BreezeStrength="1.f" BreezeMovementSpeed="8.f" BreezeVariation="1.f" BreezeLifeTime="15.f" BreezeCount="4" BreezeSpawnRadius="25.f" BreezeSpread="0.f" BreezeRadius="5.f" ConsoleMergedMeshesPool="2750" ShowTerrainSurface="1" SunShadowsMinSpec="1" SunShadowsAdditionalCascadeMinSpec="0" SunShadowsClipPlaneRange="256.0f" SunShadowsClipPlaneRangeShift="0.0f" UseLayersActivation="0" SunLinkedToTOD="1"/>
+ <VolFogShadows Enable="0" EnableForClouds="0"/>
+ <CloudShadows CloudShadowTexture="" CloudShadowSpeed="0,0,0" CloudShadowTiling="1.0" CloudShadowBrightness="1.0" CloudShadowInvert="0"/>
+ <ParticleLighting AmbientMul="1.0" LightsMul="1.0"/>
+ <SkyBox Material="EngineAssets/Materials/Sky/Sky" MaterialLowSpec="EngineAssets/Materials/Sky/Sky" Angle="0" Stretching="0.5"/>
+ <Ocean Material="EngineAssets/Materials/Water/Ocean_default" CausticsDistanceAtten="100.0" CausticDepth="8.0" CausticIntensity="1.0" CausticsTilling="1.0"/>
+ <OceanAnimation WindDirection="1.0" WindSpeed="4.0" WavesAmount="1.5" WavesSize="0.4" WavesSpeed="1.0"/>
+ <Moon Latitude="240.0" Longitude="45.0" Size="0.5" Texture="Textures/Skys/Night/half_moon.dds"/>
+ <DynTexSource Width="256" Height="256"/>
+ <Total_Illumination_v2 Active="0" IntegrationMode="0" NumberOfBounces="1" DiffuseConeWidth="24" ConeMaxLength="12.0" UseLightProbes="0" InjectionMultiplier="1.0" AmbientOffsetRed="1.0" AmbientOffsetGreen="1.0" AmbientOffsetBlue="1.0" AmbientOffsetBias="0.1" Saturation="0.8" SSAOAmount="0.7"/>
+</Environment>

+ 5 - 0
CMakeTestbed/Levels/default/leveldata/GameTokens.xml

@@ -0,0 +1,5 @@
+<GameTokens>
+ <GameTokensLibrary>
+  <LevelLibrary Name="Level"/>
+ </GameTokensLibrary>
+</GameTokens>

+ 3 - 0
CMakeTestbed/Levels/default/leveldata/Heightmap.dat

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7250c99aa182bc1bde5fed50d3a8e950a724cb35e5e80570e0dfb6cdf07b1eab
+size 17407562

+ 7 - 0
CMakeTestbed/Levels/default/leveldata/TerrainTexture.xml

@@ -0,0 +1,7 @@
+<TerrainTexture TileCountX="1" TileCountY="1" TileResolution="512">
+ <RGBLayer>
+  <Tiles>
+   <tile X="0" Y="0" Size="512"/>
+  </Tiles>
+ </RGBLayer>
+</TerrainTexture>

+ 356 - 0
CMakeTestbed/Levels/default/leveldata/TimeOfDay.xml

@@ -0,0 +1,356 @@
+<TimeOfDay Time="13.5" TimeStart="13.5" TimeEnd="13.5" TimeAnimSpeed="0">
+ <Variable Name="Sun color" Color="0.99989021,0.99946922,0.9991194">
+  <Spline Keys="-0.000628322:(0.783538:0.89627:0.930341):36,0:(0.783538:0.887923:0.921582):36,0.229167:(0.783538:0.879623:0.921582):36,0.25:(0.947307:0.745404:0.577581):36,0.458333:(1:1:1):36,0.5625:(1:1:1):36,0.75:(0.947307:0.745404:0.577581):36,0.770833:(0.783538:0.879623:0.921582):36,1:(0.783538:0.89627:0.930556):36,"/>
+ </Variable>
+ <Variable Name="Sun intensity" Value="92366.68">
+  <Spline Keys="0:1000:36,0.229167:1000:36,0.5:120000:36,0.770833:1000:65572,0.999306:1000:36,"/>
+ </Variable>
+ <Variable Name="Sun specular multiplier" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:36,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Fog color" Color="0.27049801,0.47353199,0.83076996">
+  <Spline Keys="0:(0.00651209:0.00972122:0.0137021):36,0.229167:(0.00604883:0.00972122:0.0137021):36,0.25:(0.270498:0.473532:0.83077):36,0.5:(0.270498:0.473532:0.83077):458788,0.75:(0.270498:0.473532:0.83077):36,0.770833:(0.00604883:0.00972122:0.0137021):36,1:(0.00651209:0.00972122:0.0137021):36,"/>
+ </Variable>
+ <Variable Name="Fog color multiplier" Value="1">
+  <Spline Keys="0:0.5:36,0.229167:0.5:36,0.25:1:36,0.5:1:36,0.75:1:36,0.770833:0.5:36,1:0.5:65572,"/>
+ </Variable>
+ <Variable Name="Fog height (bottom)" Value="0">
+  <Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Fog layer density (bottom)" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:36,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Fog color (top)" Color="0.597202,0.72305501,0.91309899">
+  <Spline Keys="0:(0.00699541:0.00972122:0.0122865):36,0.229167:(0.00699541:0.00972122:0.0122865):36,0.25:(0.597202:0.723055:0.913099):36,0.5:(0.597202:0.723055:0.913099):458788,0.75:(0.597202:0.723055:0.913099):36,0.770833:(0.00699541:0.00972122:0.0122865):36,1:(0.00699541:0.00972122:0.0122865):36,"/>
+ </Variable>
+ <Variable Name="Fog color (top) multiplier" Value="0.88389361">
+  <Spline Keys="-4.40702e-06:0.5:36,0.0297507:0.499195:36,0.229167:0.5:36,0.5:1:36,0.770833:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Fog height (top)" Value="100.00001">
+  <Spline Keys="0:100:36,0.25:100:36,0.5:100:36,0.75:100:65572,1:100:36,"/>
+ </Variable>
+ <Variable Name="Fog layer density (top)" Value="9.9999997e-05">
+  <Spline Keys="0:0.0001:36,0.25:0.0001:36,0.5:0.0001:65572,0.75:0.0001:36,1:0.0001:36,"/>
+ </Variable>
+ <Variable Name="Fog color height offset" Value="0">
+  <Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:65572,"/>
+ </Variable>
+ <Variable Name="Fog color (radial)" Color="0.78592348,0.52744436,0.17234583">
+  <Spline Keys="0:(0:0:0):36,0.229167:(0.00439144:0.00367651:0.00334654):36,0.25:(0.838799:0.564712:0.184475):36,0.5:(0.768151:0.514918:0.168269):458788,0.75:(0.838799:0.564712:0.184475):36,0.770833:(0.00402472:0.00334654:0.00303527):36,1:(0:0:0):36,"/>
+ </Variable>
+ <Variable Name="Fog color (radial) multiplier" Value="6">
+  <Spline Keys="0:0:36,0.25:6:36,0.5:6:36,0.75:6:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Fog radial size" Value="0.85000002">
+  <Spline Keys="0:0:36,0.25:0.85:65572,0.5:0.85:36,0.75:0.85:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Fog radial lobe" Value="0.75">
+  <Spline Keys="0:0:36,0.25:0.75:36,0.5:0.75:36,0.75:0.75:65572,1:0:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Final density clamp" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Global density" Value="1.5">
+  <Spline Keys="0:1.5:36,0.25:1.5:36,0.5:1.5:65572,0.75:1.5:36,1:1.5:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Ramp start" Value="25.000002">
+  <Spline Keys="0:25:36,0.25:25:36,0.5:25:65572,0.75:25:36,1:25:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Ramp end" Value="1000.0001">
+  <Spline Keys="0:1000:36,0.25:1000:36,0.5:1000:65572,0.75:1000:36,1:1000:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Ramp influence" Value="0.69999993">
+  <Spline Keys="0:0.7:36,0.25:0.7:36,0.5:0.7:65572,0.75:0.7:36,1:0.7:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Shadow darkening" Value="0.20000002">
+  <Spline Keys="0:0.2:36,0.25:0.2:36,0.5:0.2:65572,0.75:0.2:36,1:0.2:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Shadow darkening sun" Value="0.5">
+  <Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Shadow darkening ambient" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog: Shadow range" Value="0.10000001">
+  <Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog height (bottom)" Value="0">
+  <Spline Keys="0:0:0,1:0:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog layer density (bottom)" Value="1">
+  <Spline Keys="0:1:0,1:1:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog height (top)" Value="4000">
+  <Spline Keys="0:4000:0,1:4000:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog layer density (top)" Value="9.9999997e-05">
+  <Spline Keys="0:0.0001:0,1:0.0001:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Global fog density" Value="0.1">
+  <Spline Keys="0:0.1:0,1:0.1:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Ramp start" Value="0">
+  <Spline Keys="0:0:0,1:0:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Ramp end" Value="0">
+  <Spline Keys="0:0:0,1:0:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog albedo color (atmosphere)" Color="1,1,1">
+  <Spline Keys="0:(1:1:1):0,1:(1:1:1):0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Anisotropy factor (atmosphere)" Value="0.60000002">
+  <Spline Keys="0:0.6:0,1:0.6:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog albedo color (sun radial)" Color="1,1,1">
+  <Spline Keys="0:(1:1:1):0,1:(1:1:1):0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Anisotropy factor (sun radial)" Value="0.94999999">
+  <Spline Keys="0:0.95:0,1:0.95:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Blend factor for sun scattering" Value="1">
+  <Spline Keys="0:1:0,1:1:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Blend mode for sun scattering" Value="0">
+  <Spline Keys="0:0:0,1:0:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Fog albedo color (entities)" Color="1,1,1">
+  <Spline Keys="0:(1:1:1):0,1:(1:1:1):0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Anisotropy factor (entities)" Value="0.60000002">
+  <Spline Keys="0:0.6:0,1:0.6:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Maximum range of ray-marching" Value="64">
+  <Spline Keys="0:64:0,1:64:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: In-scattering factor" Value="1">
+  <Spline Keys="0:1:0,1:1:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Extinction factor" Value="0.30000001">
+  <Spline Keys="0:0.3:0,1:0.3:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Analytical volumetric fog visibility" Value="0.5">
+  <Spline Keys="0:0.5:0,1:0.5:0,"/>
+ </Variable>
+ <Variable Name="Volumetric fog 2: Final density clamp" Value="1">
+  <Spline Keys="0:1:0,0.5:1:36,1:1:0,"/>
+ </Variable>
+ <Variable Name="Sky light: Sun intensity" Color="1,1,1">
+  <Spline Keys="0:(1:1:1):36,0.25:(1:1:1):36,0.494381:(1:1:1):65572,0.5:(1:1:1):36,0.75:(1:1:1):36,1:(1:1:1):36,"/>
+ </Variable>
+ <Variable Name="Sky light: Sun intensity multiplier" Value="200.00002">
+  <Spline Keys="0:200:36,0.25:200:36,0.5:200:36,0.75:200:36,1:200:36,"/>
+ </Variable>
+ <Variable Name="Sky light: Mie scattering" Value="6.779707">
+  <Spline Keys="0:40:36,0.5:2:36,1:40:36,"/>
+ </Variable>
+ <Variable Name="Sky light: Rayleigh scattering" Value="0.20000002">
+  <Spline Keys="0:0.2:36,0.229167:0.2:36,0.25:1:36,0.291667:0.2:36,0.5:0.2:36,0.729167:0.2:36,0.75:1:36,0.770833:0.2:36,1:0.2:36,"/>
+ </Variable>
+ <Variable Name="Sky light: Sun anisotropy factor" Value="-0.99989998">
+  <Spline Keys="0:-0.9999:36,0.25:-0.9999:36,0.5:-0.9999:65572,0.75:-0.9999:36,1:-0.9999:36,"/>
+ </Variable>
+ <Variable Name="Sky light: Wavelength (R)" Value="694">
+  <Spline Keys="0:694:36,0.25:694:36,0.5:694:65572,0.75:694:36,1:694:36,"/>
+ </Variable>
+ <Variable Name="Sky light: Wavelength (G)" Value="596.99994">
+  <Spline Keys="0:597:36,0.25:597:36,0.5:597:36,0.75:597:36,1:597:36,"/>
+ </Variable>
+ <Variable Name="Sky light: Wavelength (B)" Value="488">
+  <Spline Keys="0:488:36,0.25:488:36,0.5:488:65572,0.75:488:36,1:488:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Horizon color" Color="0.27049801,0.39157301,0.52711499">
+  <Spline Keys="0:(0.270498:0.391573:0.520996):36,0.25:(0.270498:0.391573:0.527115):36,0.5:(0.270498:0.391573:0.527115):262180,0.75:(0.270498:0.391573:0.527115):36,1:(0.270498:0.391573:0.520996):36,"/>
+ </Variable>
+ <Variable Name="Night sky: Horizon color multiplier" Value="0">
+  <Spline Keys="0:0.1:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Zenith color" Color="0.36130697,0.434154,0.46778399">
+  <Spline Keys="0:(0.361307:0.434154:0.467784):36,0.25:(0.361307:0.434154:0.467784):36,0.5:(0.361307:0.434154:0.467784):262180,0.75:(0.361307:0.434154:0.467784):36,1:(0.361307:0.434154:0.467784):36,"/>
+ </Variable>
+ <Variable Name="Night sky: Zenith color multiplier" Value="0">
+  <Spline Keys="0:0.02:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.02:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Zenith shift" Value="0.5">
+  <Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Star intensity" Value="0">
+  <Spline Keys="0:3:36,0.25:0:36,0.5:0:65572,0.75:0:36,0.836647:1.03977:36,1:3:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon color" Color="1,1,1">
+  <Spline Keys="0:(1:1:1):36,0.25:(1:1:1):36,0.5:(1:1:1):458788,0.75:(1:1:1):36,1:(1:1:1):36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon color multiplier" Value="0">
+  <Spline Keys="0:0.4:36,0.25:0:36,0.5:0:36,0.75:0:65572,1:0.4:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon inner corona color" Color="0.904661,1,1">
+  <Spline Keys="0:(0.89627:1:1):36,0.25:(0.904661:1:1):36,0.5:(0.904661:1:1):393252,0.75:(0.904661:1:1):36,0.836647:(0.89627:1:1):36,1:(0.89627:1:1):36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon inner corona color multiplier" Value="0">
+  <Spline Keys="0:0.1:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon inner corona scale" Value="0">
+  <Spline Keys="0:2:36,0.25:0:36,0.5:0:65572,0.75:0:36,0.836647:0.693178:36,1:2:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon outer corona color" Color="0.201556,0.22696599,0.25415203">
+  <Spline Keys="0:(0.198069:0.226966:0.250158):36,0.25:(0.201556:0.226966:0.254152):36,0.5:(0.201556:0.226966:0.254152):36,0.75:(0.201556:0.226966:0.254152):36,1:(0.198069:0.226966:0.250158):36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon outer corona color multiplier" Value="0">
+  <Spline Keys="0:0.1:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Night sky: Moon outer corona scale" Value="0">
+  <Spline Keys="0:0.01:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.01:36,"/>
+ </Variable>
+ <Variable Name="Cloud shading: Sun light multiplier" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Cloud shading: Sun custom color" Color="0.83076996,0.76815104,0.65837508">
+  <Spline Keys="0:(0.737911:0.737911:0.737911):36,0.25:(0.83077:0.768151:0.658375):36,0.5:(0.83077:0.768151:0.658375):458788,0.75:(0.83077:0.768151:0.658375):36,1:(0.737911:0.737911:0.737911):36,"/>
+ </Variable>
+ <Variable Name="Cloud shading: Sun custom color multiplier" Value="1">
+  <Spline Keys="0:0.1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cloud shading: Sun custom color influence" Value="0">
+  <Spline Keys="0:0.5:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Sun shafts visibility" Value="0">
+  <Spline Keys="0:0:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Sun rays visibility" Value="1.5">
+  <Spline Keys="0:1:36,0.25:1.5:36,0.5:1.5:65572,0.75:1.5:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Sun rays attenuation" Value="1.5">
+  <Spline Keys="0:0.1:36,0.25:1.5:36,0.5:1.5:65572,0.75:1.5:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Sun rays suncolor influence" Value="0.5">
+  <Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Sun rays custom color" Color="0.66538697,0.83879906,0.94730699">
+  <Spline Keys="0:(0.665387:0.838799:0.947307):36,0.25:(0.665387:0.838799:0.947307):36,0.5:(0.665387:0.838799:0.947307):458788,0.75:(0.665387:0.838799:0.947307):36,1:(0.665387:0.838799:0.947307):36,"/>
+ </Variable>
+ <Variable Name="Ocean fog color" Color="0.0012141101,0.0091340598,0.017642001">
+  <Spline Keys="0:(0.00121411:0.00913406:0.017642):36,0.25:(0.00121411:0.00913406:0.017642):36,0.5:(0.00121411:0.00913406:0.017642):458788,0.75:(0.00121411:0.00913406:0.017642):36,1:(0.00121411:0.00913406:0.017642):36,"/>
+ </Variable>
+ <Variable Name="Ocean fog color multiplier" Value="0.5">
+  <Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Ocean fog density" Value="0.5">
+  <Spline Keys="0:0.5:36,0.25:0.5:36,0.5:0.5:65572,0.75:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Static skybox multiplier" Value="1">
+  <Spline Keys="0:1:0,1:1:0,"/>
+ </Variable>
+ <Variable Name="Film curve shoulder scale" Value="2.232213">
+  <Spline Keys="0:3:36,0.229167:3:36,0.5:2:36,0.770833:3:36,1:3:36,"/>
+ </Variable>
+ <Variable Name="Film curve midtones scale" Value="0.88389361">
+  <Spline Keys="0:0.5:36,0.229167:0.5:36,0.5:1:36,0.770833:0.5:36,1:0.5:36,"/>
+ </Variable>
+ <Variable Name="Film curve toe scale" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Film curve whitepoint" Value="4">
+  <Spline Keys="0:4:36,0.25:4:36,0.5:4:65572,0.75:4:36,1:4:36,"/>
+ </Variable>
+ <Variable Name="Saturation" Value="1">
+  <Spline Keys="0:0.8:36,0.229167:0.8:36,0.5:1:36,0.751391:1:65572,0.770833:0.8:36,1:0.8:36,"/>
+ </Variable>
+ <Variable Name="Color balance" Color="1,1,1">
+  <Spline Keys="0:(1:1:1):36,0.25:(1:1:1):36,0.5:(1:1:1):36,0.75:(1:1:1):36,1:(1:1:1):36,"/>
+ </Variable>
+ <Variable Name="Scene key" Value="0.18000002">
+  <Spline Keys="0:0.18:36,0.25:0.18:36,0.5:0.18:65572,0.75:0.18:36,1:0.18:36,"/>
+ </Variable>
+ <Variable Name="Min exposure" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Max exposure" Value="2.6142297">
+  <Spline Keys="0:2:36,0.229167:2:36,0.5:2.8:36,0.770833:2:36,1:2:36,"/>
+ </Variable>
+ <Variable Name="EV Min" Value="4.5">
+  <Spline Keys="0:4.5:0,1:4.5:0,"/>
+ </Variable>
+ <Variable Name="EV Max" Value="17">
+  <Spline Keys="0:17:0,1:17:0,"/>
+ </Variable>
+ <Variable Name="EV Auto compensation" Value="1.5">
+  <Spline Keys="0:1.5:0,1:1.5:0,"/>
+ </Variable>
+ <Variable Name="Bloom amount" Value="0.30899152">
+  <Spline Keys="0:1:36,0.229167:1:36,0.5:0.1:36,0.770833:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Filters: grain" Value="0">
+  <Spline Keys="0:0.3:65572,0.229167:0.3:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0.3:36,"/>
+ </Variable>
+ <Variable Name="Filters: photofilter color" Color="0,0,0">
+  <Spline Keys="0:(0:0:0):36,0.25:(0:0:0):36,0.5:(0:0:0):458788,0.75:(0:0:0):36,1:(0:0:0):36,"/>
+ </Variable>
+ <Variable Name="Filters: photofilter density" Value="0">
+  <Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Dof: focus range" Value="500.00003">
+  <Spline Keys="0:500:36,0.25:500:36,0.5:500:65572,0.75:500:36,1:500:36,"/>
+ </Variable>
+ <Variable Name="Dof: blur amount" Value="0.10000001">
+  <Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 0: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 0: Slope Bias" Value="64">
+  <Spline Keys="0:64:36,0.25:64:36,0.5:64:65572,0.75:64:36,1:64:36,"/>
+ </Variable>
+ <Variable Name="Cascade 1: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 1: Slope Bias" Value="23">
+  <Spline Keys="0:23:36,0.25:23:36,0.5:23:65572,0.75:23:36,1:23:36,"/>
+ </Variable>
+ <Variable Name="Cascade 2: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 2: Slope Bias" Value="4">
+  <Spline Keys="0:4:36,0.25:4:36,0.5:4:65572,0.75:4:36,1:4:36,"/>
+ </Variable>
+ <Variable Name="Cascade 3: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:36,0.25:0.1:36,0.5:0.1:36,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 3: Slope Bias" Value="1">
+  <Spline Keys="0:1:36,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 4: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:0,0.25:0.1:36,0.5:0.1:65572,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 4: Slope Bias" Value="1">
+  <Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 5: Bias" Value="0.0099999998">
+  <Spline Keys="0:0.01:0,0.25:0.01:36,0.5:0.01:65572,0.75:0.01:36,1:0.01:36,"/>
+ </Variable>
+ <Variable Name="Cascade 5: Slope Bias" Value="1">
+  <Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 6: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:0,0.25:0.1:36,0.5:0.1:36,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 6: Slope Bias" Value="1">
+  <Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 7: Bias" Value="0.10000001">
+  <Spline Keys="0:0.1:0,0.25:0.1:36,0.5:0.1:36,0.75:0.1:36,1:0.1:36,"/>
+ </Variable>
+ <Variable Name="Cascade 7: Slope Bias" Value="1">
+  <Spline Keys="0:1:0,0.25:1:36,0.5:1:65572,0.75:1:36,1:1:36,"/>
+ </Variable>
+ <Variable Name="Shadow jittering" Value="2.4999998">
+  <Spline Keys="0:5:36,0.25:2.5:36,0.5:2.5:65572,0.75:2.5:36,1:5:0,"/>
+ </Variable>
+ <Variable Name="HDR dynamic power factor" Value="0">
+  <Spline Keys="0:0:36,0.25:0:36,0.5:0:65572,0.75:0:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Sky brightening (terrain occlusion)" Value="0">
+  <Spline Keys="0:0:36,0.25:0:36,0.5:0:36,0.75:0:36,1:0:36,"/>
+ </Variable>
+ <Variable Name="Sun color multiplier" Value="9.999999">
+  <Spline Keys="0:0.1:36,0.25:10:36,0.5:10:36,0.75:10:36,1:0.1:36,"/>
+ </Variable>
+</TimeOfDay>

+ 3 - 0
CMakeTestbed/Levels/default/leveldata/VegetationMap.dat

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0e6a5435c928079b27796f6b202bbc2623e7e454244ddc099a3cadf33b7cb9e9
+size 63

+ 12 - 0
CMakeTestbed/Levels/default/tags.txt

@@ -0,0 +1,12 @@
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0
+0,0,0,0,0,0

+ 3 - 0
CMakeTestbed/Levels/default/terrain/cover.ctc

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:eee27982bfd7ad92814e2287d5fae32f943a470120550e2ac93d2299a4969876
+size 1310792

+ 3 - 0
CMakeTestbed/Levels/default/terraintexture.pak

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85
+size 22

+ 1 - 0
CMakeTestbed/autoexec.cfg

@@ -0,0 +1 @@
+map default

+ 7 - 0
CMakeTestbed/game.cfg

@@ -0,0 +1,7 @@
+sys_game_name = "CMakeTestbed"
+sys_localization_folder = Localization
+ca_useIMG_CAF = 0
+
+-- Enable warnings when asset loads take longer than the given millisecond threshold
+cl_assetLoadWarningEnable=true
+cl_assetLoadWarningMsThreshold=100

+ 53 - 0
CMakeTestbed/gems.json

@@ -0,0 +1,53 @@
+{
+    "GemListFormatVersion": 2, 
+    "Gems": [
+        {
+            "Path": "Gems/ImageProcessing",
+            "Uuid": "eeffbd9211cf4ce0b5cc73696b427cbe",
+            "Version": "0.1.0",
+            "_comment": "ImageProcessing"
+        },
+        {
+            "Path": "Gems/TextureAtlas",
+            "Uuid": "5a149b6b3c964064bd4970f0e92f72e2",
+            "Version": "0.1.0",
+            "_comment": "TextureAtlas"
+        },
+        {
+            "Path": "Gems/LmbrCentral",
+            "Uuid": "ff06785f7145416b9d46fde39098cb0c",
+            "Version": "0.1.0",
+            "_comment": "LmbrCentral"
+        },
+        {
+            "Path": "Gems/LyShine",
+            "Uuid": "0fefab3f13364722b2eab3b96ce2bf20",
+            "Version": "0.1.0",
+            "_comment": "LyShine"
+        },
+        {
+            "Path": "Gems/Maestro",
+            "Uuid": "3b9a978ed6f742a1acb99f74379a342c",
+            "Version": "0.1.0",
+            "_comment": "Maestro"
+        },
+        {
+            "Path": "Gems/SceneProcessing",
+            "Uuid": "7c2578f634df4345aca98d671e39b8ab",
+            "Version": "0.1.0",
+            "_comment": "SceneProcessing"
+        },
+        {
+            "Path": "Gems/Camera",
+            "Uuid": "f910686b6725452fbfc4671f95f733c6",
+            "Version": "0.1.0",
+            "_comment": "Camera"
+        },
+        {
+            "Path" : "CMakeTestbed/Gem",
+            "Uuid" : "e111dee500ed4812a7905093a73d3837",
+            "Version" : "0.1.0",
+            "_comment" : "CMakeTestbed"
+        }
+   ]
+}

+ 3 - 0
CMakeTestbed/preview.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a18fae4040a22d2bb359a8ca642b97bb8f6468eeb52e2826b3b029bd8f1350b6
+size 5466

+ 14 - 0
CMakeTestbed/project.json

@@ -0,0 +1,14 @@
+{
+    "project_name": "CMakeTestbed",
+    "product_name": "CMakeTestbed",
+    "executable_name": "CMakeTestbedLauncher",
+    "modules" : [],
+    "project_id": "{4F3363D3-4A7C-47A6-B464-B21524771358}",
+
+    "android_settings" : {
+        "package_name" : "com.lumberyard.yourgame",
+        "version_number" : 1,
+        "version_name" : "1.0.0.0",
+        "orientation" : "landscape"
+    }
+}

+ 6 - 0
Code/.p4ignore

@@ -0,0 +1,6 @@
+#Ignore these directories
+SDKs
+
+#ColinB (8/26)- I know there are depot files that this will ignore... But these files should not be
+#here, they should all be in 3rdParty... so we will ignore them until I can move them, it should
+#be OK for now because they shouldn't change at all anyway.

+ 16 - 0
Code/CMakeLists.txt

@@ -0,0 +1,16 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+add_subdirectory(CryEngine)
+add_subdirectory(Framework)
+add_subdirectory(LauncherUnified)
+add_subdirectory(Sandbox)
+add_subdirectory(Tools)

+ 17 - 0
Code/CryEngine/CMakeLists.txt

@@ -0,0 +1,17 @@
+#
+# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+# its licensors.
+#
+# For complete copyright and license terms please see the LICENSE at the root of this
+# distribution (the "License"). All use of this software is governed by the License,
+# or, if provided, by the license below or the license accompanying this file. Do not
+# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#
+
+add_subdirectory(Cry3DEngine)
+add_subdirectory(CryCommon)
+add_subdirectory(CryFont)
+add_subdirectory(CryNetwork)
+add_subdirectory(CrySystem)
+add_subdirectory(RenderDll)

+ 733 - 0
Code/CryEngine/Cry3DEngine/3DEngineLight.cpp

@@ -0,0 +1,733 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+// Original file Copyright Crytek GMBH or its affiliates, used under license.
+
+// Description : Light sources manager
+
+
+#include "Cry3DEngine_precompiled.h"
+
+#include "3dEngine.h"
+#include "ObjMan.h"
+#include "VisAreas.h"
+#include "AABBSV.h"
+#include "LightEntity.h"
+#include "ObjectsTree.h"
+#include "ClipVolumeManager.h"
+
+ILightSource* C3DEngine::CreateLightSource()
+{
+    // construct new object
+    CLightEntity* pLightEntity = new CLightEntity();
+
+    m_lstStaticLights.Add(pLightEntity);
+
+    return pLightEntity;
+}
+
+void C3DEngine::DeleteLightSource(ILightSource* pLightSource)
+{
+    if (m_lstStaticLights.Delete((CLightEntity*)pLightSource) || pLightSource == m_pSun)
+    {
+        if (pLightSource == m_pSun)
+        {
+            m_pSun = NULL;
+        }
+
+        delete pLightSource;
+    }
+    else
+    {
+        assert(!"Light object not found");
+    }
+}
+
+void CLightEntity::Release(bool)
+{
+    Get3DEngine()->UnRegisterEntityDirect(this);
+    Get3DEngine()->DeleteLightSource(this);
+}
+
+void CLightEntity::SetLightProperties(const CDLight& light)
+{
+    C3DEngine* engine = Get3DEngine();
+
+    m_light = light;
+
+    m_bShadowCaster = (m_light.m_Flags & DLF_CASTSHADOW_MAPS) != 0;
+
+    m_light.m_fBaseRadius = m_light.m_fRadius;
+    m_light.m_fLightFrustumAngle = CLAMP(m_light.m_fLightFrustumAngle, 0.f, (LIGHT_PROJECTOR_MAX_FOV / 2.f));
+
+    if (!(m_light.m_Flags & (DLF_PROJECT | DLF_AREA_LIGHT)))
+    {
+        m_light.m_fLightFrustumAngle = 90.f / 2.f;
+    }
+
+    m_light.m_pOwner = this;
+
+    if (m_light.m_Flags & DLF_ATTACH_TO_SUN)
+    {
+        m_dwRndFlags |= ERF_RENDER_ALWAYS | ERF_HUD;
+    }
+
+    engine->GetLightEntities()->Delete((ILightSource*)this);
+
+    PodArray<ILightSource*>& lightEntities = *engine->GetLightEntities();
+
+    //on consoles we force all lights (except sun) to be deferred
+    if (GetCVars()->e_DynamicLightsForceDeferred && !(m_light.m_Flags & (DLF_SUN | DLF_POST_3D_RENDERER)))
+    {
+        m_light.m_Flags |= DLF_DEFERRED_LIGHT;
+    }
+
+    if (light.m_Flags & DLF_DEFERRED_LIGHT)
+    {
+        lightEntities.Add((ILightSource*)this);
+    }
+    else
+    {
+        lightEntities.InsertBefore((ILightSource*)this, 0);
+    }
+}
+
+void C3DEngine::ResetCasterCombinationsCache()
+{
+    for (int nSunInUse = 0; nSunInUse < 2; nSunInUse++)
+    {
+        // clear user counters
+        for (ShadowFrustumListsCacheUsers::iterator it = m_FrustumsCacheUsers[nSunInUse].begin(); it != m_FrustumsCacheUsers[nSunInUse].end(); ++it)
+        {
+            it->second = 0;
+        }
+    }
+}
+
+void C3DEngine::DeleteAllStaticLightSources()
+{
+    for (int i = 0; i < m_lstStaticLights.Count(); i++)
+    {
+        delete m_lstStaticLights[i];
+    }
+    m_lstStaticLights.Reset();
+
+    m_pSun = NULL;
+}
+
+void C3DEngine::InitShadowFrustums(const SRenderingPassInfo& passInfo)
+{
+    assert(passInfo.IsGeneralPass());
+    FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
+    AZ_TRACE_METHOD();
+
+    if (m_pSun)
+    {
+        CDLight* pLight = &m_pSun->GetLightProperties();
+        CLightEntity* pLightEntity = (CLightEntity*)pLight->m_pOwner;
+
+        if (passInfo.RenderShadows() && (pLight->m_Flags & DLF_CASTSHADOW_MAPS) && pLight->m_Id >= 0)
+        {
+            pLightEntity->UpdateGSMLightSourceShadowFrustum(passInfo);
+
+            if (pLightEntity->m_pShadowMapInfo)
+            {
+                pLight->m_pShadowMapFrustums = pLightEntity->m_pShadowMapInfo->pGSM;
+            }
+        }
+
+        _smart_ptr<IMaterial> pMat = pLightEntity->GetMaterial();
+        if (pMat)
+        {
+            pLight->m_Shader = pMat->GetShaderItem();
+        }
+
+        // update copy of light ion the renderer
+        if (pLight->m_Id >= 0)
+        {
+            CDLight* pRndLight = NULL;
+            GetRenderer()->EF_Query(EFQ_LightSource, pLight->m_Id, pRndLight);
+            assert(pLight->m_Id == pRndLight->m_Id);
+            pRndLight->m_pShadowMapFrustums = pLight->m_pShadowMapFrustums;
+            pRndLight->m_Shader = pLight->m_Shader;
+            pRndLight->m_Flags = pLight->m_Flags;
+        }
+
+        // add per object shadow frustums
+        m_nCustomShadowFrustumCount = 0;
+        if (passInfo.RenderShadows() &&  GetCVars()->e_ShadowsPerObject > 0)
+        {
+            const uint nFrustumCount = m_lstPerObjectShadows.size();
+            if (nFrustumCount > m_lstCustomShadowFrustums.size())
+            {
+                m_lstCustomShadowFrustums.resize(nFrustumCount);
+            }
+
+            for (uint i = 0; i < nFrustumCount; ++i)
+            {
+                if (m_lstPerObjectShadows[i].pCaster)
+                {
+                    ShadowMapFrustum* pFr = &m_lstCustomShadowFrustums[i];
+                    pFr->m_eFrustumType = ShadowMapFrustum::e_PerObject;
+
+                    CLightEntity::ProcessPerObjectFrustum(pFr, &m_lstPerObjectShadows[i], m_pSun, passInfo);
+                    ++m_nCustomShadowFrustumCount;
+                }
+            }
+        }
+    }
+
+    if (passInfo.RenderShadows())
+    {
+        ResetCasterCombinationsCache();
+    }
+}
+
+void C3DEngine::AddPerObjectShadow(IShadowCaster* pCaster, float fConstBias, float fSlopeBias, float fJitter, const Vec3& vBBoxScale, uint nTexSize)
+{
+    SPerObjectShadow* pOS = GetPerObjectShadow(pCaster);
+    if (!pOS)
+    {
+        pOS = &m_lstPerObjectShadows.AddNew();
+    }
+
+    pOS->pCaster = pCaster;
+    pOS->fConstBias = fConstBias;
+    pOS->fSlopeBias = fSlopeBias;
+    pOS->fJitter = fJitter;
+    pOS->vBBoxScale = vBBoxScale;
+    pOS->nTexSize = nTexSize;
+}
+
+void C3DEngine::RemovePerObjectShadow(IShadowCaster* pCaster)
+{
+    SPerObjectShadow* pOS = GetPerObjectShadow(pCaster);
+    if (pOS)
+    {
+        FRAME_PROFILER("C3DEngine::RemovePerObjectShadow", GetSystem(), PROFILE_3DENGINE);
+
+        size_t nIndex = (size_t)(pOS - m_lstPerObjectShadows.begin());
+        m_lstPerObjectShadows.Delete(nIndex);
+    }
+}
+
+struct SPerObjectShadow* C3DEngine::GetPerObjectShadow(IShadowCaster* pCaster)
+{
+    for (int i = 0; i < m_lstPerObjectShadows.Count(); ++i)
+    {
+        if (m_lstPerObjectShadows[i].pCaster == pCaster)
+        {
+            return &m_lstPerObjectShadows[i];
+        }
+    }
+
+    return NULL;
+}
+
+void C3DEngine::GetCustomShadowMapFrustums(ShadowMapFrustum*& arrFrustums, int& nFrustumCount)
+{
+    arrFrustums = m_lstCustomShadowFrustums.begin();
+    nFrustumCount = m_nCustomShadowFrustumCount;
+}
+
+//  delete pLight->m_pProjCamera;
+//pLight->m_pProjCamera=0;
+//if(pLight->m_pShader)
+//      SAFE_RELEASE(pLight->m_pShader);
+namespace
+{
+    static inline bool CmpCastShadowFlag(const CDLight* p1, const CDLight* p2)
+    {
+        // move sun first
+        if ((p1->m_Flags & DLF_SUN) > (p2->m_Flags & DLF_SUN))
+        {
+            return true;
+        }
+        else if ((p1->m_Flags & DLF_SUN) < (p2->m_Flags & DLF_SUN))
+        {
+            return false;
+        }
+
+        // move shadow casters first
+        if ((p1->m_Flags & DLF_CASTSHADOW_MAPS) > (p2->m_Flags & DLF_CASTSHADOW_MAPS))
+        {
+            return true;
+        }
+        else if ((p1->m_Flags & DLF_CASTSHADOW_MAPS) < (p2->m_Flags & DLF_CASTSHADOW_MAPS))
+        {
+            return false;
+        }
+
+        // get some sorting consistency for shadow casters
+        if (p1->m_pOwner > p2->m_pOwner)
+        {
+            return true;
+        }
+        else if (p1->m_pOwner < p2->m_pOwner)
+        {
+            return false;
+        }
+
+        return false;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void C3DEngine::SubmitSun(const SRenderingPassInfo& passInfo)
+{
+    assert(passInfo.IsGeneralPass());
+    FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
+    AZ_TRACE_METHOD();
+
+    if (m_pSun)
+    {
+        CDLight* light = &m_pSun->GetLightProperties();
+
+        GetRenderer()->EF_ADDDlight(light, passInfo);
+    }
+}
+
+void C3DEngine::RemoveEntityLightSources(IRenderNode* pEntity)
+{
+    for (int i = 0; i < m_lstStaticLights.Count(); i++)
+    {
+        if (m_lstStaticLights[i] == pEntity)
+        {
+            m_lstStaticLights.Delete(i);
+            if (pEntity == m_pSun)
+            {
+                m_pSun = NULL;
+            }
+            i--;
+        }
+    }
+}
+
+ILightSource* C3DEngine::GetSunEntity()
+{
+    return m_pSun;
+}
+
+void C3DEngine::OnCasterDeleted(IShadowCaster* pCaster)
+{
+    FUNCTION_PROFILER(gEnv->pSystem, PROFILE_3DENGINE);
+    { // make sure pointer to object will not be used somewhere in the renderer
+        if (m_pSun)
+        {
+            m_pSun->OnCasterDeleted(pCaster);
+        }
+
+        if (GetRenderer()->GetActiveGPUCount() > 1)
+        {
+            if (ShadowFrustumMGPUCache* pFrustumCache = GetRenderer()->GetShadowFrustumMGPUCache())
+            {
+                pFrustumCache->DeleteFromCache(pCaster);
+            }
+        }
+
+        // remove from per object shadows list
+        RemovePerObjectShadow(pCaster);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void CLightVolumesMgr::Init()
+{
+    m_bUpdateLightVolumes = false;
+    for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
+    {
+        m_pLightVolumes[i].reserve(LV_MAX_COUNT);
+        m_pLightVolsInfo[i].reserve(LV_MAX_COUNT);
+    }
+    memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
+    memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
+}
+
+void CLightVolumesMgr::Reset()
+{
+    for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
+    {
+        stl::free_container(m_pLightVolumes[i]);
+    }
+
+    m_bUpdateLightVolumes = false;
+    memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
+    memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+uint16 CLightVolumesMgr::RegisterVolume(const Vec3& vPos, f32 fRadius, uint8 nClipVolumeRef, const SRenderingPassInfo& passInfo)
+{
+    DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
+
+    IF ((m_bUpdateLightVolumes && (lightVolsInfo.size() < LV_MAX_COUNT)) && fRadius < 256.0f, 1)
+    {
+        FUNCTION_PROFILER_3DENGINE;
+
+        int32 nPosx = (int32)(floorf(vPos.x * LV_CELL_RSIZEX));
+        int32 nPosy = (int32)(floorf(vPos.y * LV_CELL_RSIZEY));
+        int32 nPosz = (int32)(floorf(vPos.z * LV_CELL_RSIZEZ));
+
+        // Check if world cell has any light volume, else add new one
+        uint16 nHashIndex = GetWorldHashBucketKey(nPosx, nPosy, nPosz);
+        uint16* pCurrentVolumeID = &m_nWorldCells[nHashIndex];
+
+        while (*pCurrentVolumeID != 0)
+        {
+            SLightVolInfo& sVolInfo = *lightVolsInfo[*pCurrentVolumeID - 1];
+
+            int32 nVolumePosx = (int32)(floorf(sVolInfo.vVolume.x * LV_CELL_RSIZEX));
+            int32 nVolumePosy = (int32)(floorf(sVolInfo.vVolume.y * LV_CELL_RSIZEY));
+            int32 nVolumePosz = (int32)(floorf(sVolInfo.vVolume.z * LV_CELL_RSIZEZ));
+
+            if (nPosx == nVolumePosx &&
+                nPosy == nVolumePosy &&
+                nPosz == nVolumePosz &&
+                nClipVolumeRef  == sVolInfo.nClipVolumeID)
+            {
+                return (uint16) * pCurrentVolumeID;
+            }
+
+            pCurrentVolumeID = &sVolInfo.nNextVolume;
+        }
+
+        // create new volume
+        SLightVolInfo* pLightVolInfo = new SLightVolInfo(vPos, fRadius, nClipVolumeRef);
+        lightVolsInfo.push_back(pLightVolInfo);
+        *pCurrentVolumeID = lightVolsInfo.size();
+
+        return *pCurrentVolumeID;
+    }
+
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CLightVolumesMgr::RegisterLight(const CDLight& pDL, uint32 nLightID, [[maybe_unused]] const SRenderingPassInfo& passInfo)
+{
+    IF ((m_bUpdateLightVolumes && !(pDL.m_Flags & LV_DLF_LIGHTVOLUMES_MASK)), 1)
+    {
+        FUNCTION_PROFILER_3DENGINE;
+
+        const f32 fColCheck = (f32) fsel(pDL.m_Color.r + pDL.m_Color.g + pDL.m_Color.b - 0.333f, 1.0f, 0.0f);  //light color > threshold
+        const f32 fRadCheck = (f32) fsel(pDL.m_fRadius - 0.5f, 1.0f, 0.0f);  //light radius > threshold
+        if (fColCheck * fRadCheck)
+        {
+            //if the radius is large than certain value, all the the world light cells will be lighted anyway. So we just add the light to all the cells
+            //the input radius restriction will be added too
+            if(floorf(pDL.m_fRadius*LV_LIGHT_CELL_R_SIZE) > LV_LIGHTS_WORLD_BUCKET_SIZE)
+            {
+                for (int32 idx = 0; idx < LV_LIGHTS_WORLD_BUCKET_SIZE; idx++)
+                {
+                    SLightCell& lightCell = m_pWorldLightCells[idx];
+                    CryPrefetch(&lightCell);
+                    if (lightCell.nLightCount < LV_LIGHTS_MAX_COUNT)
+                    {
+                        lightCell.nLightID[lightCell.nLightCount] = nLightID;
+                        lightCell.nLightCount += 1;
+                    }
+                }
+            }
+            else
+            {
+                int32 nMiny = (int32)(floorf((pDL.m_Origin.y - pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
+                int32 nMaxy = (int32)(floorf((pDL.m_Origin.y + pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
+                int32 nMinx = (int32)(floorf((pDL.m_Origin.x - pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
+                int32 nMaxx = (int32)(floorf((pDL.m_Origin.x + pDL.m_fRadius) * LV_LIGHT_CELL_R_SIZE));
+
+                // Register light into all cells touched by light radius
+                for (int32 y = nMiny, ymax = nMaxy; y <= ymax; ++y)
+                {
+                    for (int32 x = nMinx, xmax = nMaxx; x <= xmax; ++x)
+                    {
+                        SLightCell& lightCell = m_pWorldLightCells[GetWorldHashBucketKey(x, y, 1, LV_LIGHTS_WORLD_BUCKET_SIZE)];
+                        CryPrefetch(&lightCell);
+                        if (lightCell.nLightCount < LV_LIGHTS_MAX_COUNT)
+                        {
+                            //only if the las light added to the cell wasn't the same light
+                            if (!(lightCell.nLightCount > 0 && lightCell.nLightID[lightCell.nLightCount - 1] == nLightID))
+                            {
+                                lightCell.nLightID[lightCell.nLightCount] = nLightID;
+                                lightCell.nLightCount += 1;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CLightVolumesMgr::AddLight(const SRenderLight& pLight, const SLightVolInfo* __restrict pVolInfo, SLightVolume& pVolume)
+{
+    // Check for clip volume
+    if (pLight.m_nStencilRef[0] == pVolInfo->nClipVolumeID || pLight.m_nStencilRef[1] == pVolInfo->nClipVolumeID ||
+        pLight.m_nStencilRef[0] == CClipVolumeManager::AffectsEverythingStencilRef)
+    {
+        const Vec4* __restrict vLight = (Vec4*) &pLight.m_Origin.x;
+        const Vec4& vVolume = pVolInfo->vVolume;
+        const f32 fDimCheck = (f32) fsel(vLight->w - vVolume.w * 0.1f, 1.0f, 0.0f);  //light radius not more than 10x smaller than volume radius
+        const f32 fOverlapCheck = (f32) fsel(sqr(vVolume.x - vLight->x) + sqr(vVolume.y - vLight->y) + sqr(vVolume.z - vLight->z) - sqr(vVolume.w + vLight->w), 0.0f, 1.0f);// touches volumes
+        if (fDimCheck * fOverlapCheck)
+        {
+            float fAttenuationBulbSize = pLight.m_fAttenuationBulbSize;
+            Vec3 lightColor =  *((Vec3*)&pLight.m_Color);
+
+            // Adjust light intensity so that the intended brightness is reached 1 meter from the light's surface
+            IF (!(pLight.m_Flags & (DLF_AREA_LIGHT | DLF_AMBIENT)), 1)
+            {
+                fAttenuationBulbSize = max(fAttenuationBulbSize, 0.001f);
+
+                // Solve I * 1 / (1 + d/lightsize)^2 = 1
+                float intensityMul = 1.0f + 1.0f / fAttenuationBulbSize;
+                intensityMul *= intensityMul;
+                lightColor *= intensityMul;
+            }
+
+            pVolume.pData.push_back();
+            SLightVolume::SLightData& lightData = pVolume.pData[pVolume.pData.size() - 1];
+            lightData.vPos = *vLight;
+            lightData.vColor = Vec4(lightColor, fAttenuationBulbSize);
+            lightData.vParams = Vec4(0.f, 0.f, 0.f, 0.f);
+
+            IF (pLight.m_Flags & DLF_PROJECT, 1)
+            {
+                lightData.vParams = Vec4(pLight.m_ObjMatrix.GetColumn0(), cos_tpl(DEG2RAD(pLight.m_fLightFrustumAngle)));
+            }
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CLightVolumesMgr::Update(const SRenderingPassInfo& passInfo)
+{
+    uint32 nThreadID = passInfo.ThreadID();
+    DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[nThreadID];
+
+    if (!m_bUpdateLightVolumes || lightVolsInfo.empty())
+    {
+        return;
+    }
+
+    FUNCTION_PROFILER_3DENGINE;
+    TArray<SRenderLight>* pLights = GetRenderer()->EF_GetDeferredLights(passInfo);
+    const uint32 nLightCount = pLights->size();
+
+    uint32 nLightVols = lightVolsInfo.size();
+    LightVolumeVector& lightVols = m_pLightVolumes[nThreadID];
+    uint32 existingLightVolsCount = 0;  //This is 0, that just means we will be overwriting all existing light volumes
+    
+    //If this is a recursive pass (not the first time that this is called this frame), we're just going to be adding on new light volumes to the existing collection
+    if (passInfo.IsRecursivePass())
+    {
+        existingLightVolsCount = lightVols.size();
+
+        //If no new light volumes have been added, don't bother updating
+        if (nLightVols == existingLightVolsCount)
+        {
+            return;
+        }
+    }
+
+    lightVols.resize(nLightVols);
+
+    if (!nLightCount)
+    {
+        //Start out existingLightVolsCount to avoid clearing out existing light volumes when we don't need to
+        for (uint32 v = existingLightVolsCount; v < nLightVols; ++v)
+        {
+            lightVols[v].pData.resize(0);
+        }
+
+        return;
+    }
+
+    const int MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE = 1024;
+
+    if (nLightCount > MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE)
+    {
+        CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_WARNING, "More lights in the scene (%d) than supported by the Light Volume Update function (%d). Extra lights will be ignored.",
+            nLightCount, MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE);
+    }
+
+    //This can be a uint8 array because nLightVols should never be greater than 256(LV_MAX_COUNT)
+    assert(LV_MAX_COUNT <= 256);
+    uint8 lightProcessedStateArray[MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE];
+
+    //Start at the number of light volumes that already exist so that we don't end up re-updating light volumes unnecessarily. 
+    for (uint32 v = existingLightVolsCount; v < nLightVols; ++v)
+    {
+        const Vec4* __restrict vBVol = &lightVolsInfo[v]->vVolume;
+        int32 nMiny = (int32)(floorf((vBVol->y - vBVol->w) * LV_LIGHT_CELL_R_SIZE));
+        int32 nMaxy = (int32)(floorf((vBVol->y + vBVol->w) * LV_LIGHT_CELL_R_SIZE));
+        int32 nMinx = (int32)(floorf((vBVol->x - vBVol->w) * LV_LIGHT_CELL_R_SIZE));
+        int32 nMaxx = (int32)(floorf((vBVol->x + vBVol->w) * LV_LIGHT_CELL_R_SIZE));
+
+        lightVols[v].pData.resize(0);
+
+        // Loop through active light cells touching bounding volume (~avg 2 cells)
+        for (int32 y = nMiny, ymax = nMaxy; y <= ymax; ++y)
+        {
+            for (int32 x = nMinx, xmax = nMaxx; x <= xmax; ++x)
+            {
+                const SLightCell& lightCell = m_pWorldLightCells[GetWorldHashBucketKey(x, y, 1, LV_LIGHTS_WORLD_BUCKET_SIZE)];
+                CryPrefetch(&lightCell);
+
+                const SRenderLight& pFirstDL = (*pLights)[lightCell.nLightID[0]];
+                CryPrefetch(&pFirstDL);
+                CryPrefetch(&pFirstDL.m_ObjMatrix);
+                for (uint32 l = 0; (l < lightCell.nLightCount) & (lightVols[v].pData.size() < LIGHTVOLUME_MAXLIGHTS); ++l)
+                {
+                    const int32 nLightId = lightCell.nLightID[l];
+
+                    //Only allow IDs < MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE to continue or else we'll overflow access to
+                    //lightProcessedStateArray[MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE].  Skipping the extra lights shouldn't really matter
+                    //since A) folks won't be using that many lights, and B) for the case of light emitting particles, they tend to be grouped
+                    //so that the individual contributions tend to bleed together anyway.
+                    if (nLightId >= MAX_NUM_LIGHTS_FOR_LIGHT_VOLUME_UPDATE)
+                    {
+                        continue;
+                    }
+
+                    if (static_cast<uint32>(nLightId) < nLightCount)
+                    {
+                        const SRenderLight& pDL = (*pLights)[nLightId];
+                        const int32 nNextLightId = lightCell.nLightID[(l + 1) & (LIGHTVOLUME_MAXLIGHTS - 1)];
+                        const SRenderLight& pNextDL = (*pLights)[nNextLightId];
+                        CryPrefetch(&pNextDL);
+                        CryPrefetch(&pNextDL.m_ObjMatrix);
+
+                        IF(lightProcessedStateArray[nLightId] != v + 1, 1)
+                        {
+                            lightProcessedStateArray[nLightId] = v + 1;
+                            AddLight(pDL, &*lightVolsInfo[v], lightVols[v]);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CLightVolumesMgr::Clear(const SRenderingPassInfo& passInfo)
+{
+    DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
+
+    m_bUpdateLightVolumes = false;
+    if (GetCVars()->e_LightVolumes && passInfo.IsGeneralPass() && GetCVars()->e_DynamicLights)
+    {
+        memset(m_nWorldCells, 0, sizeof(m_nWorldCells));
+        memset(m_pWorldLightCells, 0, sizeof(m_pWorldLightCells));
+
+        //Clean up volume info data
+        for (size_t i = 0; i < lightVolsInfo.size(); ++i)
+        {
+            delete lightVolsInfo[i];
+        }
+
+        m_pLightVolsInfo[passInfo.ThreadID()].clear();
+        m_bUpdateLightVolumes = (GetCVars()->e_LightVolumes == 1) ? true : false;
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+void CLightVolumesMgr::GetLightVolumes(threadID nThreadID, SLightVolume*& pLightVols, uint32& nNumVols)
+{
+    pLightVols = 0;
+    nNumVols = 0;
+    if (GetCVars()->e_LightVolumes == 1 && GetCVars()->e_DynamicLights && !m_pLightVolumes[nThreadID].empty())
+    {
+        pLightVols = &m_pLightVolumes[nThreadID][0];
+        nNumVols = m_pLightVolumes[nThreadID].size();
+    }
+}
+
+
+void C3DEngine::GetLightVolumes(threadID nThreadID, SLightVolume*& pLightVols, uint32& nNumVols)
+{
+    m_LightVolumesMgr.GetLightVolumes(nThreadID, pLightVols, nNumVols);
+}
+
+uint16 C3DEngine::RegisterVolumeForLighting(const Vec3& vPos, f32 fRadius, uint8 nClipVolumeRef, const SRenderingPassInfo& passInfo)
+{
+    return m_LightVolumesMgr.RegisterVolume(vPos, fRadius, nClipVolumeRef, passInfo);
+}
+
+//////////////////////////////////////////////////////////////////////////
+#ifndef _RELEASE
+void CLightVolumesMgr::DrawDebug(const SRenderingPassInfo& passInfo)
+{
+    DynArray<SLightVolInfo*>& lightVolsInfo = m_pLightVolsInfo[passInfo.ThreadID()];
+
+    IRenderer* pRenderer = GetRenderer();
+    IRenderAuxGeom* pAuxGeom = GetRenderer()->GetIRenderAuxGeom();
+    if (!pAuxGeom || !passInfo.IsGeneralPass())
+    {
+        return;
+    }
+
+    ColorF cWhite = ColorF(1, 1, 1, 1);
+    ColorF cBad = ColorF(1.0f, 0.0, 0.0f, 1.0f);
+    ColorF cWarning = ColorF(1.0f, 1.0, 0.0f, 1.0f);
+    ColorF cGood = ColorF(0.0f, 0.5, 1.0f, 1.0f);
+    ColorF cSingleCell = ColorF(0.0f, 1.0, 0.0f, 1.0f);
+
+    const uint32 nLightVols = lightVolsInfo.size();
+    LightVolumeVector& lightVols = m_pLightVolumes[passInfo.ThreadID()];
+    const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+
+    float fYLine = 8.0f, fYStep = 20.0f;
+    GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, (float*)&cWhite.r, false, "Light Volumes Info (count %d)", nLightVols);
+
+    for (uint32 v = 0; v < nLightVols; ++v)  // draw each light volume
+    {
+        SLightVolume& lv = lightVols[v];
+        SLightVolInfo& lvInfo = *lightVolsInfo[v];
+
+        ColorF& cCol = (lv.pData.size() >= 10) ? cBad : ((lv.pData.size() >= 5) ? cWarning : cGood);
+        const Vec3 vPos = Vec3(lvInfo.vVolume.x, lvInfo.vVolume.y, lvInfo.vVolume.z);
+        const float fCamDistSq = (vPos - vCamPos).len2();
+        cCol.a = max(0.25f, min(1.0f, 1024.0f / (fCamDistSq + 1e-6f)));
+
+        pRenderer->DrawLabelEx(vPos, 1.3f, (float*)&cCol.r, true, true, "Id: %d\nPos: %.2f %.2f %.2f\nRadius: %.2f\nLights: %d\nOutLights: %d",
+            v, vPos.x, vPos.y, vPos.z, lvInfo.vVolume.w, lv.pData.size(), (*(int32*)&lvInfo.vVolume.w) & (1 << 31) ? 1 : 0);
+
+        if (GetCVars()->e_LightVolumesDebug == 2)
+        {
+            const float fSideSize = 0.707f * sqrtf(lvInfo.vVolume.w * lvInfo.vVolume.w * 2);
+            pAuxGeom->DrawAABB(AABB(vPos - Vec3(fSideSize), vPos + Vec3(fSideSize)), false, cCol, eBBD_Faceted);
+        }
+
+        if (GetCVars()->e_LightVolumesDebug == 3)
+        {
+            cBad.a = 1.0f;
+            const Vec3 vCellPos = Vec3(floorf((lvInfo.vVolume.x) * LV_CELL_RSIZEX) * LV_CELL_SIZEX,
+                    floorf((lvInfo.vVolume.y) * LV_CELL_RSIZEY) * LV_CELL_SIZEY,
+                    floorf((lvInfo.vVolume.z) * LV_CELL_RSIZEZ) * LV_CELL_SIZEZ);
+
+            const Vec3 vMin = vCellPos;
+            const Vec3 vMax = vMin + Vec3(LV_CELL_SIZEX, LV_CELL_SIZEY, LV_CELL_SIZEZ);
+            pAuxGeom->DrawAABB(AABB(vMin, vMax), false, cBad, eBBD_Faceted);
+        }
+    }
+}
+#endif

+ 30 - 0
Code/CryEngine/Cry3DEngine/3DEngineMemory.cpp

@@ -0,0 +1,30 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+// Original file Copyright Crytek GMBH or its affiliates, used under license.
+
+#include "Cry3DEngine_precompiled.h"
+#include "3DEngineMemory.h"
+
+// Static CTemporaryPool instance
+CTemporaryPool* CTemporaryPool::s_Instance = NULL;
+
+namespace util
+{
+    void* pool_allocate(size_t nSize)
+    {
+        return CTemporaryPool::Get()->Allocate(nSize, 8);
+    }
+    void  pool_free(void* ptr)
+    {
+        return CTemporaryPool::Get()->Free(ptr);
+    }
+}

+ 286 - 0
Code/CryEngine/Cry3DEngine/3DEngineMemory.h

@@ -0,0 +1,286 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+// Original file Copyright Crytek GMBH or its affiliates, used under license.
+
+#ifndef CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H
+#define CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H
+#pragma once
+
+// The type of pool responsible for temporary allocations within the 3dengine
+//
+// Note: The header is included here for reasons of devirtualization. If
+// included directly from the precompiled header in 3dEngine, the gamedll will
+// fail to compile!
+#include <CryPool/PoolAlloc.h>
+#include <InplaceFactory.h>
+
+using NCryPoolAlloc::CFirstFit;        // speed of allocations are crucial, so simply use the first fitting free allocation
+using NCryPoolAlloc::CInPlace;         //
+using NCryPoolAlloc::CMemoryDynamic;   // the pool itself will be dynamically allocated
+using NCryPoolAlloc::CListItemInPlace; // use inplace items
+
+// Tempororary Pool Holder
+class CTemporaryPool
+{
+private:
+    // Access granted for 3dEngine to create, destroy and maintain the temporary
+    // pool for the 3d engine
+    friend class C3DEngine;
+
+    // The static pool instance - one pool to rule them all (temp allocations at least)
+    static CTemporaryPool* s_Instance;
+
+    // The type of the backing temporary pool
+    typedef CFirstFit<CInPlace<CMemoryDynamic>, CListItemInPlace> TTemporaryPool;
+    TTemporaryPool Pool;
+
+    // A non-recursive critical section guards the pool against concurrent access
+    typedef CryCriticalSectionNonRecursive TTemporaryPoolLock;
+    TTemporaryPoolLock Lock;
+
+    // Initialize the pool manager.
+    //
+    // Allocates the backing storage and initializes the temporary pool
+    // itself. The backing storage is aligned to 16 bytes to reduce the amount of
+    // cachelines crossed by the temporary pool
+    static bool Initialize(size_t poolSize)
+    {
+        // Create the object instance
+        s_Instance = new CTemporaryPool();
+        if (!s_Instance)
+        {
+            CryFatalError("CTemporaryPool::Init(): could not create an instance of CTemporaryPool");
+            return false;
+        }
+
+        // Allocate the backing storage
+        uint8* tempPool = reinterpret_cast<uint8*>(CryModuleMemalign(poolSize, 16));
+        if (!tempPool)
+        {
+            CryFatalError("CTemporaryPool::Init(): could not allocate %" PRISIZE_T " bytes for temportary pool", poolSize);
+            return false;
+        }
+
+        // Initialize the actual pool
+        s_Instance->Pool.InitMem(poolSize, tempPool);
+        return true;
+    }
+
+    // Shutdown the temporary pool manager.
+    //
+    // Frees the temporary pool
+    static bool Shutdown()
+    {
+        if (s_Instance == NULL)
+        {
+            CryFatalError("CTemporaryPool::Shutdown(): no temporary pool instance present");
+            return false;
+        }
+
+        bool error = false;
+        CTemporaryPool& instance = *s_Instance;
+        if (instance.Pool.Data())
+        {
+            CryModuleMemalignFree(instance.Pool.Data());
+        }
+        else
+        {
+            error = true;
+        }
+
+        delete s_Instance;
+        s_Instance = NULL;
+        return !error;
+    }
+
+    // Templated construct helper member function using an inplace factory
+    //
+    // Called from the templated New<T, Expr> function below. Returns a typed
+    // pointer to the inplace constructed object.
+    template<typename T, typename InPlaceFactory>
+    T* Construct(const InPlaceFactory& factory, void* storage)
+    {
+        return reinterpret_cast<T*>(factory.template apply<T>(storage));
+    }
+
+    // Templated destruct helper member function.
+    //
+    // Calls the object's destructor and returns a void pointer to the storage
+    template<typename T>
+    void* Destruct(T* obj)
+    {
+        obj->~T();
+        return reinterpret_cast<void*>(obj);
+    }
+
+    // Empty private constructor/destructors to prevent clients from creating and
+    // destroying instances of CTemporaryPool (there should only be one instance
+    // in the 3DEngine).
+    CTemporaryPool() {};
+    ~CTemporaryPool() {};
+
+public:
+
+    // Allocate a block of memory with the given size and alignment
+    void* Allocate(size_t size, size_t align)
+    {
+        AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
+        void* pData = Pool.Allocate<void*>(size, align);
+        if (pData == NULL)
+        {
+            CryFatalError("**** could not allocate %" PRISIZE_T " bytes from temporary pool", size);
+        }
+        return Pool.Resolve<void*>(pData);
+    };
+
+    // Allocates memory and constructs object of type 'T'
+    //
+    // Note: This method is respects the alignment of 'T' via C99 alignof()
+    template<typename T, typename Expr>
+    T* New(const Expr& expr)
+    {
+        AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
+        void* pObjStorage = Pool.Allocate<void*>(sizeof(T), alignof(T));
+        if (pObjStorage == NULL)
+        {
+            CryFatalError("**** could not allocate %d bytes from temporary pool",
+                (int)sizeof (T));
+        }
+        return Construct<T>(expr, pObjStorage);
+    };
+
+    // Allocates memory and constructs object of type 'T'
+    //
+    // Note: This method is respects the alignment of 'T' via C99 alignof()
+    template<typename T>
+    T* New()
+    {
+        AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
+        void* pObjStorage = Pool.Allocate<void*>(sizeof(T), alignof(T));
+        if (pObjStorage == NULL)
+        {
+            CryFatalError("**** could not allocate %d bytes from temporary pool",
+                (int)sizeof (T));
+        }
+        return Construct<T>(InplaceFactory(), pObjStorage);
+    };
+
+    // Frees a block of memory from the temporary pool
+    //
+    void Free(void* ptr)
+    {
+        AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
+        Pool.Free(ptr);
+    }
+
+
+    // Destroys an object of type 'T' and frees the underlying block of memory
+    template<typename T>
+    void Delete(T* ptr)
+    {
+        AUTO_LOCK_T(CryCriticalSectionNonRecursive, Lock);
+        Pool.Free(Destruct<T>(ptr));
+    }
+
+    // Static function to retrieve the static instance of CTemporaryPool
+    static CTemporaryPool* Get() { return s_Instance; };
+
+    void GetMemoryUsage(ICrySizer* pSizer) const
+    {
+        pSizer->AddObject(Pool.Data(), Pool.MemSize());
+    }
+};
+
+// A stl compliant scratch allocator that uses the given temporary pool.
+template <class Type>
+class scratch_allocator
+{
+public:
+    typedef Type value_type;
+    typedef value_type* pointer;
+    typedef const value_type* const_pointer;
+    typedef value_type& reference;
+    typedef const value_type& const_reference;
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+
+    template <class value_type1>
+    struct rebind
+    {
+        typedef scratch_allocator<value_type1> other;
+    };
+
+    scratch_allocator() {}
+    template <class value_type1>
+    scratch_allocator(const scratch_allocator<value_type1>&) {}
+    scratch_allocator(const scratch_allocator<value_type>&) {}
+    ~scratch_allocator() {}
+
+    pointer address(reference x) const {return &x; }
+    const_pointer address(const_reference x) const { return &x; }
+
+    // Note: size can be zero - return value will be null in that case
+    value_type* allocate(size_type n, const void* = 0)
+    {
+        if (n != 0)
+        {
+            size_type buf_size = n * sizeof(value_type);
+
+            void* ret = CTemporaryPool::Get()->Allocate(
+                    buf_size,
+                    alignof(value_type));
+
+            return reinterpret_cast<value_type*>(ret);
+        }
+        return 0;
+    }
+
+    // Note: size can be zero.
+    void deallocate(pointer p, [[maybe_unused]] size_type n)
+    {
+        if (p != NULL)
+        {
+            CTemporaryPool::Get()->Free(p);
+        }
+    }
+
+    size_type max_size() const  { return size_t(-1) / sizeof(value_type); }
+
+    void construct(pointer p, const_reference val)
+    { new (reinterpret_cast<void*>(p))value_type(val); }
+
+    void destroy(pointer p) { p->~value_type(); }
+
+    void cleanup() {}
+
+    size_t get_heap_size() { return 0; }
+
+    size_t get_wasted_in_allocation() { return 0; }
+
+    size_t get_wasted_in_blocks() { return 0; }
+};
+
+
+// A scratch vector type to use the stl vector
+template<typename Type>
+class scratch_vector
+    : public std::vector<Type, scratch_allocator<Type> >
+{
+};
+
+namespace util
+{
+    extern void* pool_allocate(size_t nSize);
+    extern void  pool_free(void* ptr);
+}
+
+#endif // CRYINCLUDE_CRY3DENGINE_3DENGINEMEMORY_H

+ 3957 - 0
Code/CryEngine/Cry3DEngine/3DEngineRender.cpp

@@ -0,0 +1,3957 @@
+
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+// Original file Copyright Crytek GMBH or its affiliates, used under license.
+
+// Description : rendering
+
+
+#include "Cry3DEngine_precompiled.h"
+
+#include "3dEngine.h"
+#include "ObjMan.h"
+#include "VisAreas.h"
+#include "Ocean.h"
+#include <Terrain/Bus/TerrainProviderBus.h>
+#include <AzFramework/Terrain/TerrainDataRequestBus.h>
+#include "DecalManager.h"
+#include "SkyLightManager.h"
+
+#include "CullBuffer.h"
+#include "LightEntity.h"
+#include "FogVolumeRenderNode.h"
+#include "ObjectsTree.h"
+#include "CloudsManager.h"
+#include "MatMan.h"
+#include "VolumeObjectRenderNode.h"
+#include "CryPath.h"
+#include "ILocalMemoryUsage.h"
+#include "BitFiddling.h"
+#include "ObjMan.h"
+#include "GeomCacheManager.h"
+#include "ClipVolumeManager.h"
+#include "ITimeOfDay.h"
+#include "Environment/OceanEnvironmentBus.h"
+
+#include "INetwork.h"
+#include <ThermalInfo.h>
+
+
+
+#ifdef GetCharWidth
+#undef GetCharWidth
+#endif //GetCharWidth
+
+
+#ifdef WIN32
+#include <CryWindows.h>
+#endif
+
+#include <AzFramework/IO/FileOperations.h>
+#include <AzFramework/StringFunc/StringFunc.h>
+#include <AzFramework/API/AtomActiveInterface.h>
+#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
+#include <AzCore/Interface/Interface.h>
+#include "../RenderDll/Common/Memory/VRAMDrillerBus.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+// RenderScene
+////////////////////////////////////////////////////////////////////////////////////////
+#define FREE_MEMORY_YELLOW_LIMIT (30)
+#define FREE_MEMORY_RED_LIMIT    (10)
+#define DISPLAY_INFO_SCALE       (1.25f)
+#define DISPLAY_INFO_SCALE_SMALL (1.1f)
+#define STEP_SMALL_DIFF          (2.f)
+
+#if defined(WIN32) || defined(WIN64) || defined(MAC)
+// for panorama screenshots
+class CStitchedImage
+    : public Cry3DEngineBase
+{
+public:
+    CStitchedImage(C3DEngine&  rEngine,
+        const uint32            dwWidth,
+        const uint32            dwHeight,
+        const uint32            dwVirtualWidth,
+        const uint32            dwVirtualHeight,
+        const uint32            dwSliceCount,
+        const f32                   fTransitionSize,
+        const bool              bMetaData = false)
+        : m_rEngine(rEngine)
+        , m_dwWidth(dwWidth)
+        , m_dwHeight(dwHeight)
+        , m_fInvWidth(1.f / static_cast<f32>(dwWidth))
+        , m_fInvHeight(1.f / static_cast<f32>(dwHeight))
+        , m_dwVirtualWidth(dwVirtualWidth)
+        , m_dwVirtualHeight(dwVirtualHeight)
+        , m_fInvVirtualWidth(1.f / static_cast<f32>(dwVirtualWidth))
+        , m_fInvVirtualHeight(1.f / static_cast<f32>(dwVirtualHeight))
+        , m_nFileId(0)
+        , m_dwSliceCount(dwSliceCount)
+        , m_fHorizFOV(2 * gf_PI / dwSliceCount)
+        , m_bFlipY(false)
+        , m_fTransitionSize(fTransitionSize)
+        , m_bMetaData(bMetaData)
+    {
+        assert(dwWidth);
+        assert(dwHeight);
+
+        m_RGB.resize(m_dwWidth * 3 * m_dwHeight);
+
+        // ratio between width and height defines angle 1 (angle from mid to cylinder edges)
+        float fVert1Frac = (2 * gf_PI * m_dwHeight) / m_dwWidth;
+
+        // slice count defines angle 2
+        float fHorizFrac = tanf(GetHorizFOVWithBorder() * 0.5f);
+        float fVert2Frac = 2.0f * fHorizFrac / rEngine.GetRenderer()->GetWidth() * rEngine.GetRenderer()->GetHeight();
+        //      float fVert2Frac = 2.0f * fHorizFrac / rEngine.GetRenderer()->GetWidth() * rEngine.GetRenderer()->GetHeight();
+
+        // the bigger one defines the needed angle
+        float fVertFrac = max(fVert1Frac, fVert2Frac);
+
+        // planar image becomes a barrel after projection and we need to zoom in to only utilize the usable part (inner rect)
+        // this is not always needed - for quality with low slice count we could be save some quality here
+        fVertFrac /= cosf(GetHorizFOVWithBorder() * 0.5f);
+
+        // compute FOV from Frac
+        float fVertFOV = 2 * atanf(0.5f * fVertFrac);
+
+        m_fPanoramaShotVertFOV = fabsf(fVertFOV);
+
+        CryLog("RenderFov = %f degrees (%f = max(%f,%f)*fix)", RAD2DEG(m_fPanoramaShotVertFOV), fVertFrac, fVert1Frac, fVert2Frac);
+        Clear();
+    }
+
+    void Clear()
+    {
+        memset(&m_RGB[0], 0, m_dwWidth * m_dwHeight * 3);
+    }
+
+    // szDirectory + "/" + file_id + "." + extension
+    // logs errors in the case there are problems
+    bool SaveImage(const char* szDirectory)
+    {
+        assert(szDirectory);
+
+        const char* szExtension = m_rEngine.GetCVars()->e_ScreenShotFileFormat->GetString();
+
+        if (azstricmp(szExtension, "dds") != 0  &&
+            azstricmp(szExtension, "tga") != 0    &&
+            azstricmp(szExtension, "jpg") != 0)
+        {
+            gEnv->pLog->LogError("Format e_ScreenShotFileFormat='%s' not supported", szExtension);
+            return false;
+        }
+
+        const char* sRequestedName = m_rEngine.GetCVars()->e_ScreenShotFileName->GetString();
+
+        char sFileName[AZ_MAX_PATH_LEN];
+
+        if (azstricmp(sRequestedName, "") != 0)
+        {
+            AZStd::string folderPath;
+            AZStd::string fileName;
+            AzFramework::StringFunc::Path::Split(sRequestedName, nullptr, &folderPath, &fileName);
+            gEnv->pFileIO->CreatePath((AZStd::string("@user@/ScreenShots/") + folderPath).c_str());
+            azsnprintf(sFileName, sizeof(sFileName), "@user@/ScreenShots/%s.%s", sRequestedName, szExtension);
+        }
+        else
+        {
+            azsnprintf(sFileName, sizeof(sFileName), "@user@/ScreenShots/%s", szDirectory);
+            gEnv->pFileIO->CreatePath(sFileName);
+
+            // find free file id
+            for (;; )
+            {
+                azsnprintf(sFileName, sizeof(sFileName), "@user@/ScreenShots/%s/%.5d.%s", szDirectory, m_nFileId, szExtension);
+
+                AZ::IO::HandleType fileHandle = gEnv->pCryPak->FOpen(sFileName, "rb");
+
+                if (fileHandle == AZ::IO::InvalidHandle)
+                {
+                    break; // file doesn't exist
+                }
+
+                gEnv->pCryPak->FClose(fileHandle);
+                m_nFileId++;
+            }
+        }
+
+        bool bOk;
+
+        if (azstricmp(szExtension, "dds") == 0)
+        {
+            bOk = gEnv->pRenderer->WriteDDS((byte*)&m_RGB[0], m_dwWidth, m_dwHeight, 3, sFileName, eTF_BC3, 1);
+        }
+        else
+        if (azstricmp(szExtension, "tga") == 0)
+        {
+            bOk = gEnv->pRenderer->WriteTGA((byte*)&m_RGB[0], m_dwWidth, m_dwHeight, sFileName, 24, 24);
+        }
+        else
+        {
+            bOk = gEnv->pRenderer->WriteJPG((byte*)&m_RGB[0], m_dwWidth, m_dwHeight, sFileName, 24);
+        }
+
+        if (!bOk)
+        {
+            gEnv->pLog->LogError("Failed to write '%s' (not supported on this platform?)", sFileName);
+        }
+        else //write meta data
+        {
+            if (m_bMetaData)
+            {
+                const f32   fSizeX  =   GetCVars()->e_ScreenShotMapSizeX;
+                const f32   fSizeY  =   GetCVars()->e_ScreenShotMapSizeY;
+                const f32   fTLX    =   GetCVars()->e_ScreenShotMapCenterX - fSizeX;
+                const f32   fTLY    =   GetCVars()->e_ScreenShotMapCenterY - fSizeY;
+                const f32   fBRX    =   GetCVars()->e_ScreenShotMapCenterX + fSizeX;
+                const f32   fBRY    =   GetCVars()->e_ScreenShotMapCenterY + fSizeY;
+
+                snprintf(sFileName, sizeof(sFileName), "@user@/ScreenShots/%s/%.5d.%s", szDirectory, m_nFileId, "xml");
+
+                AZ::IO::HandleType metaFileHandle = gEnv->pCryPak->FOpen(sFileName, "wt");
+                if (metaFileHandle != AZ::IO::InvalidHandle)
+                {
+                    char sFileData[1024];
+                    snprintf(sFileData, sizeof(sFileData), "<MiniMap Filename=\"%.5d.%s\" startX=\"%f\" startY=\"%f\" endX=\"%f\" endY=\"%f\"/>",
+                        m_nFileId, szExtension, fTLX, fTLY, fBRX, fBRY);
+                    string data(sFileData);
+                    gEnv->pCryPak->FWrite(data.c_str(), data.size(), metaFileHandle);
+                    gEnv->pCryPak->FClose(metaFileHandle);
+                }
+            }
+        }
+
+        // reset filename when done so user doesn't overwrite other screen shots (unless they want to)
+        // this is done here as there is no callback for standard screenshots to allow the user to clear
+        // this when done with the screen shot, so I decided to just always clear it when done
+        m_rEngine.GetCVars()->e_ScreenShotFileName->Set("");
+
+        return bOk;
+    }
+
+    // rasterize rectangle
+    // Arguments:
+    //   x0 - <x1, including
+    //   y0 - <y1, including
+    //   x1 - >x0, excluding
+    //   y1 - >y0, excluding
+    void RasterizeRect(const uint32*   pRGBAImage,
+        const uint32    dwWidth,
+        const uint32    dwHeight,
+        const uint32    dwSliceX,
+        const uint32    dwSliceY,
+        const f32           fTransitionSize,
+        const bool      bFadeBordersX,
+        const bool      bFadeBordersY)
+    {
+        {
+            //calculate rect inside the whole image
+            const int32 OrgX0 =   static_cast<int32>(static_cast<f32>((dwSliceX * dwWidth) * m_dwWidth) * m_fInvVirtualWidth);
+            const int32 OrgY0 =   static_cast<int32>(static_cast<f32>((dwSliceY * dwHeight) * m_dwHeight) * m_fInvVirtualHeight);
+            const int32 OrgX1 =   min(static_cast<int32>(static_cast<f32>(((dwSliceX + 1) * dwWidth) * m_dwWidth) * m_fInvVirtualWidth), static_cast<int32>(m_dwWidth)) - (m_rEngine.GetCVars()->e_ScreenShotDebug == 1 ? 1 : 0);
+            const int32 OrgY1 =   min(static_cast<int32>(static_cast<f32>(((dwSliceY + 1) * dwHeight) * m_dwHeight) * m_fInvVirtualHeight), static_cast<int32>(m_dwHeight)) - (m_rEngine.GetCVars()->e_ScreenShotDebug == 1 ? 1 : 0);
+            //expand bounds for borderblending
+            const int32 CenterX   =   (OrgX0 + OrgX1) / 2;
+            const int32 CenterY   =   (OrgY0 + OrgY1) / 2;
+            const int32 X0    =   static_cast<int32>(static_cast<f32>(OrgX0 - CenterX) * (1.f + fTransitionSize)) + CenterX;
+            const int32 Y0    =   static_cast<int32>(static_cast<f32>(OrgY0 - CenterY) * (1.f + fTransitionSize)) + CenterY;
+            const int32 X1    =   static_cast<int32>(static_cast<f32>(OrgX1 - CenterX) * (1.f + fTransitionSize)) + CenterX;
+            const int32 Y1    =   static_cast<int32>(static_cast<f32>(OrgY1 - CenterY) * (1.f + fTransitionSize)) + CenterY;
+            const f32 InvBlendX   =   1.f / max(static_cast<f32>(X1 - OrgX1), 0.01f);//0.5 is here because the border is two times wider then the border of the single segment in total
+            const f32 InvBlendY   =   1.f / max(static_cast<f32>(Y1 - OrgY1), 0.01f);
+            const int32 DebugScale =   (m_rEngine.GetCVars()->e_ScreenShotDebug == 2) ? 65536 : 0;
+            for (int32 y = max(Y0, 0); y < Y1 && y < (int)m_dwHeight; y++)
+            {
+                const f32 WeightY   =   bFadeBordersY ? min(1.f, static_cast<f32>(min(y - Y0, Y1 - y)) * InvBlendY) : 1.f;
+                for (int32 x = max(X0, 0); x < X1 && x < (int)m_dwWidth; x++)
+                {
+                    uint8* pDst = &m_RGB[m_bFlipY ? 3 * (x + (m_dwHeight - y - 1) * m_dwWidth) : 3 * (x + y * m_dwWidth)];
+                    const f32 WeightX =   bFadeBordersX ? min(1.f, static_cast<f32>(min(x - X0, X1 - x)) * InvBlendX) : 1.f;
+                    GetBilinearFilteredBlend(static_cast<int32>(static_cast<f32>(x - X0) / static_cast<f32>(X1 - X0) * static_cast<f32>(dwWidth) * 16.f),
+                        static_cast<int32>(static_cast<f32>(y - Y0) / static_cast<f32>(Y1 - Y0) * static_cast<f32>(dwHeight) * 16.f),
+                        pRGBAImage, dwWidth, dwHeight,
+                        max(static_cast<int32>(WeightX * WeightY * 65536.f), DebugScale), pDst);
+                }
+            }
+        }
+    }
+
+    void RasterizeCylinder(const uint32* pRGBAImage,
+        const uint32 dwWidth,
+        const uint32 dwHeight,
+        const uint32 dwSlice,
+        const bool bFadeBorders)
+    {
+        float fSrcAngleMin = GetSliceAngle(dwSlice - 1);
+        float fFractionVert = tanf(m_fPanoramaShotVertFOV * 0.5f);
+        float fFractionHoriz = fFractionVert * gEnv->pRenderer->GetCamera().GetProjRatio();
+        float fInvFractionHoriz = 1.0f / fFractionHoriz;
+
+        // for soft transition
+        float fFadeOutFov = GetHorizFOVWithBorder();
+        float fFadeInFov = GetHorizFOV();
+
+        int x0 = 0, y0 = 0, x1 = m_dwWidth, y1 = m_dwHeight;
+
+        float fScaleX = 1.0f / m_dwWidth;
+        float fScaleY = 0.5f * fInvFractionHoriz / (m_dwWidth / (2 * gf_PI)) / dwHeight * dwWidth;                          // this value is not correctly computed yet - but using many slices reduced the problem
+
+        if (m_bFlipY)
+        {
+            fScaleY = -fScaleY;
+        }
+
+
+        // it's more efficient to process colums than lines
+        for (int x = x0; x < x1; ++x)
+        {
+            uint8* pDst = &m_RGB[3 * (x + y0 * m_dwWidth)];
+            float fSrcX = x * fScaleX - 0.5f; // -0.5 .. 0.5
+            float fSrcAngleX = fSrcAngleMin + 2 * gf_PI * fSrcX;
+
+            if (fSrcAngleX > gf_PI)
+            {
+                fSrcAngleX -= 2 * gf_PI;
+            }
+            if (fSrcAngleX < -gf_PI)
+            {
+                fSrcAngleX += 2 * gf_PI;
+            }
+
+            if (fabs(fSrcAngleX) > fFadeOutFov * 0.5f)
+            {
+                continue;                                                   // clip away curved parts of the barrel
+            }
+            float fScrPosX = (tanf(fSrcAngleX) * 0.5f * fInvFractionHoriz + 0.5f) * dwWidth;
+            //          float fInvCosSrcX = 1.0f / cos(fSrcAngleX);
+            float fInvCosSrcX = 1.0f / cosf(fSrcAngleX);
+
+            if (fScrPosX >= 0 && fScrPosX <= (float)dwWidth) // this is an optimization - but it could be done even more efficient
+            {
+                if (fInvCosSrcX > 0)                                                  // don't render the viewer opposing direction
+                {
+                    int iSrcPosX16 = (int)(fScrPosX * 16.0f);
+
+                    float fYOffset = 16 * 0.5f * dwHeight - 16 * 0.5f * m_dwHeight * fScaleY * fInvCosSrcX * dwHeight;
+                    float fYMul = 16 * fScaleY * fInvCosSrcX * dwHeight;
+
+                    float fSrcY = y0 * fYMul + fYOffset;
+
+                    uint32 dwLerp64k = 256 * 256 - 1;
+
+                    if (!bFadeBorders)
+                    {
+                        // first pass - every second image without soft borders
+                        for (int y = y0; y < y1; ++y, fSrcY += fYMul, pDst += m_dwWidth * 3)
+                        {
+                            GetBilinearFiltered(iSrcPosX16, (int)fSrcY, pRGBAImage, dwWidth, dwHeight, pDst);
+                        }
+                    }
+                    else
+                    {
+                        // second pass - do all the inbetween with soft borders
+                        float fOffSlice = fabs(fSrcAngleX / fFadeInFov) - 0.5f;
+
+                        if (fOffSlice < 0)
+                        {
+                            fOffSlice = 0; // no transition in this area
+                        }
+                        float fBorder = (fFadeOutFov - fFadeInFov) * 0.5f;
+
+                        if (fBorder < 0.001f)
+                        {
+                            fBorder = 0.001f; // we do not have border
+                        }
+                        float fFade = 1.0f - fOffSlice * fFadeInFov / fBorder;
+
+                        if (fFade < 0.0f)
+                        {
+                            fFade = 0.0f; // don't use this slice here
+                        }
+                        dwLerp64k = (uint32)(fFade * (256.0f * 256.0f - 1.0f)); // 0..64k
+
+                        if (dwLerp64k)                                              // optimization
+                        {
+                            for (int y = y0; y < y1; ++y, fSrcY += fYMul, pDst += m_dwWidth * 3)
+                            {
+                                GetBilinearFilteredBlend(iSrcPosX16, (int)fSrcY, pRGBAImage, dwWidth, dwHeight, dwLerp64k, pDst);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // fast, rgb only
+    static inline ColorB lerp(const ColorB x, const ColorB y, const uint32 a, const uint32 dwBase)
+    {
+        const int32 b = dwBase - a;
+        const int32 RC  =   dwBase / 2;//rounding correction
+
+
+        return ColorB(((int)x.r * b + (int)y.r * a + RC) / dwBase,
+            ((int)x.g * b + (int)y.g * a + RC) / dwBase,
+            ((int)x.b * b + (int)y.b * a + RC) / dwBase);
+    }
+
+    static inline ColorB Mul(const ColorB x, const int32 a, const int32 dwBase)
+    {
+        return ColorB(((int)x.r * (int)a) / dwBase,
+            ((int)x.g * (int)a) / dwBase,
+            ((int)x.b * (int)a) / dwBase);
+    }
+    static inline ColorB MadSaturate(const ColorB x, const int32 a, const int32 dwBase, const ColorB y)
+    {
+        const int32 MAX_COLOR   =   0xff;
+        const ColorB PreMuled   =   Mul(x, a, dwBase);
+        return ColorB(min((int)PreMuled.r + (int)y.r, MAX_COLOR),
+            min((int)PreMuled.g + (int)y.g, MAX_COLOR),
+            min((int)PreMuled.b + (int)y.b, MAX_COLOR));
+    }
+
+    // bilinear filtering in fixpoint,
+    // 4bit fractional part -> multiplier 16
+    // --lookup outside of the image is not defined
+    //  lookups outside the image are now clamped, needed due to some float inaccuracy while rasterizing a rect-screenshot
+    // Arguments:
+    //   iX16 - fX mul 16
+    //   iY16 - fY mul 16
+    //   result - [0]=red, [1]=green, [2]=blue
+    static inline bool GetBilinearFilteredRaw(const int iX16, const int iY16,
+        const uint32* pRGBAImage,
+        const uint32 dwWidth, const uint32 dwHeight,
+        ColorB& result)
+    {
+        int iLocalX = min(max(iX16 / 16, 0), static_cast<int>(dwWidth - 1));
+        int iLocalY = min(max(iY16 / 16, 0), static_cast<int>(dwHeight - 1));
+
+        int iLerpX = iX16 & 0xf;      // 0..15
+        int iLerpY = iY16 & 0xf;      // 0..15
+
+        ColorB colS[4];
+
+        const uint32* pRGBA = &pRGBAImage[iLocalX + iLocalY * dwWidth];
+
+        colS[0] = pRGBA[0];
+        colS[1] = pRGBA[1];
+        colS[2] = pRGBA[iLocalY + 1uL < dwHeight ? dwWidth : 0];
+        colS[3] = pRGBA[(iLocalX + 1uL < dwWidth ? 1 : 0) + (iLocalY + 1uL < dwHeight ? dwWidth : 0)];
+
+        ColorB colTop, colBottom;
+
+        colTop = lerp(colS[0], colS[1], iLerpX, 16);
+        colBottom = lerp(colS[2], colS[3], iLerpX, 16);
+
+        result = lerp(colTop, colBottom, iLerpY, 16);
+        return true;
+    }
+
+
+    // blend with background
+    static inline bool GetBilinearFiltered(const int iX16, const int iY16,
+        const uint32* pRGBAImage,
+        const uint32 dwWidth, const uint32 dwHeight,
+        uint8 result[3])
+    {
+        ColorB colFiltered;
+        if (GetBilinearFilteredRaw(iX16, iY16, pRGBAImage, dwWidth, dwHeight, colFiltered))
+        {
+            result[0] = colFiltered.r;
+            result[1] = colFiltered.g;
+            result[2] = colFiltered.b;
+            return true;
+        }
+        return false;
+    }
+
+    static inline bool GetBilinearFilteredBlend(const int iX16, const int iY16,
+        const uint32* pRGBAImage,
+        const uint32 dwWidth, const uint32 dwHeight,
+        const uint32 dwLerp64k,
+        uint8 result[3])
+    {
+        ColorB colFiltered;
+        if (GetBilinearFilteredRaw(iX16, iY16, pRGBAImage, dwWidth, dwHeight, colFiltered))
+        {
+            ColorB colRet = lerp(ColorB(result[0], result[1], result[2]), colFiltered, dwLerp64k, 256 * 256);
+
+            result[0] = colRet.r;
+            result[1] = colRet.g;
+            result[2] = colRet.b;
+            return true;
+        }
+        return false;
+    }
+
+    static inline bool GetBilinearFilteredAdd(const int iX16, const int iY16,
+        const uint32* pRGBAImage,
+        const uint32 dwWidth, const uint32 dwHeight,
+        const uint32 dwLerp64k,
+        uint8 result[3])
+    {
+        ColorB colFiltered;
+        if (GetBilinearFilteredRaw(iX16, iY16, pRGBAImage, dwWidth, dwHeight, colFiltered))
+        {
+            ColorB colRet = MadSaturate(colFiltered, dwLerp64k, 256 * 256, ColorB(result[0], result[1], result[2]));
+
+            result[0] = colRet.r;
+            result[1] = colRet.g;
+            result[2] = colRet.b;
+            return true;
+        }
+        return false;
+    }
+
+
+    float GetSliceAngle(const uint32 dwSlice) const
+    {
+        uint32 dwAlternatingSlice = (dwSlice * 2) % m_dwSliceCount;
+
+        float fAngleStep = m_fHorizFOV;
+
+        float fRet = fAngleStep * dwAlternatingSlice;
+
+        if (dwSlice * 2 >= m_dwSliceCount)
+        {
+            fRet += fAngleStep;
+        }
+
+        return fRet;
+    }
+
+    float GetHorizFOV() const
+    {
+        return m_fHorizFOV;
+    }
+
+    float GetHorizFOVWithBorder() const
+    {
+        return m_fHorizFOV * (1.0f + m_fTransitionSize);
+    }
+
+    void* GetBuffer(){ return &m_RGB[0]; }
+    uint32 GetWidth() { return m_dwWidth; }
+    uint32 GetHeight() { return m_dwHeight; }
+
+
+    //private: // -------------------------------------------------------------------
+
+    uint32                      m_dwWidth;                  // >0
+    uint32                      m_dwHeight;                 // >0
+    f32                         m_fInvWidth;                // >0
+    f32                         m_fInvHeight;               // >0
+    uint32                      m_dwVirtualWidth;           // >0
+    uint32                      m_dwVirtualHeight;          // >0
+    f32                         m_fInvVirtualWidth;         // >0
+    f32                         m_fInvVirtualHeight;        // >0
+    std::vector<uint8>          m_RGB;                      // [channel + x*3 + m_dwWidth*3*y], channel=0..2, x<m_dwWidth, y<m_dwHeight, no alpha channel to occupy less memory
+    uint32                      m_nFileId;                  // counts up until it finds free file id
+    bool                        m_bFlipY;                   // might be useful for some image formats
+    bool                        m_bMetaData;                // output additional metadata
+
+    float                       m_fPanoramaShotVertFOV;     // -1 means not set yet - in radians
+
+private:
+
+    uint32                      m_dwSliceCount;             //
+    C3DEngine&                  m_rEngine;                  //
+    float                       m_fHorizFOV;                // - in radians
+    float                       m_fTransitionSize;          // [0..1], 0=no transition, 1.0=full transition
+};
+#endif
+
+enum EScreenShotType
+{
+    ESST_NONE = 0,
+    ESST_HIGHRES = 1,
+    ESST_PANORAMA,
+    ESST_MAP_DELAYED,
+    ESST_MAP,
+    ESST_SWMAP,
+    ESST_SWMAP_DELAYED,
+};
+
+void C3DEngine::ScreenshotDispatcher([[maybe_unused]] const int nRenderFlags, [[maybe_unused]] const SRenderingPassInfo& passInfo)
+{
+#if defined(WIN32) || defined(WIN64) || defined(MAC)
+    CStitchedImage*   pStitchedImage = 0;
+    const uint32  dwPanWidth          = max(1, GetCVars()->e_ScreenShotWidth);
+    const uint32  dwPanHeight         = max(1, GetCVars()->e_ScreenShotHeight);
+    const f32         fTransitionSize = min(1.f, abs(GetCVars()->e_ScreenShotQuality) * 0.01f);
+
+    const uint32 widthSlices  = (dwPanWidth  + GetRenderer()->GetWidth()  - 1) / GetRenderer()->GetWidth();
+    const uint32 heightSlices = (dwPanHeight + GetRenderer()->GetHeight() - 1) / GetRenderer()->GetHeight();
+    uint32 MinSlices    = max(widthSlices, heightSlices);
+    MinSlices           = max(MinSlices, (uint32)GetCVars()->e_ScreenShotMinSlices);
+
+    const uint32  dwVirtualWidth  =   GetRenderer()->GetWidth() * MinSlices;
+    const uint32  dwVirtualHeight =   GetRenderer()->GetHeight() * MinSlices;
+
+    GetRenderer()->StartScreenShot(GetCVars()->e_ScreenShot);
+
+    switch (abs(GetCVars()->e_ScreenShot))
+    {
+    case ESST_HIGHRES:
+        GetConsole()->ShowConsole(false);
+
+        MinSlices = max(MinSlices, 1u);
+        pStitchedImage  =   new CStitchedImage(*this, dwPanWidth, dwPanHeight, dwVirtualWidth, dwVirtualHeight, MinSlices, fTransitionSize);
+
+        ScreenShotHighRes(pStitchedImage, nRenderFlags, passInfo, MinSlices, fTransitionSize);
+        pStitchedImage->SaveImage("HiRes");
+        pStitchedImage->Clear();    // good for debugging
+        delete pStitchedImage;
+        if (GetCVars()->e_ScreenShot > 0)     // <0 is used for multiple frames (videos)
+        {
+            GetCVars()->e_ScreenShot = 0;
+        }
+        break;
+    case ESST_PANORAMA:
+        GetConsole()->ShowConsole(false);
+
+        // Panorama screenshots will exhibit artifacts if insufficient slices are used to render them
+        // 20 slices yields great quality.
+        MinSlices = max(MinSlices, 20u);
+        pStitchedImage  =   new CStitchedImage(*this, dwPanWidth, dwPanHeight, dwVirtualWidth, dwVirtualHeight, MinSlices, fTransitionSize);
+        
+        ScreenShotPanorama(pStitchedImage, nRenderFlags, passInfo, MinSlices, fTransitionSize);
+        pStitchedImage->SaveImage("Panorama");
+        pStitchedImage->Clear();    // good for debugging
+        delete pStitchedImage;
+        if (GetCVars()->e_ScreenShot > 0)     // <0 is used for multiple frames (videos)
+        {
+            GetCVars()->e_ScreenShot = 0;
+        }
+        break;
+    case ESST_MAP_DELAYED:
+    {
+        GetCVars()->e_ScreenShot  =   sgn(GetCVars()->e_ScreenShot) * ESST_MAP;   // sgn() to keep sign bit , <0 is used for multiple frames (videos)
+    }
+    break;
+    case ESST_SWMAP_DELAYED:
+    {
+        GetCVars()->e_ScreenShot  =   sgn(GetCVars()->e_ScreenShot) * ESST_SWMAP;     // sgn() to keep sign bit , <0 is used for multiple frames (videos)
+    }
+    break;
+    case ESST_SWMAP:
+    case ESST_MAP:
+    {
+        static const unsigned int nMipMapSnapshotSize = 2048;
+        GetRenderer()->ChangeViewport(0, 0, nMipMapSnapshotSize, nMipMapSnapshotSize);
+        uint32 TmpHeight, TmpWidth, TmpVirtualHeight, TmpVirtualWidth;
+        TmpHeight = TmpWidth = TmpVirtualHeight = TmpVirtualWidth = 1;
+
+        while ((TmpHeight << 1) <= dwPanHeight)
+        {
+            TmpHeight <<= 1;
+        }
+        while ((TmpWidth << 1) <= dwPanWidth)
+        {
+            TmpWidth <<= 1;
+        }
+        const uint32  TmpMinSlices                =   max(max(1, GetCVars()->e_ScreenShotMinSlices),
+                max(static_cast<int>((TmpWidth + nMipMapSnapshotSize - 1) / nMipMapSnapshotSize),
+                    static_cast<int>((TmpHeight + nMipMapSnapshotSize - 1) / nMipMapSnapshotSize)));
+        while ((TmpVirtualHeight << 1) <= TmpMinSlices * nMipMapSnapshotSize)
+        {
+            TmpVirtualHeight <<= 1;
+        }
+        while ((TmpVirtualWidth << 1) <= TmpMinSlices * nMipMapSnapshotSize)
+        {
+            TmpVirtualWidth <<= 1;
+        }
+
+        GetConsole()->ShowConsole(false);
+        pStitchedImage    =   new CStitchedImage(*this, TmpWidth, TmpHeight, TmpVirtualWidth, TmpVirtualHeight, TmpMinSlices, fTransitionSize, true);
+        ScreenShotMap(pStitchedImage, nRenderFlags, passInfo, TmpMinSlices, fTransitionSize);
+        if (abs(GetCVars()->e_ScreenShot) == ESST_MAP)
+        {
+            pStitchedImage->SaveImage("Map");
+        }
+
+        if (m_pScreenshotCallback)
+        {
+            const f32   fSizeX  =   GetCVars()->e_ScreenShotMapSizeX;
+            const f32   fSizeY  =   GetCVars()->e_ScreenShotMapSizeY;
+            const f32   fTLX    =   GetCVars()->e_ScreenShotMapCenterX - fSizeX;
+            const f32   fTLY    =   GetCVars()->e_ScreenShotMapCenterY - fSizeY;
+            const f32   fBRX    =   GetCVars()->e_ScreenShotMapCenterX + fSizeX;
+            const f32   fBRY    =   GetCVars()->e_ScreenShotMapCenterY + fSizeY;
+
+            m_pScreenshotCallback->SendParameters(pStitchedImage->GetBuffer(), pStitchedImage->GetWidth(), pStitchedImage->GetHeight(), fTLX, fTLY, fBRX, fBRY);
+        }
+
+        pStitchedImage->Clear();    // good for debugging
+        delete pStitchedImage;
+    }
+        if (GetCVars()->e_ScreenShot > 0)     // <0 is used for multiple frames (videos)
+        {
+            GetCVars()->e_ScreenShot = 0;
+        }
+
+        break;
+    default:
+        GetCVars()->e_ScreenShot = 0;
+    }
+
+    GetRenderer()->EndScreenShot(GetCVars()->e_ScreenShot);
+
+#endif //#if defined(WIN32) || defined(WIN64)
+}
+
+
+
+struct SDebugFrustrum
+{
+    Vec3                      m_vPos[8];
+    const char*      m_szName;
+    CTimeValue            m_TimeStamp;
+    ColorB                    m_Color;
+    float                     m_fQuadDist;      // < 0 if not used
+};
+
+static StaticInstance<std::vector<SDebugFrustrum>> g_DebugFrustrums;
+
+void C3DEngine::DebugDraw_Draw()
+{
+#ifndef _RELEASE
+    if (m_DebugDrawListMgr.IsEnabled())
+    {
+        m_DebugDrawListMgr.Update();
+    }
+
+    CTimeValue CurrentTime = gEnv->pTimer->GetFrameStartTime();
+
+    IRenderAuxGeom* pAux = GetRenderer()->GetIRenderAuxGeom();
+
+    SAuxGeomRenderFlags   oldFlags = pAux->GetRenderFlags();
+    SAuxGeomRenderFlags   newFlags;
+    newFlags.SetAlphaBlendMode(e_AlphaBlended);
+    newFlags.SetCullMode(e_CullModeNone);
+    newFlags.SetDepthWriteFlag(e_DepthWriteOff);
+    pAux->SetRenderFlags(newFlags);
+    std::vector<SDebugFrustrum>::iterator it;
+
+    for (it = g_DebugFrustrums.begin(); it != g_DebugFrustrums.end(); )
+    {
+        SDebugFrustrum& ref = *it;
+
+        float fRatio = (CurrentTime - ref.m_TimeStamp).GetSeconds() * 2.0f;
+
+        if (fRatio > 1.0f)
+        {
+            it = g_DebugFrustrums.erase(it);
+            continue;
+        }
+
+        vtx_idx pnInd[8] = {    0, 4, 1, 5, 2, 6, 3, 7    };
+
+        float fRadius = ((ref.m_vPos[0] + ref.m_vPos[1] + ref.m_vPos[2] + ref.m_vPos[3]) - (ref.m_vPos[4] + ref.m_vPos[5] + ref.m_vPos[6] + ref.m_vPos[7])).GetLength() * 0.25f;
+        float fDistance = min(fRadius, 33.0f);  // in meters
+
+        float fRenderRatio = fRatio * fDistance / fRadius;
+
+        if (ref.m_fQuadDist > 0)
+        {
+            fRenderRatio = ref.m_fQuadDist / fRadius;
+        }
+
+        Vec3 vPos[4];
+
+        for (uint32 i = 0; i < 4; ++i)
+        {
+            vPos[i] = ref.m_vPos[i] * fRenderRatio + ref.m_vPos[i + 4] * (1.0f - fRenderRatio);
+        }
+
+        Vec3 vMid = (vPos[0] + vPos[1] + vPos[2] + vPos[3]) * 0.25f;
+
+        ColorB col = ref.m_Color;
+
+        if (ref.m_fQuadDist <= 0)
+        {
+            for (uint32 i = 0; i < 4; ++i)
+            {
+                vPos[i] = vPos[i] * 0.95f + vMid * 0.05f;
+            }
+
+            // quad
+            if (ref.m_fQuadDist != -999.f)
+            {
+                pAux->DrawTriangle(vPos[0], col, vPos[2], col, vPos[1], col);
+                pAux->DrawTriangle(vPos[2], col, vPos[0], col, vPos[3], col);
+            }
+            // projection lines
+            pAux->DrawLines(ref.m_vPos, 8, pnInd, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
+            pAux->DrawLines(ref.m_vPos, 8, pnInd + 2, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
+            pAux->DrawLines(ref.m_vPos, 8, pnInd + 4, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
+            pAux->DrawLines(ref.m_vPos, 8, pnInd + 6, 2, RGBA8(0xff, 0xff, 0x1f, 0xff));
+        }
+        else
+        {
+            // rectangle
+            pAux->DrawPolyline(vPos, 4, true, RGBA8(0xff, 0xff, 0x1f, 0xff));
+        }
+
+        ++it;
+    }
+
+    pAux->SetRenderFlags(oldFlags);
+
+
+    if (GetCVars()->e_DebugDraw == 16)
+    {
+        DebugDraw_UpdateDebugNode();
+    }
+    else
+    {
+        GetRenderer()->SetDebugRenderNode(NULL);
+    }
+
+#endif //_RELEASE
+}
+
+void C3DEngine::DebugDraw_UpdateDebugNode()
+{
+#ifndef _RELEASE
+
+
+#endif //_RELEASE
+}
+
+void C3DEngine::RenderWorld(const int nRenderFlags, const SRenderingPassInfo& passInfo, const char* szDebugName)
+{
+    AZ_TRACE_METHOD();
+
+    if (nRenderFlags & SHDF_ALLOW_AO)
+    {
+        SVOGILegacyRequestBus::Broadcast(&SVOGILegacyRequests::OnFrameStart, passInfo);
+    }
+
+    if (m_szLevelFolder[0] != 0)
+    {
+        m_nFramesSinceLevelStart++;
+    }
+
+    assert(szDebugName);
+
+    if (!GetCVars()->e_Render)
+    {
+        return;
+    }
+
+    IF (!m_bEditor && (m_bInShutDown || m_bInUnload) && !GetRenderer()->IsPost3DRendererEnabled(), 0)
+    {
+        // Do not render during shutdown/unloading (should never reach here, unless something wrong with game/editor code)
+        return;
+    }
+
+#ifdef ENABLE_LW_PROFILERS
+    int64 renderStart = CryGetTicks();
+#endif
+    FUNCTION_PROFILER_3DENGINE;
+
+    if (GetCVars()->e_ScreenShot)
+    {
+        ScreenshotDispatcher(nRenderFlags, passInfo);
+        // screenshots can mess up the frame ids, be safe and recreate the rendering passinfo object after a screenshot
+        const_cast<SRenderingPassInfo&>(passInfo) = SRenderingPassInfo::CreateGeneralPassRenderingInfo(passInfo.GetCamera());
+    }
+
+    if (GetCVars()->e_DefaultMaterial)
+    {
+        _smart_ptr<IMaterial> pMat = GetMaterialManager()->LoadMaterial("Materials/material_default");
+        _smart_ptr<IMaterial> pTerrainMat = GetMaterialManager()->LoadMaterial("Materials/material_terrain_default");
+        GetRenderer()->SetDefaultMaterials(pMat, pTerrainMat);
+    }
+    else
+    {
+        GetRenderer()->SetDefaultMaterials(NULL, NULL);
+    }
+
+    // skip rendering if camera is invalid
+    if (IsCameraAnd3DEngineInvalid(passInfo, szDebugName))
+    {
+        return;
+    }
+
+    // this will also set the camera in passInfo for the General Pass (done here to support e_camerafreeze)
+    UpdateRenderingCamera(szDebugName, passInfo);
+
+    RenderInternal(nRenderFlags, passInfo, szDebugName);
+
+#if !defined(_RELEASE)
+    PrintDebugInfo(passInfo);
+#endif
+}
+
+void C3DEngine::RenderInternal(const int nRenderFlags, const SRenderingPassInfo& passInfo, [[maybe_unused]] const char* szDebugName)
+{
+    assert(m_pObjManager);
+
+
+    if (AZ::Interface<AzFramework::AtomActiveInterface>::Get())
+    {
+        GetRenderer()->EF_EndEf3D(
+            IsShadersSyncLoad() ? (nRenderFlags | SHDF_NOASYNC | SHDF_STREAM_SYNC) : nRenderFlags,
+            GetObjManager()->GetUpdateStreamingPrioriryRoundId(),
+            GetObjManager()->GetUpdateStreamingPrioriryRoundIdFast(),
+            passInfo);
+    }
+    else
+    {
+        UpdatePreRender(passInfo);
+        RenderScene(nRenderFlags, passInfo);
+        UpdatePostRender(passInfo);
+    }
+}
+
+
+void C3DEngine::PreWorldStreamUpdate(const CCamera& cam)
+{
+    if (m_szLevelFolder[0] != 0)
+    {
+        m_nStreamingFramesSinceLevelStart++;
+    }
+
+    // force preload terrain data if camera was teleported more than 32 meters
+    if (!IsAreaActivationInUse() || m_bLayersActivated)
+    {
+        float fDistance = m_vPrevMainFrameCamPos.GetDistance(cam.GetPosition());
+
+        if (m_vPrevMainFrameCamPos != Vec3(-1000000.f, -1000000.f, -1000000.f))
+        {
+            m_vAverageCameraMoveDir = m_vAverageCameraMoveDir * .75f + (cam.GetPosition() - m_vPrevMainFrameCamPos) / max(0.01f, GetTimer()->GetFrameTime()) * .25f;
+            if (m_vAverageCameraMoveDir.GetLength() > 10.f)
+            {
+                m_vAverageCameraMoveDir.SetLength(10.f);
+            }
+
+            float fNewSpeed = fDistance / max(0.001f, gEnv->pTimer->GetFrameTime());
+            if (fNewSpeed > m_fAverageCameraSpeed)
+            {
+                m_fAverageCameraSpeed = fNewSpeed * .20f + m_fAverageCameraSpeed * .80f;
+            }
+            else
+            {
+                m_fAverageCameraSpeed = fNewSpeed * .02f + m_fAverageCameraSpeed * .98f;
+            }
+            m_fAverageCameraSpeed = CLAMP(m_fAverageCameraSpeed, 0, 10.f);
+        }
+
+        // Adjust streaming mip bias based on camera speed and depending on installed on HDD or not
+        bool bStreamingFromHDD = gEnv->pSystem->GetStreamEngine()->IsStreamDataOnHDD();
+        if (GetCVars()->e_StreamAutoMipFactorSpeedThreshold)
+        {
+            if (m_fAverageCameraSpeed > GetCVars()->e_StreamAutoMipFactorSpeedThreshold)
+            {
+                GetRenderer()->SetTexturesStreamingGlobalMipFactor(bStreamingFromHDD ? GetCVars()->e_StreamAutoMipFactorMax * .5f : GetCVars()->e_StreamAutoMipFactorMax);
+            }
+            else
+            {
+                GetRenderer()->SetTexturesStreamingGlobalMipFactor(bStreamingFromHDD ? GetCVars()->e_StreamAutoMipFactorMin * .5f : GetCVars()->e_StreamAutoMipFactorMin);
+            }
+        }
+        else
+        {
+            if (bStreamingFromHDD)
+            {
+                GetRenderer()->SetTexturesStreamingGlobalMipFactor(0);
+            }
+            else
+            {
+                GetRenderer()->SetTexturesStreamingGlobalMipFactor(GetCVars()->e_StreamAutoMipFactorMaxDVD);
+            }
+        }
+
+        if (GetCVars()->e_AutoPrecacheCameraJumpDist && fDistance > GetCVars()->e_AutoPrecacheCameraJumpDist)
+        {
+            m_bContentPrecacheRequested = true;
+
+            // Invalidate existing precache info
+            m_pObjManager->IncrementUpdateStreamingPrioriryRoundIdFast(8);
+            m_pObjManager->IncrementUpdateStreamingPrioriryRoundId(8);
+        }
+
+        m_vPrevMainFrameCamPos = cam.GetPosition();
+    }
+}
+
+void C3DEngine::WorldStreamUpdate()
+{
+#if defined(STREAMENGINE_ENABLE_STATS)
+    static uint32 nCurrentRequestCount = 0;
+    static uint64 nCurrentBytesRead = 0;
+    if (m_nStreamingFramesSinceLevelStart == 1)
+    {
+        // store current streaming stats
+        SStreamEngineStatistics& fullStats = gEnv->pSystem->GetStreamEngine()->GetStreamingStatistics();
+        nCurrentBytesRead = fullStats.nTotalBytesRead;
+        nCurrentRequestCount = fullStats.nTotalRequestCount;
+    }
+#endif
+
+    static float fTestStartTime = 0;
+    if (m_nStreamingFramesSinceLevelStart == 1)
+    {
+        fTestStartTime = GetCurAsyncTimeSec();
+        gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME, 0, 0);
+    }
+
+    // Simple streaming performance test: Wait until all startup texture streaming jobs finish and print a message
+    if (!m_bEditor)
+    {
+        if (!m_bPreCacheEndEventSent)
+        {
+            IStreamEngine* pSE = gEnv->pSystem->GetStreamEngine();
+            SStreamEngineOpenStats openStats;
+            pSE->GetStreamingOpenStatistics(openStats);
+            bool bStarted =
+                (openStats.nOpenRequestCountByType[eStreamTaskTypeTexture] > 0) ||
+                (openStats.nOpenRequestCountByType[eStreamTaskTypeGeometry] > 0);
+
+            float fTime = GetCurAsyncTimeSec() - fTestStartTime;
+
+            switch (m_nStreamingFramesSinceLevelStart)
+            {
+            case 1:
+                pSE->PauseStreaming(true, (1 << eStreamTaskTypeTexture) | (1 << eStreamTaskTypeGeometry));
+                break;
+            case 4:
+                pSE->PauseStreaming(false, (1 << eStreamTaskTypeGeometry));
+                break;
+            case 8:
+                pSE->PauseStreaming(false, (1 << eStreamTaskTypeTexture));
+                break;
+            }
+
+            int nGlobalSystemState = gEnv->pSystem->GetSystemGlobalState();
+
+            if ((nGlobalSystemState != ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE && (!bStarted || fTime >= 10.0f)) && m_nStreamingFramesSinceLevelStart > 16)
+            {
+                gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE);
+
+                if (!bStarted)
+                {
+                    PrintMessage("Textures startup streaming finished in %.1f sec", fTime);
+                }
+                else
+                {
+                    PrintMessage("Textures startup streaming timed out after %.1f sec", fTime);
+                }
+
+                m_fTimeStateStarted = fTime;
+            }
+
+            if (nGlobalSystemState == ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_COMPLETE && (fTime - m_fTimeStateStarted) > 0.4f)
+            {
+                pSE->PauseStreaming(false, (1 << eStreamTaskTypeTexture) | (1 << eStreamTaskTypeGeometry));
+
+                m_bPreCacheEndEventSent = true;
+                gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_RUNNING);
+                gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_END, 0, 0);
+
+                fTestStartTime = 0.f;
+
+#if defined(STREAMENGINE_ENABLE_STATS)
+                SStreamEngineStatistics& fullStats = pSE->GetStreamingStatistics();
+                uint64 nBytesRead = fullStats.nTotalBytesRead - nCurrentBytesRead;
+                uint32 nRequestCount = fullStats.nTotalRequestCount - nCurrentRequestCount;
+
+                uint32 nOverallFileReadKB = (uint32)(nBytesRead / 1024);
+                uint32 nOverallFileReadNum = nRequestCount;
+                uint32 nBlockSize = (uint32)(nBytesRead / max((uint32)1, nRequestCount));
+                float fReadBandwidthMB = (float)fullStats.nTotalSessionReadBandwidth / (1024 * 1024);
+
+                PrintMessage("Average block size: %d KB, Average throughput: %.1f MB/sec, Jobs processed: %d (%.1f MB), File IO Bandwidth: %.2fMB/s",
+                    (nBlockSize) / 1024, (float)(nOverallFileReadKB / max(fTime, 1.f)) / 1024.f,
+                    nOverallFileReadNum, (float)nOverallFileReadKB / 1024.f,
+                    fReadBandwidthMB);
+
+                if (GetCVars()->e_StreamSaveStartupResultsIntoXML)
+                {
+                    const char* testResultsFile = "@cache@/TestResults/Streaming_Level_Start_Throughput.xml";
+
+                    AZ::IO::HandleType resultsFile = gEnv->pCryPak->FOpen(testResultsFile, "wb");
+                    if (resultsFile != AZ::IO::InvalidHandle)
+                    {
+                        AZ::IO::Print(resultsFile,
+                            "<phase name=\"Streaming_Level_Start_Throughput\">\n"
+                            "<metrics name=\"Streaming\">\n"
+                            "<metric name=\"Duration_Sec\" value=\"%.1f\"/>\n"
+                            "<metric name=\"BlockSize_KB\" value=\"%d\"/>\n"
+                            "<metric name=\"Throughput_MB_Sec\" value=\"%.1f\"/>\n"
+                            "<metric name=\"Jobs_Num\" value=\"%d\"/>\n"
+                            "<metric name=\"Read_MB\" value=\"%.1f\"/>\n"
+                            "</metrics>\n"
+                            "</phase>\n",
+                            fTime,
+                            (nOverallFileReadKB / nOverallFileReadNum),
+                            (float)nOverallFileReadKB / max(fTime, 1.f) / 1024.f,
+                            nOverallFileReadNum,
+                            (float)nOverallFileReadKB / 1024.f);
+                        gEnv->pCryPak->FClose(resultsFile);
+                    }
+                }
+#endif
+                // gEnv->pCryPak->GetFileReadSequencer()->EndSection(); // STREAMING
+            }
+            else if (m_szLevelFolder[0])
+            {
+                ProposeContentPrecache();
+            }
+        }
+    }
+    else
+    {
+        if (!m_bPreCacheEndEventSent && m_nStreamingFramesSinceLevelStart == 4)
+        {
+            m_bPreCacheEndEventSent = true;
+            gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_RUNNING);
+            gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_END, 0, 0);
+        }
+    }
+}
+
+void C3DEngine::PrintDebugInfo(const SRenderingPassInfo& passInfo)
+{
+    if (GetCVars()->e_DebugDraw)
+    {
+        f32 fColor[4] = {1, 1, 0, 1};
+
+        float fYLine = 8.0f, fYStep = 20.0f;
+
+        GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "e_DebugDraw = %d", GetCVars()->e_DebugDraw);
+
+        const char* szMode = "";
+
+        switch (static_cast<int>(GetCVars()->e_DebugDraw))
+        {
+        case  -1:
+            szMode = "Showing bounding boxes";
+            break;
+        case  1:
+            szMode = "bounding boxes, name of the used cgf, polycount, used LOD";
+            break;
+        case  -2:
+        case  2:
+            szMode = "color coded polygon count(red,yellow,green,turqoise, blue)";
+            break;
+        case  -3:
+            szMode = "show color coded LODs count, flashing color indicates LOD.";
+            break;
+        case  3:
+            szMode = "show color coded LODs count, flashing color indicates LOD.\nFormat: (Current LOD [Min LOD; Max LOD] (LOD Ratio / Distance to camera)";
+            break;
+        case  -4:
+        case  4:
+            szMode = "object texture memory usage in KB";
+            break;
+        case  -5:
+        case  5:
+            szMode = "number of render materials (color coded)";
+            break;
+        case  6:
+            szMode = "ambient color (R,G,B,A)";
+            break;
+        case  7:
+            szMode = "triangle count, number of render materials, texture memory in KB";
+            break;
+        case  8:
+            szMode = "Free slot";
+            break;
+        case  9:
+            szMode = "Free slot";
+            break;
+        case 10:
+            szMode = "Deprecated option, use \"r_showlines 2\" instead";
+            break;
+        case 11:
+            szMode = "Free slot";
+            break;
+        case 12:
+            szMode = "Free slot";
+            break;
+        case 13:
+            szMode = "occlusion amount (used during AO computations)";
+            break;
+        //          case 14:    szMode="";break;
+        case 15:
+            szMode = "display helpers";
+            break;
+        case 16:
+            szMode = "Debug Gun";
+            break;
+        case 17:
+            szMode = "streaming: buffer sizes (black: geometry, blue: texture)";
+            if (gEnv->pLocalMemoryUsage)
+            {
+                gEnv->pLocalMemoryUsage->OnRender(GetRenderer(), &passInfo.GetCamera());
+            }
+            break;
+        case 18:
+            szMode = "Free slot";
+            break;
+        case 19:
+            szMode = "physics proxy triangle count";
+            break;
+        case 20:
+            szMode = "Character attachments texture memory usage";
+            break;
+        case 21:
+            szMode = "Display animated objects distance to camera";
+            break;
+        case -22:
+        case 22:
+            szMode = "object's current LOD vertex count";
+            break;
+        case 23:
+            szMode = "Display shadow casters in red";
+            break;
+        case 24:
+            szMode = "Objects without LODs.\n    name - (triangle count)\n    draw calls - zpass/general/transparent/shadows/misc";
+            break;
+        case 25:
+            szMode = "Objects without LODs (Red). Objects that need more LODs (Blue)\n    name - (triangle count)\n    draw calls - zpass/general/transparent/shadows/misc";
+            break;
+
+        default:
+            assert(0);
+        }
+
+        GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "   %s", szMode);
+
+        if (GetCVars()->e_DebugDraw == 17)
+        {
+            GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "   StatObj geometry used: %.2fMb / %dMb", CObjManager::s_nLastStreamingMemoryUsage / (1024.f * 1024.f), GetCVars()->e_StreamCgfPoolSize);
+
+            ICVar* cVar = GetConsole()->GetCVar("r_TexturesStreaming");
+            if (!cVar || !cVar->GetIVal())
+            {
+                GetRenderer()->Draw2dLabel(8.0f, fYLine += fYStep, 2.0f, fColor, false, "   You have to set r_TexturesStreaming = 1 to see texture information!");
+            }
+        }
+    }
+
+    float fTextPosX = 10, fTextPosY = 10, fTextStepY = 12;
+
+    // print list of streamed meshes
+    if (m_pObjManager && GetCVars()->e_StreamCgf && GetCVars()->e_StreamCgfDebug >= 3)
+    {
+        // overall status
+        {
+            static char szCGFStreaming[256] = "";
+            static SObjectsStreamingStatus objectsStreamingStatus = {0};
+
+            {
+                m_pObjManager->GetObjectsStreamingStatus(objectsStreamingStatus);
+                sprintf_s(szCGFStreaming, 256, "CgfStrm: Loaded:%d InProg:%d All:%d Act:%d MemUsed:%2.2f MemReq:%2.2f Pool:%d",
+                    objectsStreamingStatus.nReady, objectsStreamingStatus.nInProgress, objectsStreamingStatus.nTotal, objectsStreamingStatus.nActive, float(objectsStreamingStatus.nAllocatedBytes) / 1024 / 1024, float(objectsStreamingStatus.nMemRequired) / 1024 / 1024, GetCVars()->e_StreamCgfPoolSize);
+            }
+
+            bool bOutOfMem((float(objectsStreamingStatus.nMemRequired) / 1024 / 1024) > GetCVars()->e_StreamCgfPoolSize);
+            bool bCloseToOutOfMem((float(objectsStreamingStatus.nMemRequired) / 1024 / 1024) > GetCVars()->e_StreamCgfPoolSize * 90 / 100);
+
+            ColorF color = Col_White;
+            if (bOutOfMem)
+            {
+                color = Col_Red;
+            }
+            else if (bCloseToOutOfMem)
+            {
+                color = Col_Orange;
+            }
+
+            DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, color, szCGFStreaming);
+            fTextPosY += fTextStepY;
+        }
+
+        DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_White, "------------------- List of meshes bigger than %d KB -------------------", GetCVars()->e_StreamCgfDebugMinObjSize);
+
+        for (int nObjId = 0; nObjId < m_pObjManager->GetArrStreamableObjects().Count(); nObjId++)
+        {
+            CStatObj* pStatObj = (CStatObj*)m_pObjManager->GetArrStreamableObjects()[nObjId].GetStreamAbleObject();
+
+            int nKB = pStatObj->GetStreamableContentMemoryUsage() >> 10;
+            int nSel = (pStatObj->m_nSelectedFrameId >= passInfo.GetMainFrameID() - 2);
+
+            string sName;
+            pStatObj->GetStreamableName(sName);
+
+            if ((nKB >= GetCVars()->e_StreamCgfDebugMinObjSize && strstr(sName.c_str(), GetCVars()->e_StreamCgfDebugFilter->GetString())) || nSel)
+            {
+                const char* pComment = 0;
+
+                if (!pStatObj->m_bCanUnload)
+                {
+                    pComment = "NO_STRM";
+                }
+                else if (pStatObj->m_pLod0)
+                {
+                    pComment = "  LOD_X";
+                }
+                else if (!pStatObj->m_bLodsAreLoadedFromSeparateFile && pStatObj->m_nLoadedLodsNum > 1)
+                {
+                    pComment = " SINGLE";
+                }
+                else if (pStatObj->m_nLoadedLodsNum > 1)
+                {
+                    pComment = "  LOD_0";
+                }
+                else
+                {
+                    pComment = "NO_LODS";
+                }
+
+                int nDiff = SATURATEB(int(float(nKB - GetCVars()->e_StreamCgfDebugMinObjSize) / max(1, (int)GetCVars()->e_StreamCgfDebugMinObjSize) * 255));
+                ColorB col(nDiff, 255 - nDiff, 0, 255);
+                if (nSel && (1 & (int)(GetCurTimeSec() * 5.f)))
+                {
+                    col = Col_Yellow;
+                }
+                ColorF fColor(col[0] / 255.f, col[1] / 255.f, col[2] / 255.f, col[3] / 255.f);
+
+                const char* pStatusText = "Unload";
+                if (pStatObj->m_eStreamingStatus == ecss_Ready)
+                {
+                    pStatusText = "Ready ";
+                }
+                else if (pStatObj->m_eStreamingStatus == ecss_InProgress)
+                {
+                    pStatusText = "InProg";
+                }
+
+                DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, fColor, "%1.2f mb, %s, %s, %s",
+                    1.f / 1024.f * nKB, pComment, pStatusText, sName.c_str());
+
+                if (fTextPosY > (float)gEnv->pRenderer->GetHeight())
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    if (m_arrProcessStreamingLatencyTestResults.Count())
+    {
+        float fAverTime = 0;
+        for (int i = 0; i < m_arrProcessStreamingLatencyTestResults.Count(); i++)
+        {
+            fAverTime += m_arrProcessStreamingLatencyTestResults[i];
+        }
+        fAverTime /= m_arrProcessStreamingLatencyTestResults.Count();
+
+        int nAverTexNum = 0;
+        for (int i = 0; i < m_arrProcessStreamingLatencyTexNum.Count(); i++)
+        {
+            nAverTexNum += m_arrProcessStreamingLatencyTexNum[i];
+        }
+        nAverTexNum /= m_arrProcessStreamingLatencyTexNum.Count();
+
+        DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Yellow, "------ SQT Average Time = %.1f, TexNum = %d ------",  fAverTime, nAverTexNum);
+
+        for (int i = 0; i < m_arrProcessStreamingLatencyTestResults.Count(); i++)
+        {
+            DrawTextLeftAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Yellow, "Run %d: Time = %.1f, TexNum = %d",
+                i, m_arrProcessStreamingLatencyTestResults[i], m_arrProcessStreamingLatencyTexNum[i]);
+        }
+    }
+
+#if defined(USE_GEOM_CACHES)
+#ifndef _RELEASE
+    if (GetCVars()->e_GeomCacheDebug)
+    {
+        m_pGeomCacheManager->DrawDebugInfo();
+    }
+    else
+    {
+        m_pGeomCacheManager->ResetDebugInfo();
+    }
+#endif
+#endif
+}
+
+void C3DEngine::UpdatePreRender(const SRenderingPassInfo& passInfo)
+{
+    AZ_TRACE_METHOD();
+    FUNCTION_PROFILER(GetISystem(), PROFILE_3DENGINE);
+
+    assert(passInfo.IsGeneralPass());
+
+    // Compute global shadow cascade parameters.
+    {
+        m_fGsmRange = GetCVars()->e_GsmRange;
+        m_fGsmRangeStep = GetCVars()->e_GsmRangeStep;
+
+        //!!!also formulas for computing biases per gsm needs to be changed
+        m_fShadowsConstBias = GetCVars()->e_ShadowsConstBias;
+        m_fShadowsSlopeBias = GetCVars()->e_ShadowsSlopeBias;
+
+        if (m_eShadowMode == ESM_HIGHQUALITY)
+        {
+            m_fGsmRange = min(0.15f, GetCVars()->e_GsmRange);
+            m_fGsmRangeStep = min(2.8f, GetCVars()->e_GsmRangeStep);
+
+            m_fShadowsConstBias = min(GetCVars()->e_ShadowsConstBiasHQ, GetCVars()->e_ShadowsConstBias);
+            m_fShadowsSlopeBias = min(GetCVars()->e_ShadowsSlopeBiasHQ, GetCVars()->e_ShadowsSlopeBias);
+        }
+
+        const int nCascadeCount = Get3DEngine()->GetShadowsCascadeCount(NULL);
+        m_pObjManager->SetGSMMaxDistance(Get3DEngine()->m_fGsmRange * powf(Get3DEngine()->m_fGsmRangeStep, (float)nCascadeCount));
+    }
+
+    // (bethelz) This has to happen before particle updates.
+    m_PhysicsAreaUpdates.Update();
+
+    if (passInfo.RenderClouds())
+    {
+        if (m_pCloudsManager)
+        {
+            m_pCloudsManager->MoveClouds();
+        }
+
+        CVolumeObjectRenderNode::MoveVolumeObjects();
+    }
+
+    UpdateSun(passInfo);
+
+    // Set traceable fog volume areas
+    CFogVolumeRenderNode::SetTraceableArea(AABB(passInfo.GetCamera().GetPosition(), 1024.0f), passInfo);
+}
+
+void C3DEngine::UpdatePostRender(const SRenderingPassInfo& passInfo)
+{
+    AZ_TRACE_METHOD();
+    FUNCTION_PROFILER(GetISystem(), PROFILE_3DENGINE);
+
+    assert (m_pObjManager);
+
+    m_pObjManager->CheckTextureReadyFlag();
+    if (GetCVars()->e_StreamCgf)
+    {
+        static Array2d<int> memUsage;
+
+        int nArrayDim = 256;
+#ifndef CONSOLE_CONST_CVAR_MODE
+        if (GetCVars()->e_StreamCgfDebugHeatMap == 1)
+        {
+            memUsage.Allocate(nArrayDim);
+            CCamera camOld = passInfo.GetCamera();
+
+            PrintMessage("Computing mesh streaming heat map");
+
+            //The assumption is that this is called on Main Thread, otherwise the loop
+            //Should be wrapped inside a EnumerateHandlers lambda.
+            auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
+            const float defaultTerrainHeight = AzFramework::Terrain::TerrainDataRequests::GetDefaultTerrainHeight();
+
+            const AZ::Aabb terrainAabb = terrain ? terrain->GetTerrainAabb() : AZ::Aabb::CreateFromPoint(AZ::Vector3::CreateZero());
+            const int nTerrainSizeX = static_cast<int>(terrainAabb.GetXExtent());
+            const int nTerrainSizeY = static_cast<int>(terrainAabb.GetYExtent());
+            const int nStepX = nTerrainSizeX / nArrayDim;
+            const int nStepY = nTerrainSizeY / nArrayDim;
+
+            for (int x = 0; x < nTerrainSizeX; x += nStepX)
+            {
+                for (int y = 0; y < nTerrainSizeY; y += nStepY)
+                {
+                    CCamera camTmp = camOld;
+                    float terrainHeight = terrain ? terrain->GetHeightFromFloats((float)x, (float)y) : defaultTerrainHeight;
+                    camTmp.SetPosition(Vec3((float)x + (float)nStepX / 2.f, (float)y + (float)nStepY / 2.f, terrainHeight));
+                    //SetCamera(camTmp);
+                    m_pObjManager->ProcessObjectsStreaming(passInfo);
+
+                    SObjectsStreamingStatus objectsStreamingStatus;
+                    m_pObjManager->GetObjectsStreamingStatus(objectsStreamingStatus);
+
+                    memUsage[x / nStepX][y / nStepY] = objectsStreamingStatus.nMemRequired;
+                }
+
+                if (!((x / nStepX) & 31))
+                {
+                    PrintMessage(" working ...");
+                }
+            }
+
+            PrintMessage(" done");
+
+            GetCVars()->e_StreamCgfDebugHeatMap = 2;
+            //SetCamera(camOld);
+        }
+        else if (GetCVars()->e_StreamCgfDebugHeatMap == 2)
+        {
+            auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
+            const float defaultTerrainHeight = AzFramework::Terrain::TerrainDataRequests::GetDefaultTerrainHeight();
+
+            const AZ::Aabb terrainAabb = terrain ? terrain->GetTerrainAabb() : AZ::Aabb::CreateFromPoint(AZ::Vector3::CreateZero());
+            const float terrainSizeX = terrainAabb.GetXExtent();
+            const float terrainSizeY = terrainAabb.GetYExtent();
+            const float fStepX = terrainSizeX / nArrayDim;
+            const float fStepY = terrainSizeY / nArrayDim;
+
+            for (int x = 0; x < memUsage.GetSize(); x++)
+            {
+                for (int y = 0; y < memUsage.GetSize(); y++)
+                {
+                    float terrainHeight = terrain ? terrain->GetHeightFromFloats((float)x * fStepX, (float)y * fStepY) : defaultTerrainHeight;
+                    Vec3 v0((float)x* fStepX,       (float)y* fStepY,       terrainHeight);
+                    Vec3 v1((float)x* fStepX + fStepX, (float)y* fStepY + fStepY, v0.z + fStepX);
+                    v0 += Vec3(.25f, .25f, .25f);
+                    v1 -= Vec3(.25f, .25f, .25f);
+                    AABB box(v0, v1);
+                    if (!passInfo.GetCamera().IsAABBVisible_F(box))
+                    {
+                        continue;
+                    }
+
+                    int nMemUsageMB = memUsage[(int)(x)][(int)(y)] / 1024 / 1024;
+
+                    int nOverLoad = nMemUsageMB - GetCVars()->e_StreamCgfPoolSize;
+
+                    ColorB col = Col_Red;
+
+                    if (nOverLoad < GetCVars()->e_StreamCgfPoolSize / 2)
+                    {
+                        col = Col_Yellow;
+                    }
+
+                    if (nOverLoad < 0)
+                    {
+                        col = Col_Green;
+                    }
+
+                    DrawBBox(box, col);
+                }
+            }
+        }
+#endif //CONSOLE_CONST_CVAR_MODE
+        m_pObjManager->ProcessObjectsStreaming(passInfo);
+    }
+    else
+    {
+        m_pObjManager->GetStreamPreCacheCameras()[0].vPosition = passInfo.GetCamera().GetPosition();
+        if (Distance::Point_AABBSq(m_pObjManager->GetStreamPreCacheCameras()[0].vPosition, m_pObjManager->GetStreamPreCacheCameras()[0].bbox) > 0.0f)
+        {
+            m_pObjManager->GetStreamPreCacheCameras()[0].bbox = AABB(m_pObjManager->GetStreamPreCacheCameras()[0].vPosition, GetCVars()->e_StreamPredictionBoxRadius);
+        }
+        m_pObjManager->UpdateObjectsStreamingPriority(false, passInfo);
+    }
+
+    // (bethelz) Per-frame precache request handled by streaming systems.
+    m_bContentPrecacheRequested = false;
+}
+
+int __cdecl C3DEngine__Cmp_SRNInfo(const void* v1, const void* v2)
+{
+    SRNInfo* p1 = (SRNInfo*)v1;
+    SRNInfo* p2 = (SRNInfo*)v2;
+
+    float fViewDist1 = p1->fMaxViewDist - p1->objSphere.radius;
+    float fViewDist2 = p2->fMaxViewDist - p2->objSphere.radius;
+
+    // if same - give closest sectors higher priority
+    if (fViewDist1 > fViewDist2)
+    {
+        return 1;
+    }
+    else if (fViewDist1 < fViewDist2)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+void C3DEngine::SetSkyMaterialPath(const string& skyMatName)
+{
+    m_skyMatName = skyMatName;
+    m_pSkyMat = nullptr;
+}
+
+void C3DEngine::SetSkyLowSpecMaterialPath(const string& skyLowSpecMatName)
+{
+    m_skyLowSpecMatName = skyLowSpecMatName;
+    m_pSkyLowSpecMat = nullptr;
+}
+
+void C3DEngine::LoadSkyMaterial()
+{
+    const int skyType = GetCVars()->e_SkyType;
+    if (skyType == 0)
+    {
+        if (!m_pSkyLowSpecMat)
+        {
+            m_pSkyLowSpecMat = m_skyLowSpecMatName.empty() ? nullptr : m_pMatMan->LoadMaterial(m_skyLowSpecMatName.c_str(), false, false, MTL_FLAG_IS_SKY);
+            AZ_Warning("3DEngine", m_pSkyLowSpecMat, "Missing low spec sky material: %s", m_skyLowSpecMatName.c_str());
+        }
+    }
+    else
+    {
+        if (!m_pSkyMat)
+        {
+            m_pSkyMat = m_skyMatName.empty() ? nullptr : m_pMatMan->LoadMaterial(m_skyMatName.c_str(), false, false, MTL_FLAG_IS_SKY);
+            AZ_Warning("3DEngine", m_pSkyMat, "Missing sky material: %s", m_skyMatName.c_str());
+        }
+    }
+    m_previousSkyType = skyType;
+}
+
+_smart_ptr<IMaterial> C3DEngine::GetSkyMaterial()
+{
+    const int skyType = GetCVars()->e_SkyType;
+
+    // If e_SkyType has changed, then we may need to load a different sky material.
+    if (skyType != m_previousSkyType)
+    {
+        LoadSkyMaterial();
+    }
+
+    return (skyType == 0) ? m_pSkyLowSpecMat : m_pSkyMat;
+}
+
+void C3DEngine::SetSkyMaterial(_smart_ptr<IMaterial> pSkyMat)
+{
+    m_pSkyMat = pSkyMat;
+}
+
+bool C3DEngine::IsHDRSkyMaterial(_smart_ptr<IMaterial> pMat) const
+{
+    return pMat && !azstricmp(pMat->GetSafeSubMtl(0)->GetShaderItem().m_pShader->GetName(), "SkyHDR");
+}
+
+void C3DEngine::RenderScene(const int nRenderFlags, const SRenderingPassInfo& passInfo)
+{
+    FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
+    AZ_TRACE_METHOD();
+    CRY_ASSERT(passInfo.IsGeneralPass());
+    CRY_ASSERT(m_pVisAreaManager);
+    CRY_ASSERT(m_pClipVolumeManager);
+    CRY_ASSERT(m_pDecalManager);
+
+    GetObjManager()->GetCullThread().SetActive(true);
+
+    if (GetCVars()->e_CoverageBuffer)
+    {
+        m_pCoverageBuffer->BeginFrame(passInfo);
+    }
+
+    if (m_pVisAreaManager != nullptr)
+    {
+        m_pVisAreaManager->DrawOcclusionAreasIntoCBuffer(m_pCoverageBuffer, passInfo);
+        m_pVisAreaManager->CheckVis(passInfo);
+    }
+
+    if (m_pClipVolumeManager)
+    {
+        m_pClipVolumeManager->PrepareVolumesForRendering(passInfo);
+    }
+
+    if (m_pObjManager)
+    {
+        m_pObjManager->RenderAllObjectDebugInfo();
+    }
+    SRendItemSorter rendItemSorter = SRendItemSorter::CreateRendItemSorter(passInfo);
+
+    // make sure all jobs from the previous frame have finished
+    threadID nPrevThreadID = 0;
+    gEnv->pRenderer->EF_Query(EFQ_RenderThreadList, nPrevThreadID);
+    gEnv->pRenderer->GetFinalizeRendItemJobExecutor(nPrevThreadID)->WaitForCompletion();
+    gEnv->pRenderer->GetFinalizeShadowRendItemJobExecutor(nPrevThreadID)->WaitForCompletion();
+
+    GetRenderer()->EF_ClearSkinningDataPool();
+    GetRenderer()->BeginSpawningGeneratingRendItemJobs(passInfo.ThreadID());
+
+    GetRenderer()->EF_StartEf(passInfo);
+
+    m_bIsInRenderScene = true;
+    COctreeNode::ReleaseEmptyNodes();
+
+    m_LightVolumesMgr.Clear(passInfo);
+
+    SubmitSun(passInfo);
+
+    if (GetCVars()->e_StatObjBufferRenderTasks && m_pObjManager != nullptr)
+    {
+        m_pObjManager->BeginOcclusionCulling(passInfo);
+    }
+
+    if (m_pVisAreaManager != nullptr)
+    {
+        m_pVisAreaManager->DrawVisibleSectors(passInfo, rendItemSorter);
+    }
+    m_nOceanRenderFlags &= ~OCR_OCEANVOLUME_VISIBLE;
+
+    if (IsOutdoorVisible() || GetRenderer()->IsPost3DRendererEnabled())
+    {
+        if (m_pVisAreaManager != nullptr && m_pVisAreaManager->m_lstOutdoorPortalCameras.Count()   &&
+            (m_pVisAreaManager->m_pCurArea || m_pVisAreaManager->m_pCurPortal))
+        { // enable multi-camera culling
+            const_cast<CCamera&>(passInfo.GetCamera()).m_pMultiCamera = &m_pVisAreaManager->m_lstOutdoorPortalCameras;
+        }
+
+        if (IsOutdoorVisible())
+        {
+            RenderSkyBox(GetSkyMaterial(), passInfo);
+        }
+
+        rendItemSorter.IncreaseOctreeCounter();
+        {
+            FRAME_PROFILER_LEGACYONLY("COctreeNode::Render_____", GetSystem(), PROFILE_3DENGINE);
+            AZ_TRACE_METHOD_NAME("COctreeNode::Render");
+            if (m_pObjectsTree != nullptr)
+            {
+                m_pObjectsTree->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS, passInfo, rendItemSorter);
+            }
+        }
+        rendItemSorter.IncreaseGroupCounter();
+    }
+    else if (m_pVisAreaManager && m_pVisAreaManager->IsSkyVisible())
+    {
+        RenderSkyBox(GetSkyMaterial(), passInfo);
+    }
+    
+    // Outdoor is not visible, that means there is no SkyBox to render.
+    // So we want to clear the GBuffer RT/background in order to avoid artifacts.
+    GetRenderer()->SetClearBackground(!IsOutdoorVisible());
+
+    if (nRenderFlags & SHDF_ALLOW_AO)
+    {
+        SVOGILegacyRequestBus::Broadcast(&SVOGILegacyRequests::UpdateRenderData);
+    }
+
+    {
+        FRAME_PROFILER_LEGACYONLY("COctreeNode::Render_Object_Nodes_NEAR", GetSystem(), PROFILE_3DENGINE);
+        AZ_TRACE_METHOD_NAME("COctreeNode::Render_Object_Nodes_NEAR");
+        rendItemSorter.IncreaseOctreeCounter();
+        if (GetCVars()->e_PortalsBigEntitiesFix)
+        {
+            if (!IsOutdoorVisible() && GetVisAreaManager() != nullptr && GetVisAreaManager()->GetCurVisArea())
+            {
+                if (GetVisAreaManager()->GetCurVisArea()->IsConnectedToOutdoor())
+                {
+                    CCamera cam = passInfo.GetCamera();
+                    cam.SetFrustum(cam.GetViewSurfaceX(), cam.GetViewSurfaceZ(), cam.GetFov(), min(cam.GetNearPlane(), 1.f), 2.f, cam.GetPixelAspectRatio());
+                    m_pObjectsTree->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS | OCTREENODE_RENDER_FLAG_OBJECTS_ONLY_ENTITIES,  SRenderingPassInfo::CreateTempRenderingInfo(cam, passInfo), rendItemSorter);
+                }
+            }
+        }
+    }
+    rendItemSorter.IncreaseGroupCounter();
+
+    // render special objects like laser beams intersecting entire level
+    for (int i = 0; i < m_lstAlwaysVisible.Count(); i++)
+    {
+        IRenderNode* pObj = m_lstAlwaysVisible[i];
+        const AABB& objBox = pObj->GetBBox();
+        // don't frustum cull the HUD. When e.g. zooming the FOV for this camera is very different to the
+        // fixed HUD FOV, and this can cull incorrectly.
+        const unsigned int dwRndFlags = pObj->GetRndFlags();
+        if (dwRndFlags & ERF_HUD || passInfo.GetCamera().IsAABBVisible_E(objBox))
+        {
+            FRAME_PROFILER_LEGACYONLY("C3DEngine::RenderScene_DrawAlwaysVisible", GetSystem(), PROFILE_3DENGINE);
+            AZ_TRACE_METHOD_NAME("COctreeNode::RenderScene_DrawAlwaysVisible");
+
+            Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+            float fEntDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
+            assert(fEntDistance >= 0 && _finite(fEntDistance));
+            if (fEntDistance < pObj->m_fWSMaxViewDist && GetObjManager() != nullptr)
+            {
+                GetObjManager()->RenderObject(pObj, objBox, fEntDistance, pObj->GetRenderNodeType(), passInfo, rendItemSorter);
+            }
+        }
+    }
+    rendItemSorter.IncreaseGroupCounter();
+
+    if (m_pOcean)
+    {
+        ProcessOcean(passInfo);
+    }
+
+    if (passInfo.RenderDecals() && m_pDecalManager != nullptr)
+    {
+        m_pDecalManager->Render(passInfo);
+    }
+
+    // tell the occlusion culler that no new work will be submitted
+    if (GetCVars()->e_StatObjBufferRenderTasks == 1 && GetObjManager() != nullptr)
+    {
+        GetObjManager()->PushIntoCullQueue(SCheckOcclusionJobData::CreateQuitJobData());
+    }
+
+    // fill shadow list here to allow more time between starting and waiting for the occlusion buffer
+    InitShadowFrustums(passInfo);
+
+    gEnv->pSystem->DoWorkDuringOcclusionChecks();
+
+    if (GetCVars()->e_StatObjBufferRenderTasks && m_pObjManager != nullptr)
+    {
+        m_pObjManager->RenderBufferedRenderMeshes(passInfo);
+    }
+
+    // don't start shadow jobs if we aren't generating shadows
+    if ((nRenderFlags & SHDF_NO_SHADOWGEN) == 0)
+    {
+        GetRenderer()->EF_InvokeShadowMapRenderJobs(IsShadersSyncLoad() ? (nRenderFlags | SHDF_NOASYNC | SHDF_STREAM_SYNC) : nRenderFlags);
+    }
+
+    m_LightVolumesMgr.Update(passInfo);
+
+    SetupDistanceFog();
+
+    SetupClearColor();
+
+    {
+        FRAME_PROFILER("Renderer::EF_EndEf3D", GetSystem(), PROFILE_RENDERER);
+        // TODO: separate SHDF_NOASYNC and SHDF_STREAM_SYNC flags
+        GetRenderer()->EF_EndEf3D(IsShadersSyncLoad() ? (nRenderFlags | SHDF_NOASYNC | SHDF_STREAM_SYNC) : nRenderFlags,  GetObjManager()->GetUpdateStreamingPrioriryRoundId(), GetObjManager()->GetUpdateStreamingPrioriryRoundIdFast(), passInfo);
+    }
+
+    GetRenderer()->EnableFog(false);
+
+    bool bIsMultiThreadedRenderer = false;
+    gEnv->pRenderer->EF_Query(EFQ_RenderMultithreaded, bIsMultiThreadedRenderer);
+    if (bIsMultiThreadedRenderer)
+    {
+        gEnv->pRenderer->EndSpawningGeneratingRendItemJobs();
+    }
+
+    m_bIsInRenderScene = false;
+
+#ifndef _RELEASE
+    IF (GetCVars()->e_LightVolumesDebug, 0)
+    {
+        m_LightVolumesMgr.DrawDebug(passInfo);
+    }
+#endif
+}
+
+void C3DEngine::WaitForCullingJobsCompletion()
+{
+    const bool waitForOcclusionJobCompletion = true;
+    m_pObjManager->EndOcclusionCulling(waitForOcclusionJobCompletion);
+    COctreeNode::WaitForContentJobCompletion();
+}
+
+void C3DEngine::RenderSceneReflection(const int nRenderFlags, const SRenderingPassInfo& passInfo)
+{
+    FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
+    AZ_TRACE_METHOD();
+    CRY_ASSERT(passInfo.IsRecursivePass());
+    CRY_ASSERT(passInfo.GetRecursiveLevel() < MAX_RECURSION_LEVELS);
+    CRY_ASSERT(m_pVisAreaManager);
+    CRY_ASSERT(m_pClipVolumeManager);
+    CRY_ASSERT(m_pDecalManager);
+
+    if (!GetCVars()->e_Recursion)
+    {
+        return;
+    }
+
+    if (m_pVisAreaManager != nullptr)
+    {
+        m_pVisAreaManager->CheckVis(passInfo);
+    }
+
+    if (m_pClipVolumeManager != nullptr)
+    {
+        m_pClipVolumeManager->PrepareVolumesForRendering(passInfo);
+    }
+    ////////////////////////////////////////////////////////////////////////////////////////
+    // From here we add render elements of main scene
+    ////////////////////////////////////////////////////////////////////////////////////////
+    SRendItemSorter rendItemSorter = SRendItemSorter::CreateRendItemSorter(passInfo);
+
+    GetRenderer()->EF_StartEf(passInfo);
+
+    if (m_pVisAreaManager != nullptr)
+    {
+        m_pVisAreaManager->DrawVisibleSectors(passInfo, rendItemSorter);
+    }
+
+    if (IsOutdoorVisible() || GetRenderer()->IsPost3DRendererEnabled())
+    {
+        if (m_pVisAreaManager != nullptr && m_pVisAreaManager->m_lstOutdoorPortalCameras.Count() &&
+            (m_pVisAreaManager->m_pCurArea || m_pVisAreaManager->m_pCurPortal))
+        { // enable multi-camera culling
+            const_cast<CCamera&>(passInfo.GetCamera()).m_pMultiCamera = &m_pVisAreaManager->m_lstOutdoorPortalCameras;
+        }
+
+        if (IsOutdoorVisible())
+        {
+            RenderSkyBox(GetSkyMaterial(), passInfo);
+        }
+
+        {
+            rendItemSorter.IncreaseOctreeCounter();
+            FRAME_PROFILER("COctreeNode::Render_____", GetSystem(), PROFILE_3DENGINE);
+            if (m_pObjectsTree != nullptr)
+            {
+                m_pObjectsTree->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS, passInfo, rendItemSorter);
+            }
+        }
+        rendItemSorter.IncreaseGroupCounter();
+    }
+    else if (m_pVisAreaManager != nullptr && m_pVisAreaManager->IsSkyVisible())
+    {
+        RenderSkyBox(GetSkyMaterial(), passInfo);
+    }
+
+    {
+        FRAME_PROFILER("COctreeNode::Render_Object_Nodes_NEAR", GetSystem(), PROFILE_3DENGINE);
+        rendItemSorter.IncreaseOctreeCounter();
+        if (GetCVars()->e_PortalsBigEntitiesFix)
+        {
+            if (!IsOutdoorVisible() && GetVisAreaManager() != nullptr && GetVisAreaManager()->GetCurVisArea())
+            {
+                if (GetVisAreaManager()->GetCurVisArea()->IsConnectedToOutdoor())
+                {
+                    CCamera cam = passInfo.GetCamera();
+                    cam.SetFrustum(cam.GetViewSurfaceX(), cam.GetViewSurfaceZ(), cam.GetFov(), min(cam.GetNearPlane(), 1.f), 2.f, cam.GetPixelAspectRatio());
+                    if (m_pObjectsTree != nullptr)
+                    {
+                        m_pObjectsTree->Render_Object_Nodes(false, OCTREENODE_RENDER_FLAG_OBJECTS | OCTREENODE_RENDER_FLAG_OBJECTS_ONLY_ENTITIES, SRenderingPassInfo::CreateTempRenderingInfo(cam, passInfo), rendItemSorter);
+                    }
+                }
+            }
+        }
+    }
+    rendItemSorter.IncreaseGroupCounter();
+
+    // render special objects like laser beams intersecting entire level
+    for (int i = 0; i < m_lstAlwaysVisible.Count(); i++)
+    {
+        IRenderNode* pObj = m_lstAlwaysVisible[i];
+        const AABB& objBox = pObj->GetBBox();
+        // don't frustum cull the HUD. When e.g. zooming the FOV for this camera is very different to the
+        // fixed HUD FOV, and this can cull incorrectly.
+        const unsigned int dwRndFlags = pObj->GetRndFlags();
+        if (dwRndFlags & ERF_HUD || passInfo.GetCamera().IsAABBVisible_E(objBox))
+        {
+            FRAME_PROFILER("C3DEngine::RenderScene_DrawAlwaysVisible", GetSystem(), PROFILE_3DENGINE);
+
+            Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+            float fEntDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
+            assert(fEntDistance >= 0 && _finite(fEntDistance));
+            if (fEntDistance < pObj->m_fWSMaxViewDist)
+            {
+                GetObjManager()->RenderObject(pObj, objBox, fEntDistance, pObj->GetRenderNodeType(), passInfo, rendItemSorter);
+            }
+        }
+    }
+    rendItemSorter.IncreaseGroupCounter();
+
+    if (m_pOcean)
+    {
+        ProcessOcean(passInfo);
+    }
+
+    //Update light volumes again. Processing particles may have resulted in an increase in the number of light volumes.
+    m_LightVolumesMgr.Update(passInfo);
+
+    if (passInfo.RenderDecals() && m_pDecalManager != nullptr)
+    {
+        m_pDecalManager->Render(passInfo);
+    }
+
+    {
+        FRAME_PROFILER("Renderer::EF_EndEf3D", GetSystem(), PROFILE_RENDERER);
+        GetRenderer()->EF_EndEf3D(IsShadersSyncLoad() ? (nRenderFlags | SHDF_NOASYNC | SHDF_STREAM_SYNC) : nRenderFlags,  GetObjManager()->GetUpdateStreamingPrioriryRoundId(), GetObjManager()->GetUpdateStreamingPrioriryRoundIdFast(), passInfo);
+    }
+}
+
+void C3DEngine::ProcessOcean(const SRenderingPassInfo& passInfo)
+{
+    FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
+    AZ_TRACE_METHOD();
+
+    AZ_Assert(m_pOcean != nullptr, "Ocean pointer must be validated before calling ProcessOcean");
+
+    if (GetOceanRenderFlags() & OCR_NO_DRAW || !GetVisAreaManager() || GetCVars()->e_DefaultMaterial)
+    {
+        return;
+    }
+
+    bool bOceanIsForcedByVisAreaFlags = GetVisAreaManager()->IsOceanVisible();
+
+    if (!IsOutdoorVisible() && !bOceanIsForcedByVisAreaFlags)
+    {
+        return;
+    }
+
+    bool bOceanVisible = false;
+    if (OceanToggle::IsActive())
+    {
+        bOceanVisible = OceanRequest::OceanIsEnabled();
+    }
+    else
+    {
+        bOceanVisible = true;
+    }
+
+    if (bOceanVisible && passInfo.RenderWaterOcean() && m_bOcean)
+    {
+        Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+        float fWaterPlaneSize = passInfo.GetCamera().GetFarPlane();
+        const float fOceanLevel = OceanToggle::IsActive() ? OceanRequest::GetOceanLevel():  m_pOcean->GetWaterLevel();
+
+        AABB boxOcean(Vec3(vCamPos.x - fWaterPlaneSize, vCamPos.y - fWaterPlaneSize, std::numeric_limits<float>::lowest()),
+            Vec3(vCamPos.x + fWaterPlaneSize, vCamPos.y + fWaterPlaneSize, fOceanLevel + 0.5f));
+
+        if ((!bOceanIsForcedByVisAreaFlags && passInfo.GetCamera().IsAABBVisible_EM(boxOcean)) ||
+            (bOceanIsForcedByVisAreaFlags && passInfo.GetCamera().IsAABBVisible_E (boxOcean)))
+        {
+            bool bOceanIsVisibleFromIndoor = true;
+            if (class PodArray<CCamera>* pMultiCamera = passInfo.GetCamera().m_pMultiCamera)
+            {
+                for (int i = 0; i < pMultiCamera->Count(); i++)
+                {
+                    CVisArea* pExitPortal = (CVisArea*)(pMultiCamera->Get(i))->m_pPortal;
+                    float fMinZ = pExitPortal->GetAABBox()->min.z;
+                    float fMaxZ = pExitPortal->GetAABBox()->max.z;
+
+                    if (!bOceanIsForcedByVisAreaFlags)
+                    {
+                        if (fMinZ > fOceanLevel && vCamPos.z < fMinZ)
+                        {
+                            bOceanIsVisibleFromIndoor = false;
+                        }
+
+                        if (fMaxZ < fOceanLevel && vCamPos.z > fMaxZ)
+                        {
+                            bOceanIsVisibleFromIndoor = false;
+                        }
+                    }
+                }
+            }
+
+            if (bOceanIsVisibleFromIndoor)
+            {
+                m_pOcean->Update(passInfo);
+
+                if ((GetOceanRenderFlags() & OCR_OCEANVOLUME_VISIBLE))
+                {
+                    if (passInfo.RenderWaterOcean())
+                    {
+                        m_pOcean->Render(passInfo);
+                        m_pOcean->SetLastFov(passInfo.GetCamera().GetFov());
+                    }
+                }
+            }
+        }
+    }
+
+    if (GetCVars()->e_WaterRipplesDebug > 0)
+    {
+        GetRenderer()->EF_DrawWaterSimHits();
+    }
+}
+
+void C3DEngine::RenderSkyBox(_smart_ptr<IMaterial> pMat, const SRenderingPassInfo& passInfo)
+{
+    FUNCTION_PROFILER_3DENGINE_LEGACYONLY;
+    AZ_TRACE_METHOD();
+
+    if (!Get3DEngine()->GetCoverageBuffer()->IsOutdooVisible())
+    {
+        return;
+    }
+
+    const float fForceDrawLastSortOffset = 100000.0f;
+
+    // hdr sky dome
+    // TODO: temporary workaround to force the right sky dome for the selected shader
+    if (m_pREHDRSky && IsHDRSkyMaterial(pMat))
+    {
+        if (GetCVars()->e_SkyBox)
+        {
+#ifndef CONSOLE_CONST_CVAR_MODE
+            if (GetCVars()->e_SkyQuality < 1)
+            {
+                GetCVars()->e_SkyQuality = 1;
+            }
+            else if (GetCVars()->e_SkyQuality > 2)
+            {
+                GetCVars()->e_SkyQuality = 2;
+            }
+#endif
+            m_pSkyLightManager->SetQuality(GetCVars()->e_SkyQuality);
+
+            // set sky light incremental update rate and perform update
+            if (GetCVars()->e_SkyUpdateRate <= 0.0f)
+            {
+                GetCVars()->e_SkyUpdateRate = 0.01f;
+            }
+            m_pSkyLightManager->IncrementalUpdate(GetCVars()->e_SkyUpdateRate, passInfo);
+
+            // prepare render object
+            CRenderObject* pObj = GetRenderer()->EF_GetObject_Temp(passInfo.ThreadID());
+            if (!pObj)
+            {
+                return;
+            }
+            pObj->m_II.m_Matrix.SetTranslationMat(passInfo.GetCamera().GetPosition());
+            pObj->m_pRenderNode = 0;//m_pREHDRSky;
+            pObj->m_fSort = fForceDrawLastSortOffset; // force sky to draw last
+
+            /*          if( 0 == m_nRenderStackLevel )
+            {
+            // set scissor rect
+            pObj->m_nScissorX1 = GetCamera().m_ScissorInfo.x1;
+            pObj->m_nScissorY1 = GetCamera().m_ScissorInfo.y1;
+            pObj->m_nScissorX2 = GetCamera().m_ScissorInfo.x2;
+            pObj->m_nScissorY2 = GetCamera().m_ScissorInfo.y2;
+            }*/
+
+            m_pREHDRSky->m_pRenderParams = m_pSkyLightManager->GetRenderParams();
+            m_pREHDRSky->m_moonTexId = m_nNightMoonTexId;
+
+            // add sky dome to render list
+            SRendItemSorter rendItemSorter = SRendItemSorter::CreateRendItemSorter(passInfo);
+            GetRenderer()->EF_AddEf(m_pREHDRSky, pMat->GetSafeSubMtl(0)->GetShaderItem(), pObj, passInfo, EFSLIST_GENERAL, 1, rendItemSorter);
+        }
+    }
+    // skybox
+    else
+    {
+        if (pMat && m_pRESky && GetCVars()->e_SkyBox)
+        {
+            CRenderObject* pObj = GetRenderer()->EF_GetObject_Temp(passInfo.ThreadID());
+            if (!pObj)
+            {
+                return;
+            }
+            pObj->m_II.m_Matrix.SetTranslationMat(passInfo.GetCamera().GetPosition());
+            pObj->m_II.m_Matrix = pObj->m_II.m_Matrix * Matrix33::CreateRotationZ(DEG2RAD(m_fSkyBoxAngle));
+            pObj->m_fSort = fForceDrawLastSortOffset; // force sky to draw last
+
+            if (OceanToggle::IsActive())
+            {
+                m_pRESky->m_fTerrainWaterLevel = OceanRequest::GetOceanLevelOrDefault(-100000.0f);
+            }
+            else
+            {
+                const float waterLevel = m_pOcean ? m_pOcean->GetWaterLevel() : 0.0f;
+                m_pRESky->m_fTerrainWaterLevel = max(0.0f, waterLevel);
+            }
+            m_pRESky->m_fSkyBoxStretching = m_fSkyBoxStretching;
+
+            SRendItemSorter rendItemSorter = SRendItemSorter::CreateRendItemSorter(passInfo);
+            GetRenderer()->EF_AddEf(m_pRESky, pMat->GetSafeSubMtl(0)->GetShaderItem(), pObj, passInfo, EFSLIST_GENERAL, 1, rendItemSorter);
+        }
+    }
+}
+
+void C3DEngine::DrawTextRightAligned(const float x, const float y, const char* format, ...)
+{
+    va_list args;
+    va_start(args, format);
+
+    SDrawTextInfo ti;
+    ti.flags = eDrawText_FixedSize | eDrawText_Right | eDrawText_2D | eDrawText_Monospace;
+    ti.xscale = ti.yscale = DISPLAY_INFO_SCALE;
+    GetRenderer()->DrawTextQueued(Vec3(x, y, 1.0f), ti, format, args);
+
+    va_end(args);
+}
+
+void C3DEngine::DrawTextAligned(int flags, const float x, const float y, const float scale, const ColorF& color, const char* format, ...)
+{
+    va_list args;
+    va_start(args, format);
+
+    SDrawTextInfo ti;
+    ti.flags = flags;
+    ti.color[0] = color[0];
+    ti.color[1] = color[1];
+    ti.color[2] = color[2];
+    ti.color[3] = color[3];
+    ti.xscale = ti.yscale = scale;
+    GetRenderer()->DrawTextQueued(Vec3(x, y, 1.0f), ti, format, args);
+
+    va_end(args);
+}
+
+void C3DEngine::DrawTextLeftAligned(const float x, const float y, const float scale, const ColorF& color, const char* format, ...)
+{
+    va_list args;
+    va_start(args, format);
+
+    SDrawTextInfo ti;
+    ti.flags = eDrawText_FixedSize | eDrawText_2D | eDrawText_Monospace;
+    ti.color[0] = color[0];
+    ti.color[1] = color[1];
+    ti.color[2] = color[2];
+    ti.color[3] = color[3];
+    ti.xscale = ti.yscale = scale;
+    GetRenderer()->DrawTextQueued(Vec3(x, y, 1.0f), ti, format, args);
+
+    va_end(args);
+}
+
+void C3DEngine::DrawTextRightAligned(const float x, const float y, const float scale, const ColorF& color, const char* format, ...)
+{
+    va_list args;
+    va_start(args, format);
+
+    SDrawTextInfo ti;
+    ti.flags = eDrawText_FixedSize | eDrawText_Right | eDrawText_2D | eDrawText_Monospace;
+    ti.color[0] = color[0];
+    ti.color[1] = color[1];
+    ti.color[2] = color[2];
+    ti.color[3] = color[3];
+    ti.xscale = ti.yscale = scale;
+    GetRenderer()->DrawTextQueued(Vec3(x, y, 1.0f), ti, format, args);
+
+    va_end(args);
+}
+
+int __cdecl C3DEngine__Cmp_FPS(const void* v1, const void* v2)
+{
+    float f1 = *(float*)v1;
+    float f2 = *(float*)v2;
+
+    if (f1 > f2)
+    {
+        return 1;
+    }
+    else if (f1 < f2)
+    {
+        return -1;
+    }
+
+    return 0;
+}
+
+inline void Blend(float& Stat, float StatCur, float fBlendCur)
+{
+    Stat = Stat * (1.f - fBlendCur) + StatCur * fBlendCur;
+}
+
+inline void Blend(float& Stat, int& StatCur, float fBlendCur)
+{
+    Blend(Stat, float(StatCur), fBlendCur);
+    StatCur = int_round(Stat);
+}
+
+#ifdef ENABLE_LW_PROFILERS
+static void AppendString(char*& szEnd, const char* szToAppend)
+{
+    assert(szToAppend);
+
+    while (*szToAppend)
+    {
+        *szEnd++ = *szToAppend++;
+    }
+
+    *szEnd++ = ' ';
+    *szEnd = 0;
+}
+#endif
+
+void C3DEngine::DisplayInfo([[maybe_unused]] float& fTextPosX, [[maybe_unused]] float& fTextPosY, [[maybe_unused]] float& fTextStepY, [[maybe_unused]] const bool bEnhanced)
+{
+#ifdef ENABLE_LW_PROFILERS
+    //  FUNCTION_PROFILER_3DENGINE; causes 0 fps in stats
+    static ICVar* pDisplayInfo = GetConsole()->GetCVar("r_DisplayInfo");
+    assert(pDisplayInfo);
+    if (pDisplayInfo && pDisplayInfo->GetIVal() == 0)
+    {
+        return;
+    }
+
+    if (gEnv->IsDedicated())
+    {
+        return;
+    }
+
+#if defined(INFO_FRAME_COUNTER)
+    static int frameCounter = 0;
+#endif
+    GetRenderer()->SetState(GS_NODEPTHTEST);
+
+    fTextPosY = -10;
+    fTextStepY = 13;
+    fTextPosX = (float)GetRenderer()->GetOverlayWidth() - 5.0f;
+
+    const char* description = GetRenderer()->GetRenderDescription();
+    if (description && description[0] != 0)
+    {
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.5f, ColorF(1.0f, 1.0f, 0.5f, 1.0f),
+            "%s", description);
+    }
+
+    // If stat averaging is on, compute blend amount for current stats.
+    float fFPS = GetTimer()->GetFrameRate();
+
+    // Limit the FPS history for a single level to ~1 hour.
+    // This vector is cleared on each level load, but during a soak test this continues to grow every frame
+    const AZStd::size_t maxFPSEntries = 60 * 60 * 60; // 60ms * 60s * 60min
+    if (arrFPSforSaveLevelStats.size() < maxFPSEntries)
+    {
+        arrFPSforSaveLevelStats.push_back(SATURATEB((int)fFPS));
+    }
+
+    float fBlendTime = GetTimer()->GetCurrTime();
+    int iBlendMode = 0;
+    float fBlendCur = GetTimer()->GetProfileFrameBlending(&fBlendTime, &iBlendMode);
+
+    if (pDisplayInfo && pDisplayInfo->GetIVal() == 3)
+    {
+        static float fCurrentFPS, fCurrentFrameTime;
+        Blend(fCurrentFPS, fFPS, fBlendCur);
+        Blend(fCurrentFrameTime, GetTimer()->GetRealFrameTime() * 1000.0f, fBlendCur);
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.5f, ColorF(1.0f, 1.0f, 0.5f, 1.0f),
+            "FPS %.1f - %.1fms", fCurrentFPS, fCurrentFrameTime);
+        return;
+    }
+
+    // make level name
+    char szLevelName[128];
+
+    *szLevelName = 0;
+    {
+        int ii;
+        for (ii = strlen(m_szLevelFolder) - 2; ii > 0; ii--)
+        {
+            if (m_szLevelFolder[ii] == '\\' || m_szLevelFolder[ii] == '/')
+            {
+                break;
+            }
+        }
+
+        if (ii >= 0)
+        {
+            cry_strcpy(szLevelName, &m_szLevelFolder[ii + 1]);
+
+            for (int i = strlen(szLevelName) - 1; i > 0; i--)
+            {
+                if (szLevelName[i] == '\\' || szLevelName[i] == '/')
+                {
+                    szLevelName[i] = 0;
+                }
+            }
+        }
+    }
+
+    Matrix33 m = Matrix33(GetRenderingCamera().GetMatrix());
+    //m.OrthonormalizeFast();       // why is that needed? is it?
+    Ang3 aAng = RAD2DEG(Ang3::GetAnglesXYZ(m));
+    Vec3 vPos = GetRenderingCamera().GetPosition();
+
+    // Time of day info
+    int hours = 0;
+    int minutes = 0;
+    ITimeOfDay* timeOfDay = GetTimeOfDay();
+    if (timeOfDay)
+    {
+        float time = timeOfDay->GetTime();
+        hours = (int)time;
+        minutes = (int)((time - hours) * 60);
+    }
+
+    // display out of memory message if an allocation failed
+    IF (gEnv->bIsOutOfMemory, 0)
+    {
+        ColorF fColor(1.0f, 0.0f, 0.0f, 1.0f);
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 4.0f, fColor, "**** Out of Memory ****");
+        fTextPosY += 40.0f;
+    }
+    // display out of memory message if an allocation failed
+    IF (gEnv->bIsOutOfVideoMemory, 0)
+    {
+        ColorF fColor(1.0f, 0.0f, 0.0f, 1.0f);
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 4.0f, fColor, "**** Out of Video Memory ****");
+        fTextPosY += 40.0f;
+    }
+
+    float fogCullDist = 0.0f;
+    Vec2 vViewportScale = Vec2(0.0f, 0.0f);
+    m_pRenderer->EF_Query(EFQ_GetFogCullDistance, fogCullDist);
+    m_pRenderer->EF_Query(EFQ_GetViewportDownscaleFactor, vViewportScale);
+
+    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "CamPos=%.2f %.2f %.2f Angl=%3d %2d %3d ZN=%.2f ZF=%d",
+        vPos.x, vPos.y, vPos.z, (int)aAng.x, (int)aAng.y, (int)aAng.z,
+        GetRenderingCamera().GetNearPlane(), (int)GetRenderingCamera().GetFarPlane());
+
+    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "Cam FC=%.2f VS=%.2f,%.2f Zoom=%.2f Speed=%1.2f TimeOfDay=%02d:%02d",
+        fogCullDist, vViewportScale.x, vViewportScale.y,
+        GetZoomFactor(), GetAverageCameraSpeed(), hours, minutes);
+
+    // get version
+    const SFileVersion& ver = GetSystem()->GetFileVersion();
+    //char sVersion[128];
+    //ver.ToString(sVersion);
+
+    // Get memory usage.
+    static IMemoryManager::SProcessMemInfo processMemInfo;
+    {
+        static int nGetMemInfoCount = 0;
+        if ((nGetMemInfoCount & 0x1F) == 0 && GetISystem()->GetIMemoryManager())
+        {
+            // Only get mem stats every 32 frames.
+            GetISystem()->GetIMemoryManager()->GetProcessMemInfo(processMemInfo);
+        }
+        nGetMemInfoCount++;
+    }
+
+    bool bMultiGPU;
+    m_pRenderer->EF_Query(EFQ_MultiGPUEnabled, bMultiGPU);
+
+    const char* pRenderType(0);
+
+    if (AZ::Interface<AzFramework::AtomActiveInterface>::Get())
+    {
+        pRenderType = "DX11";
+    }
+    else
+    {
+        switch (gEnv->pRenderer->GetRenderType())
+        {
+        case eRT_OpenGL:
+            pRenderType = "GL";
+            break;
+        case eRT_DX11:
+            pRenderType = "DX11";
+            break;
+        case eRT_DX12:
+            pRenderType = "DX12";
+            break;
+        case eRT_Xenia:
+            pRenderType = "Xenia";
+            break;
+        case eRT_Jasper: 
+            pRenderType = "Jasper";
+            break;
+        case eRT_Provo:
+            pRenderType = "Provo";
+            break;
+        case eRT_Metal:
+            pRenderType = "Metal";
+            break;
+        case eRT_Null:
+            pRenderType = "Null";
+            break;
+        case eRT_Undefined:
+        default:
+            assert(0);
+            pRenderType = "Undefined";
+            break;
+        }
+    }
+    assert(gEnv->pSystem);
+    bool bTextureStreamingEnabled = false;
+    m_pRenderer->EF_Query(EFQ_TextureStreamingEnabled, bTextureStreamingEnabled);
+    const bool bCGFStreaming = GetCVars()->e_StreamCgf && m_pObjManager;
+    const bool bTexStreaming = gEnv->pSystem->GetStreamEngine() && bTextureStreamingEnabled;
+    char szFlags[128], * szFlagsEnd = szFlags;
+
+#ifndef _RELEASE
+    ESystemConfigSpec spec = GetISystem()->GetConfigSpec();
+    switch (spec)
+    {
+    case CONFIG_AUTO_SPEC:
+        AppendString(szFlagsEnd, "Auto");
+        break;
+    case CONFIG_LOW_SPEC:
+        AppendString(szFlagsEnd, "LowSpec");
+        break;
+    case CONFIG_MEDIUM_SPEC:
+        AppendString(szFlagsEnd, "MedSpec");
+        break;
+    case CONFIG_HIGH_SPEC:
+        AppendString(szFlagsEnd, "HighSpec");
+        break;
+    case CONFIG_VERYHIGH_SPEC:
+        AppendString(szFlagsEnd, "VeryHighSpec");
+        break;
+    default:
+        assert(0);
+    }
+#endif
+#ifndef CONSOLE_CONST_CVAR_MODE
+    static ICVar* pMultiThreaded = GetConsole()->GetCVar("r_MultiThreaded");
+    if (pMultiThreaded && pMultiThreaded->GetIVal() > 0)
+#endif
+    AppendString(szFlagsEnd, "MT");
+
+    char* sAAMode = NULL;
+    m_pRenderer->EF_Query(EFQ_AAMode, sAAMode);
+    AppendString(szFlagsEnd, sAAMode);
+
+    if (IsAreaActivationInUse())
+    {
+        AppendString(szFlagsEnd, "LA");
+    }
+
+    if (bMultiGPU)
+    {
+        AppendString(szFlagsEnd, "MGPU");
+    }
+
+    if (gEnv->pSystem->IsDevMode())
+    {
+        AppendString(szFlagsEnd, gEnv->IsEditor() ? "DevMode (Editor)" : "DevMode");
+    }
+
+    if (bCGFStreaming || bTexStreaming)
+    {
+        if (bCGFStreaming && !bTexStreaming)
+        {
+            AppendString(szFlagsEnd, "StG");
+        }
+        if (bTexStreaming && !bCGFStreaming)
+        {
+            AppendString(szFlagsEnd, "StT");
+        }
+        if (bTexStreaming && bCGFStreaming)
+        {
+            AppendString(szFlagsEnd, "StGT");
+        }
+    }
+
+    // remove last space
+    if (szFlags != szFlagsEnd)
+    {
+        *(szFlagsEnd - 1) = 0;
+    }
+#ifdef _RELEASE
+    const char* mode = "Release";
+#else
+    const char* mode = "Profile";
+#endif
+
+    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "%s %s %dbit %s %s [%d.%d]",
+        pRenderType, mode, (int)sizeof(char*) * 8, szFlags, szLevelName, ver.v[1], ver.v[0]);
+
+    // Polys in scene
+    int nPolygons, nShadowPolygons;
+    GetRenderer()->GetPolyCount(nPolygons, nShadowPolygons);
+    int nDrawCalls,  nShadowGenDrawCalls;
+    GetRenderer()->GetCurrentNumberOfDrawCalls(nDrawCalls,  nShadowGenDrawCalls);
+
+    int nGeomInstances = GetRenderer()->GetNumGeomInstances();
+    int nGeomInstanceDrawCalls = GetRenderer()->GetNumGeomInstanceDrawCalls();
+
+    if (fBlendCur != 1.f)
+    {
+        // Smooth over time.
+        static float fPolygons, fShadowVolPolys, fDrawCalls, fShadowGenDrawCalls, fGeomInstances, fGeomInstanceDrawCalls;
+        Blend(fPolygons, nPolygons, fBlendCur);
+        Blend(fShadowVolPolys, nShadowPolygons, fBlendCur);
+        Blend(fDrawCalls, nDrawCalls, fBlendCur);
+        Blend(fShadowGenDrawCalls, nShadowGenDrawCalls, fBlendCur);
+        Blend(fGeomInstances, nGeomInstances, fBlendCur);
+        Blend(fGeomInstanceDrawCalls, nGeomInstanceDrawCalls, fBlendCur);
+    }
+
+    //
+    static float m_lastAverageDPTime = -FLT_MAX;
+    float curTime = gEnv->pTimer->GetAsyncCurTime();
+    static int lastDrawCalls = 0;
+    static int lastShadowGenDrawCalls = 0;
+    static int avgPolys = 0;
+    static int avgShadowPolys = 0;
+    static int sumPolys = 0;
+    static int sumShadowPolys = 0;
+    static int nPolysFrames = 0;
+    if (curTime < m_lastAverageDPTime)
+    {
+        m_lastAverageDPTime = curTime;
+    }
+    if (curTime - m_lastAverageDPTime > 1.0f)
+    {
+        lastDrawCalls = nDrawCalls;
+        lastShadowGenDrawCalls = nShadowGenDrawCalls;
+        m_lastAverageDPTime = curTime;
+        avgPolys = nPolysFrames ? sumPolys / nPolysFrames : 0;
+        avgShadowPolys = nPolysFrames ? sumShadowPolys / nPolysFrames : 0;
+        sumPolys = nPolygons;
+        sumShadowPolys = nShadowPolygons;
+        nPolysFrames = 1;
+    }
+    else
+    {
+        nPolysFrames++;
+        sumPolys += nPolygons;
+        sumShadowPolys += nShadowPolygons;
+    }
+    //
+
+    int     nMaxDrawCalls = GetCVars()->e_MaxDrawCalls <= 0 ? 2000 : GetCVars()->e_MaxDrawCalls;
+    bool    bInRed = (nDrawCalls + nShadowGenDrawCalls) > nMaxDrawCalls;
+
+    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, bInRed ? Col_Red : Col_White, "DP: %04d (%04d) ShadowGen:%04d (%04d) - Total: %04d Instanced: %04d",
+        nDrawCalls, lastDrawCalls, nShadowGenDrawCalls, lastShadowGenDrawCalls, nDrawCalls + nShadowGenDrawCalls, nDrawCalls + nShadowGenDrawCalls - nGeomInstances + nGeomInstanceDrawCalls);
+#if defined(MOBILE)
+    bInRed = nPolygons > 500000;
+#else
+    bInRed = nPolygons > 1500000;
+#endif
+
+    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, bInRed ? Col_Red : Col_White, "Polys: %03d,%03d (%03d,%03d) Shadow:%03d,%03d (%03d,%03d)",
+        nPolygons / 1000, nPolygons % 1000, avgPolys / 1000, avgPolys % 1000,
+        nShadowPolygons / 1000, nShadowPolygons % 1000, avgShadowPolys / 1000, avgShadowPolys % 1000);
+
+    {
+        SShaderCacheStatistics stats;
+        m_pRenderer->EF_Query(EFQ_GetShaderCacheInfo, stats);
+        {
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_White, "ShaderCache: %d GCM | %d Async Reqs | Compile: %s",
+                (int)stats.m_nGlobalShaderCacheMisses, (int)stats.m_nNumShaderAsyncCompiles, stats.m_bShaderCompileActive ? "On" : "Off");
+        }
+    }
+
+    // print stats about CGF's streaming
+    if (bCGFStreaming)
+    {
+        static char szCGFStreaming[256] = "";
+        static SObjectsStreamingStatus objectsStreamingStatus = {0};
+
+        if (!(GetRenderer()->GetFrameID(false) & 15) || !szCGFStreaming[0] || GetCVars()->e_StreamCgfDebug)
+        {
+            m_pObjManager->GetObjectsStreamingStatus(objectsStreamingStatus);
+            sprintf_s(szCGFStreaming, 256, "CgfStrm: Loaded:%d InProg:%d All:%d Act:%d PcP:%d MemUsed:%2.2f MemReq:%2.2f Pool:%d",
+                objectsStreamingStatus.nReady, objectsStreamingStatus.nInProgress, objectsStreamingStatus.nTotal, objectsStreamingStatus.nActive,
+                (int)m_pObjManager->GetStreamPreCachePointDefs().size(),
+                float(objectsStreamingStatus.nAllocatedBytes) / 1024 / 1024, float(objectsStreamingStatus.nMemRequired) / 1024 / 1024, GetCVars()->e_StreamCgfPoolSize);
+        }
+
+        bool bOutOfMem((float(objectsStreamingStatus.nMemRequired) / 1024 / 1024) > GetCVars()->e_StreamCgfPoolSize);
+        bool bCloseToOutOfMem((float(objectsStreamingStatus.nMemRequired) / 1024 / 1024) > GetCVars()->e_StreamCgfPoolSize * 90 / 100);
+
+        ColorF color = Col_White;
+        if (bOutOfMem)
+        {
+            color = Col_Red;
+        }
+        else if (bCloseToOutOfMem)
+        {
+            color = Col_Orange;
+        }
+        //      if(bTooManyRequests)
+        //      color = Col_Magenta;
+
+        if ((pDisplayInfo->GetIVal() == 2 || GetCVars()->e_StreamCgfDebug) || bOutOfMem || bCloseToOutOfMem)
+        {
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, color, szCGFStreaming);
+        }
+    }
+
+    // print stats about textures' streaming
+    if (bTexStreaming)
+    {
+        static char szTexStreaming[256] = "";
+        static bool bCloseToOutOfMem = false;
+        static bool bOutOfMem = false;
+        static bool bTooManyRequests = false;
+        static bool bOverloadedPool = false;
+        static uint32 nTexCount = 0;
+        static uint32 nTexSize = 0;
+
+        float fTexBandwidthRequired = 0.f;
+        m_pRenderer->GetBandwidthStats(&fTexBandwidthRequired);
+
+        if (!(GetRenderer()->GetFrameID(false) % 30) || !szTexStreaming[0])
+        {
+            STextureStreamingStats stats(!(GetRenderer()->GetFrameID(false) % 120));
+            m_pRenderer->EF_Query(EFQ_GetTexStreamingInfo, stats);
+
+            if (!(GetRenderer()->GetFrameID(false) % 120))
+            {
+                bOverloadedPool = stats.bPoolOverflowTotally;
+                nTexCount = stats.nRequiredStreamedTexturesCount;
+                nTexSize = stats.nRequiredStreamedTexturesSize;
+            }
+
+            int nPlatformSize = nTexSize;
+
+            const int iPercentage = int((float)stats.nCurrentPoolSize / stats.nMaxPoolSize * 100.f);
+            const int iStaticPercentage = int((float)stats.nStaticTexturesSize / stats.nMaxPoolSize * 100.f);
+            sprintf_s(szTexStreaming, "TexStrm: TexRend: %u NumTex: %u Req:%.1fMB Mem(strm/stat/tot):%.1f/%.1f/%.1fMB(%d%%/%d%%) PoolSize:%" PRISIZE_T "MB PoolFrag:%.1f%%",
+                stats.nNumTexturesPerFrame, nTexCount, (float)nPlatformSize / 1024 / 1024,
+                (float)stats.nStreamedTexturesSize / 1024 / 1024, (float)stats.nStaticTexturesSize / 1024 / 1024, (float)stats.nCurrentPoolSize / 1024 / 1024,
+                iPercentage, iStaticPercentage, stats.nMaxPoolSize / 1024 / 1024,
+                stats.fPoolFragmentation * 100.0f
+                );
+            bOverloadedPool |= stats.bPoolOverflowTotally;
+
+            bCloseToOutOfMem = iPercentage >= 90;
+            bOutOfMem = stats.bPoolOverflow;
+        }
+
+        if (pDisplayInfo->GetIVal() == 2 || bCloseToOutOfMem || bTooManyRequests || bOverloadedPool)
+        {
+            ColorF color = Col_White;
+            if (bOutOfMem)
+            {
+                color = Col_Red;
+            }
+            else if (bCloseToOutOfMem)
+            {
+                color = Col_Orange;
+            }
+            if (bTooManyRequests)
+            {
+                color = Col_Magenta;
+            }
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, color, "%s", szTexStreaming);
+        }
+
+        if (pDisplayInfo->GetIVal() > 0 && bOverloadedPool)
+        {
+            DrawTextLeftAligned(0, 10, 2.3f, Col_Red, "Texture pool totally overloaded!");
+        }
+    }
+
+
+
+    {
+        static char szMeshPoolUse[256] = "";
+        static unsigned nFlushFrameId = 0U;
+        static unsigned nFallbackFrameId = 0U;
+        static SMeshPoolStatistics lastStats;
+        static SMeshPoolStatistics stats;
+
+        const unsigned nMainFrameId = GetRenderer()->GetFrameID(false);
+        m_pRenderer->EF_Query(EFQ_GetMeshPoolInfo, stats);
+        const int iPercentage = int((float)stats.nPoolInUse / (stats.nPoolSize ? stats.nPoolSize : 1U) * 100.f);
+        const int iVolatilePercentage = int((float)stats.nInstancePoolInUse / (stats.nInstancePoolSize ? stats.nInstancePoolSize : 1U) * 100.f);
+        nFallbackFrameId = lastStats.nFallbacks < stats.nFallbacks ? nMainFrameId : nFallbackFrameId;
+        nFlushFrameId = lastStats.nFlushes < stats.nFlushes ? nMainFrameId : nFlushFrameId;
+        const bool bOverflow = nMainFrameId - nFlushFrameId < 50;
+        const bool bFallback = nMainFrameId - nFallbackFrameId < 50;
+
+        sprintf_s(szMeshPoolUse,
+            "Mesh Pool: MemUsed:%.2fKB(%d%%%%) Peak %.fKB PoolSize:%" PRISIZE_T "KB Flushes %" PRISIZE_T " Fallbacks %.3fKB %s",
+            (float)stats.nPoolInUse / 1024,
+            iPercentage,
+            (float)stats.nPoolInUsePeak / 1024,
+            stats.nPoolSize / 1024,
+            stats.nFlushes,
+            (float)stats.nFallbacks / 1024.0f,
+            (bFallback ? "FULL!" : bOverflow ? "OVERFLOW" : ""));
+
+        if (stats.nPoolSize && (pDisplayInfo->GetIVal() == 2 || bOverflow || bFallback))
+        {
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE,
+                bFallback ? Col_Red : bOverflow ? Col_Orange : Col_White,
+                szMeshPoolUse);
+        }
+        if (stats.nPoolSize && pDisplayInfo->GetIVal() == 2)
+        {
+            char szVolatilePoolsUse[256];
+            sprintf_s(szVolatilePoolsUse,
+                "Mesh Instance Pool: MemUsed:%.2fKB(%d%%%%) Peak %.fKB PoolSize:%" PRISIZE_T "KB Fallbacks %.3fKB",
+                (float)stats.nInstancePoolInUse / 1024,
+                iVolatilePercentage,
+                (float)stats.nInstancePoolInUsePeak / 1024,
+                stats.nInstancePoolSize / 1024,
+                (float)stats.nInstanceFallbacks / 1024.0f);
+
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE,
+                Col_White, szVolatilePoolsUse);
+        }
+
+        memcpy(&lastStats, &stats, sizeof(lastStats));
+    }
+
+    // streaming info
+    {
+        IStreamEngine* pSE = gEnv->pSystem->GetStreamEngine();
+        if (pSE)
+        {
+            SStreamEngineStatistics& stats = pSE->GetStreamingStatistics();
+            SStreamEngineOpenStats openStats;
+            pSE->GetStreamingOpenStatistics(openStats);
+
+            static char szStreaming[128] = "";
+            if (!(GetRenderer()->GetFrameID(false) & 7))
+            {
+                if (pDisplayInfo->GetIVal() == 2)
+                {
+                    sprintf_s(szStreaming, "Streaming IO: ACT: %3dmsec, Jobs:%2d Total:%5d",
+                        (uint32)stats.fAverageCompletionTime, openStats.nOpenRequestCount, stats.nTotalStreamingRequestCount);
+                }
+                else
+                {
+                    sprintf_s(szStreaming, "Streaming IO: ACT: %3dmsec, Jobs:%2d",
+                        (uint32)stats.fAverageCompletionTime, openStats.nOpenRequestCount);
+                }
+            }
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, szStreaming);
+
+            if (stats.bTempMemOutOfBudget)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.3f, Col_Red, "Temporary Streaming Memory Pool Out of Budget!");
+            }
+        }
+
+        if (pDisplayInfo && pDisplayInfo->GetIVal() == 2) // more streaming info
+        {
+            SStreamEngineStatistics& stats = gEnv->pSystem->GetStreamEngine()->GetStreamingStatistics();
+
+            { // HDD stats
+                static char szStreaming[512] = "";
+                sprintf_s(szStreaming, "HDD: BW:%1.2f|%1.2fMb/s (Eff:%2.1f|%2.1fMb/s) - Seek:%1.2fGB - Active:%2.1f%%%%",
+                    (float)stats.hddInfo.nCurrentReadBandwidth / (1024 * 1024), (float)stats.hddInfo.nSessionReadBandwidth / (1024 * 1024),
+                    (float)stats.hddInfo.nActualReadBandwidth / (1024 * 1024), (float)stats.hddInfo.nAverageActualReadBandwidth / (1024 * 1024),
+                    (float)stats.hddInfo.nAverageSeekOffset / (1024 * 1024), stats.hddInfo.fAverageActiveTime);
+
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, szStreaming);
+            }
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Display Info about dynamic lights.
+    //////////////////////////////////////////////////////////////////////////
+    {
+        {
+#ifndef _RELEASE
+            // Checkpoint loading information
+            if (!gEnv->bMultiplayer)
+            {
+                ISystem::ICheckpointData data;
+                gEnv->pSystem->GetCheckpointData(data);
+
+                if (data.m_loadOrigin != ISystem::eLLO_Unknown)
+                {
+                    static const char* loadStates[] =
+                    {
+                        "",
+                        "New Level",
+                        "Level to Level",
+                        "Resumed Game",
+                        "Map Command",
+                    };
+
+                    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.3f, Col_White, "%s, Checkpoint loads: %i", loadStates[(int)data.m_loadOrigin], (int)data.m_totalLoads);
+                }
+            }
+#endif
+
+            int nPeakMemMB = (int)(processMemInfo.PeakPagefileUsage >> 20);
+            int nVirtMemMB = (int)(processMemInfo.PagefileUsage >> 20);
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "Mem=%d Peak=%d DLights=(%d)", nVirtMemMB, nPeakMemMB, m_nRealLightsNum + m_nDeferredLightsNum);
+
+            uint32 nShadowFrustums = 0;
+            uint32 nShadowAllocs = 0;
+            uint32 nShadowMaskChannels = 0;
+            m_pRenderer->EF_Query(EFQ_GetShadowPoolFrustumsNum, nShadowFrustums);
+            m_pRenderer->EF_Query(EFQ_GetShadowPoolAllocThisFrameNum, nShadowAllocs);
+            m_pRenderer->EF_Query(EFQ_GetShadowMaskChannelsNum, nShadowMaskChannels);
+            bool bThrash = (nShadowAllocs & 0x80000000) ? true : false;
+            nShadowAllocs &= ~0x80000000;
+            uint32 nAvailableShadowMaskChannels = nShadowMaskChannels >> 16;
+            uint32 nUsedShadowMaskChannels = nShadowMaskChannels & 0xFFFF;
+            bool bTooManyLights = nUsedShadowMaskChannels > nAvailableShadowMaskChannels ? true : false;
+
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, (nShadowFrustums || nShadowAllocs) ? Col_Yellow : Col_White, "%d Shadow Mask Channels, %3d Shadow Frustums, %3d Frustum Renders This Frame",
+                nUsedShadowMaskChannels, nShadowFrustums, nShadowAllocs);
+
+            if (bThrash)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Red, "SHADOW POOL THRASHING!!!");
+            }
+
+            if (bTooManyLights)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Red, "TOO MANY SHADOW CASTING LIGHTS (%d/%d)!!!", nUsedShadowMaskChannels, nAvailableShadowMaskChannels);
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Red, "Consider increasing 'r_ShadowCastingLightsMaxCount'");
+            }
+
+#ifndef _RELEASE
+            uint32 numTiledShadingSkippedLights;
+            m_pRenderer->EF_Query(EFQ_GetTiledShadingSkippedLightsNum, numTiledShadingSkippedLights);
+            if (numTiledShadingSkippedLights > 0)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, Col_Red, "TILED SHADING: SKIPPED %d LIGHTS", numTiledShadingSkippedLights);
+            }
+
+            if (GetCVars()->e_levelStartupFrameNum)
+            {
+                static float startupAvgFPS = 0.f;
+                static float levelStartupTime = 0;
+                static int levelStartupFrameEnd = GetCVars()->e_levelStartupFrameNum + GetCVars()->e_levelStartupFrameDelay;
+                int curFrameID = GetRenderer()->GetFrameID(false);
+
+                if (curFrameID >= GetCVars()->e_levelStartupFrameDelay)
+                {
+                    if (curFrameID == GetCVars()->e_levelStartupFrameDelay)
+                    {
+                        levelStartupTime = gEnv->pTimer->GetAsyncCurTime();
+                    }
+                    if (curFrameID == levelStartupFrameEnd)
+                    {
+                        startupAvgFPS = (float)GetCVars()->e_levelStartupFrameNum / (gEnv->pTimer->GetAsyncCurTime() - levelStartupTime);
+                    }
+                    if (curFrameID >= levelStartupFrameEnd)
+                    {
+                        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 2.f, Col_Red, "Startup AVG FPS: %.2f", startupAvgFPS);
+                        fTextPosY += fTextStepY;
+                    }
+                }
+            }
+#endif //_RELEASE
+        }
+
+        m_nDeferredLightsNum = 0;
+    }
+
+    assert(pDisplayInfo);
+    if (bEnhanced)
+    {
+#define CONVX(x) (((x) / (float)gUpdateTimesNum))
+#define CONVY(y) (1.f - ((y) / 720.f))
+#define TICKS_TO_MS(t)  (1000.f * gEnv->pTimer->TicksToSeconds(t))
+# define MAX_PHYS_TIME 32.f
+# define MAX_PLE_TIME 4.f
+        uint32 gUpdateTimeIdx = 0, gUpdateTimesNum = 0;
+        const sUpdateTimes* gUpdateTimes = gEnv->pSystem->GetUpdateTimeStats(gUpdateTimeIdx, gUpdateTimesNum);
+        if (pDisplayInfo->GetIVal() >= 5)
+        {
+            const SAuxGeomRenderFlags flags = gEnv->pRenderer->GetIRenderAuxGeom()->GetRenderFlags();
+            SAuxGeomRenderFlags newFlags(flags);
+            newFlags.SetAlphaBlendMode(e_AlphaNone);
+            newFlags.SetMode2D3DFlag(e_Mode2D);
+            newFlags.SetCullMode(e_CullModeNone);
+            newFlags.SetDepthWriteFlag(e_DepthWriteOff);
+            newFlags.SetDepthTestFlag(e_DepthTestOff);
+            newFlags.SetFillMode(e_FillModeSolid);
+            gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(newFlags);
+            const ColorF colorPhysFull = Col_Blue;
+            const ColorF colorSysFull = Col_Green;
+            const ColorF colorRenFull = Col_Red;
+            const ColorF colorPhysHalf = colorPhysFull * 0.15f;
+            const ColorF colorSysHalf = colorSysFull * 0.15f;
+            const ColorF colorRenHalf = colorRenFull * 0.15f;
+            float phys = (TICKS_TO_MS(gUpdateTimes[0].PhysStepTime) / 66.f) * 720.f;
+            float sys = (TICKS_TO_MS(gUpdateTimes[0].SysUpdateTime) / 66.f) * 720.f;
+            float ren = (TICKS_TO_MS(gUpdateTimes[0].RenderTime) / 66.f) * 720.f;
+            float _lerp = ((float)(max((int)gUpdateTimeIdx - (int)0, 0) / (float)gUpdateTimesNum));
+            ColorB colorPhysLast;
+            colorPhysLast.lerpFloat(colorPhysFull, colorPhysHalf, _lerp);
+            ColorB colorSysLast;
+            colorSysLast.lerpFloat(colorSysFull, colorSysHalf, _lerp);
+            ColorB colorRenLast;
+            colorRenLast.lerpFloat(colorRenFull, colorRenHalf, _lerp);
+            Vec3 lastPhys(CONVX(0), CONVY(phys), 1.f);
+            Vec3 lastSys(CONVX(0), CONVY(sys), 1.f);
+            Vec3 lastRen(CONVX(0), CONVY(ren), 1.f);
+            for (uint32 i = 0; i < gUpdateTimesNum; ++i)
+            {
+                const float x = (float)i;
+                _lerp = ((float)(max((int)gUpdateTimeIdx - (int)i, 0) / (float)gUpdateTimesNum));
+                const sUpdateTimes& sample = gUpdateTimes[i];
+                phys = (TICKS_TO_MS(sample.PhysStepTime) / 66.f) * 720.f;
+                sys = (TICKS_TO_MS(sample.SysUpdateTime) / 66.f) * 720.f;
+                ren = (TICKS_TO_MS(sample.RenderTime) / 66.f) * 720.f;
+                Vec3 curPhys(CONVX(x), CONVY(phys), 1.f);
+                Vec3 curSys(CONVX(x), CONVY(sys), 1.f);
+                Vec3 curRen(CONVX(x), CONVY(ren), 1.f);
+                ColorB colorPhys;
+                colorPhys.lerpFloat(colorPhysFull, colorPhysHalf, _lerp);
+                ColorB colorSys;
+                colorSys.lerpFloat(colorSysFull, colorSysHalf, _lerp);
+                ColorB colorRen;
+                colorRen.lerpFloat(colorRenFull, colorRenHalf, _lerp);
+                gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(lastPhys, colorPhysLast, curPhys, colorPhys);
+                gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(lastSys, colorSysLast, curSys, colorSys);
+                gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(lastRen, colorRenLast, curRen, colorRen);
+                lastPhys = curPhys;
+                colorPhysLast = colorPhys;
+                lastSys = curSys;
+                colorSysLast = colorSys;
+                lastRen = curRen;
+                colorRenLast = colorRen;
+            }
+            gEnv->pRenderer->GetIRenderAuxGeom()->SetRenderFlags(flags);
+        }
+        const float curPhysTime = TICKS_TO_MS(gUpdateTimes[gUpdateTimeIdx].PhysStepTime);
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE_SMALL, curPhysTime > MAX_PHYS_TIME ? Col_Red : Col_White, "%3.1f ms      Phys", curPhysTime);
+        const float curPhysWaitTime = TICKS_TO_MS(gUpdateTimes[gUpdateTimeIdx].physWaitTime);
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE_SMALL, curPhysTime > MAX_PHYS_TIME ? Col_Red : Col_White, "%3.1f ms   WaitPhys", curPhysWaitTime);
+
+        float partTicks = 0;
+
+        //3dengine stats from RenderWorld
+        {
+#if defined(MOBILE)
+            const float maxVal = 12.f;
+#else
+            const float maxVal = 50.f;
+#endif
+            float fTimeMS = TICKS_TO_MS(m_nRenderWorldUSecs) - partTicks;
+            DrawTextRightAligned(fTextPosX, fTextPosY += (fTextStepY - STEP_SMALL_DIFF), DISPLAY_INFO_SCALE_SMALL, fTimeMS > maxVal ? Col_Red : Col_White, "%.2f ms RendWorld", fTimeMS);
+        }
+
+        {
+            SStreamEngineStatistics stat =  gEnv->pSystem->GetStreamEngine()->GetStreamingStatistics();
+
+            float fTimeMS = 1000.0f * gEnv->pTimer->TicksToSeconds(stat.nMainStreamingThreadWait);
+            DrawTextRightAligned(fTextPosX, fTextPosY += (fTextStepY - STEP_SMALL_DIFF),
+                DISPLAY_INFO_SCALE_SMALL, Col_White, "%3.1f ms     StreamFin", fTimeMS);
+        }
+
+        {
+            SNetworkPerformance stat;
+            gEnv->pNetwork->GetPerformanceStatistics(&stat);
+
+            float fTimeMS = 1000.0f * gEnv->pTimer->TicksToSeconds(stat.m_nNetworkSync);
+            DrawTextRightAligned(fTextPosX, fTextPosY += (fTextStepY - STEP_SMALL_DIFF),
+                DISPLAY_INFO_SCALE_SMALL, Col_White, "%3.1f ms     NetworkSync", fTimeMS);
+        }
+    }
+
+#undef MAX_PHYS_TIME
+#undef TICKS_TO_MS
+#undef CONVY
+#undef CONVX
+
+    //////////////////////////////////////////////////////////////////////////
+    // Display Thermal information of the device (if supported)
+    //////////////////////////////////////////////////////////////////////////
+
+    if (ThermalInfoRequestsBus::GetTotalNumOfEventHandlers())
+    {
+        const int thermalSensorCount = static_cast<int>(ThermalSensorType::Count);
+        const char* sensorStrings[thermalSensorCount] = { "CPU", "GPU", "Battery" };
+        for (int i = 0; i < thermalSensorCount; ++i)
+        {
+            float temperature = 0.f;
+            ThermalSensorType sensor = static_cast<ThermalSensorType>(i);
+            EBUS_EVENT_RESULT(temperature, ThermalInfoRequestsBus, GetSensorTemp, sensor);
+            AZStd::string tempText;
+            ColorF tempColor;
+            if (temperature > 0.f)
+            {
+                float overheatingTemp = 0.f;
+                EBUS_EVENT_RESULT(overheatingTemp, ThermalInfoRequestsBus, GetSensorOverheatingTemp, sensor);
+                tempText = AZStd::string::format(" %.1f C", temperature);
+                tempColor = temperature >= overheatingTemp ? Col_Red : Col_White;
+            }
+            else
+            {
+                tempText = "N/A";
+                tempColor = Col_White;
+            }
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE, tempColor, "%s Temp %s", sensorStrings[i], tempText.c_str());
+        }       
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Display Current fps
+    //////////////////////////////////////////////////////////////////////////
+
+    if (iBlendMode)
+    {
+        // Track FPS frequency, report min/max.
+        Blend(m_fAverageFPS, fFPS, fBlendCur);
+
+        Blend(m_fMinFPSDecay, fFPS, fBlendCur);
+        if (fFPS <= m_fMinFPSDecay)
+        {
+            m_fMinFPS = m_fMinFPSDecay = fFPS;
+        }
+
+        Blend(m_fMaxFPSDecay, fFPS, fBlendCur);
+        if (fFPS >= m_fMaxFPSDecay)
+        {
+            m_fMaxFPS = m_fMaxFPSDecay = fFPS;
+        }
+
+        const char* sMode = "";
+        switch (iBlendMode)
+        {
+        case 1:
+            sMode = "frame avg";
+            break;
+        case 2:
+            sMode = "time avg";
+            break;
+        case 3:
+            sMode = "peak hold";
+            break;
+        }
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.5f, ColorF(1.0f, 1.0f, 0.5f, 1.0f),
+            "FPS %.1f [%.0f..%.0f], %s over %.1f s",
+            m_fAverageFPS, m_fMinFPS, m_fMaxFPS, sMode, fBlendTime);
+    }
+    else
+    {
+        const int nHistorySize = 16;
+        static float arrfFrameRateHistory[nHistorySize] = {0};
+
+        static int nFrameId = 0;
+        nFrameId++;
+        int nSlotId = nFrameId % nHistorySize;
+        assert(nSlotId >= 0 && nSlotId < nHistorySize);
+        arrfFrameRateHistory[nSlotId] = min(9999.f, GetTimer()->GetFrameRate());
+
+        float fMinFPS = 9999.0f;
+        float fMaxFPS = 0;
+        for (int i = 0; i < nHistorySize; i++)
+        {
+            if (arrfFrameRateHistory[i] < fMinFPS)
+            {
+                fMinFPS = arrfFrameRateHistory[i];
+            }
+            if (arrfFrameRateHistory[i] > fMaxFPS)
+            {
+                fMaxFPS = arrfFrameRateHistory[i];
+            }
+        }
+
+        float fFrameRate = 0;
+        float fValidFrames = 0;
+        for (int i = 0; i < nHistorySize; i++)
+        {
+            int s = (nFrameId - i) % nHistorySize;
+            fFrameRate += arrfFrameRateHistory[s];
+            fValidFrames++;
+        }
+        fFrameRate /= fValidFrames;
+
+        m_fAverageFPS = fFrameRate;
+        m_fMinFPS = m_fMinFPSDecay = fMinFPS;
+        m_fMaxFPS = m_fMaxFPSDecay = fMaxFPS;
+
+
+        //only difference to r_DisplayInfo 1, need ms for GPU time
+        float fMax = (int(GetCurTimeSec() * 2) & 1) ? 999.f : 888.f;
+        if (bEnhanced)
+        {
+            /*          DrawTextRightAligned( fTextPosX, fTextPosY+=fTextStepY, "%6.2f ~%6.2f ms (%6.2f..%6.2f) CPU",
+            GetTimer()->GetFrameTime()*1000.0f, 1000.0f/max(0.0001f,fFrameRate),
+            1000.0f/max(0.0001f,fMinFPS),
+            1000.0f/max(0.0001f,fMaxFPS));
+            */
+            const RPProfilerStats* pFrameRPPStats = GetRenderer()->GetRPPStats(eRPPSTATS_OverallFrame);
+            float gpuTime = pFrameRPPStats ? pFrameRPPStats->gpuTime : 0.0f;
+            static float sGPUTime = 0.f;
+            if (gpuTime < 1000.f && gpuTime > 0.01f)
+            {
+                sGPUTime = gpuTime;                              //catch sporadic jumps
+            }
+            if (sGPUTime > 0.01f)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, DISPLAY_INFO_SCALE_SMALL, (gpuTime >= 40.f) ? Col_Red : Col_White, "%3.1f ms       GPU", sGPUTime);
+            }
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.4f, ColorF(1.0f, 1.0f, 0.2f, 1.0f), "FPS %5.1f (%3d..%3d)(%3.1f ms)",
+                min(fMax, fFrameRate), (int)min(fMax, fMinFPS), (int)min(fMax, fMaxFPS), GetTimer()->GetFrameTime() * 1000.0f);
+        }
+        else
+        {
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, 1.4f, ColorF(1.0f, 1.0f, 0.2f, 1.0f), "FPS %5.1f (%3d..%3d)",
+                min(fMax, fFrameRate), (int)min(fMax, fMinFPS), (int)min(fMax, fMaxFPS));
+        }
+    }
+
+#ifndef _RELEASE
+    if (GetCVars()->e_GsmStats)
+    {
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "--------------- GSM Stats ---------------");
+
+        if (m_pSun && m_pSun->m_pShadowMapInfo)
+        {
+            CLightEntity::ShadowMapInfo* pSMI = m_pSun->m_pShadowMapInfo;
+            int arrGSMCastersCount[MAX_GSM_LODS_NUM];
+            memset(arrGSMCastersCount, 0, sizeof(arrGSMCastersCount));
+            char szText[256] = "Objects count per shadow map: ";
+            for (int nLod = 0; nLod < Get3DEngine()->GetShadowsCascadeCount(NULL) && nLod < MAX_GSM_LODS_NUM; nLod++)
+            {
+                ShadowMapFrustum*& pLsource = pSMI->pGSM[nLod];
+                if (nLod)
+                {
+                    azstrcat(szText, AZ_ARRAY_SIZE(szText), ", ");
+                }
+
+                char* pstr = szText + strlen(szText);
+                sprintf_s(pstr, sizeof(szText) - (pstr - szText), "%d", pLsource->m_castersList.Count());
+            }
+
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, szText);
+        }
+
+        for (int nSunInUse = 0; nSunInUse < 2; nSunInUse++)
+        {
+            if (nSunInUse)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "WithSun  ListId   FrNum UserNum");
+            }
+            else
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "NoSun    ListId   FrNum UserNum");
+            }
+
+            // TODO: For Nick, check if needed anymore
+            //for(ShadowFrustumListsCache::iterator it = m_FrustumsCache[nSunInUse].begin(); it != m_FrustumsCache[nSunInUse].end(); ++it)
+            //{
+            //  int nListId = (int)it->first;
+            //  PodArray<ShadowMapFrustum*> * pList = it->second;
+
+            //  DrawTextRightAligned( fTextPosX, fTextPosY+=fTextStepY,
+            //    "%8d %8d %8d",
+            //    nListId,
+            //    pList->Count(), m_FrustumsCacheUsers[nSunInUse][nListId]);
+            //}
+        }
+    }
+
+    // objects counter
+    if (GetCVars()->e_ObjStats)
+    {
+#define DRAW_OBJ_STATS(_var) DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "%s: %d", (#_var), GetInstCount(_var))
+
+        DRAW_OBJ_STATS(eERType_NotRenderNode);
+        DRAW_OBJ_STATS(eERType_Light);
+        DRAW_OBJ_STATS(eERType_Cloud);
+        DRAW_OBJ_STATS(eERType_FogVolume);
+        DRAW_OBJ_STATS(eERType_Decal);
+        DRAW_OBJ_STATS(eERType_WaterVolume);
+        DRAW_OBJ_STATS(eERType_DistanceCloud);
+        DRAW_OBJ_STATS(eERType_VolumeObject);
+        DRAW_OBJ_STATS(eERType_Rope);
+        DRAW_OBJ_STATS(eERType_PrismObject);
+        DRAW_OBJ_STATS(eERType_RenderComponent);
+        DRAW_OBJ_STATS(eERType_StaticMeshRenderComponent);
+        DRAW_OBJ_STATS(eERType_DynamicMeshRenderComponent);
+        DRAW_OBJ_STATS(eERType_SkinnedMeshRenderComponent);
+        DRAW_OBJ_STATS(eERType_GameEffect);
+        DRAW_OBJ_STATS(eERType_BreakableGlass);
+
+        if (IsObjectTreeReady())
+        {
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "--- By list type: ---");
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "  Main:      %d", m_pObjectsTree->GetObjectsCount(eMain));
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "Caster:      %d", m_pObjectsTree->GetObjectsCount(eCasters));
+            DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "LigAll:      %d", m_lstStaticLights.Count());
+        }
+
+        int nFree = m_LTPRootFree.Count();
+        int nUsed = m_LTPRootUsed.Count();
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "RNTmpData(Used+Free): %d + %d = %d (%d KB)",
+            nUsed, nFree, nUsed + nFree, (nUsed + nFree) * (int)sizeof(CRNTmpData) / 1024);
+
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "COctreeNode::m_arrEmptyNodes.Count() = %d", COctreeNode::m_arrEmptyNodes.Count());
+    }
+
+    CCullBuffer* pCB = GetCoverageBuffer();
+    if (pCB && GetCVars()->e_CoverageBuffer && GetCVars()->e_CoverageBufferDebug && pCB->TrisWritten())
+    {
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY,
+            "CB: Write:%3d/%2d Test:%4d/%4d/%3d ZFarM:%.2f ZNearM:%.2f Res:%d OI:%s",
+            pCB->TrisWritten(), pCB->ObjectsWritten(),
+            pCB->TrisTested(), pCB->ObjectsTested(), pCB->ObjectsTestedAndRejected(),
+            pCB->GetZFarInMeters(), pCB->GetZNearInMeters(), pCB->SelRes(),
+            pCB->IsOutdooVisible() ? "Out" : "In");
+    }
+
+#if defined(INFO_FRAME_COUNTER)
+    ++frameCounter;
+    DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "Frame #%d", frameCounter);
+#endif
+
+    ITimeOfDay* pTimeOfDay = Get3DEngine()->GetTimeOfDay();
+    if (GetCVars()->e_TimeOfDayDebug && pTimeOfDay)
+    {
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "---------------------------------------");
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "------------ Time of Day  -------------");
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, " ");
+
+        int nVarCount = pTimeOfDay->GetVariableCount();
+        for (int v = 0; v < nVarCount; ++v)
+        {
+            ITimeOfDay::SVariableInfo pVar;
+            pTimeOfDay->GetVariableInfo(v, pVar);
+
+            if (pVar.type == ITimeOfDay::TYPE_FLOAT)
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, " %s: %.9f", pVar.displayName, pVar.fValue[0]);
+            }
+            else
+            {
+                DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, " %s: %.3f %.3f %.3f", pVar.displayName, pVar.fValue[0], pVar.fValue[1], pVar.fValue[2]);
+            }
+        }
+        DrawTextRightAligned(fTextPosX, fTextPosY += fTextStepY, "---------------------------------------");
+    }
+
+#endif
+    // We only show memory usage in dev mode.
+    if (gEnv->pSystem->IsDevMode())
+    {
+        if (GetCVars()->e_DisplayMemoryUsageIcon)
+        {
+            uint64                    nAverageMemoryUsage(0);
+            uint64                    nHighMemoryUsage(0);
+            uint64                    nCurrentMemoryUsage(0);
+            const     uint64  nMegabyte(1024 * 1024);
+
+            // Copied from D3DDriver.cpp, function CD3D9Renderer::RT_EndFrame().
+            int                           nIconSize = 16;
+
+            nCurrentMemoryUsage = processMemInfo.TotalPhysicalMemory - processMemInfo.FreePhysicalMemory;
+
+#if defined(_WIN64) || defined(WIN64) || defined(MAC) || defined(LINUX64)
+            nAverageMemoryUsage = 3000;
+            nHighMemoryUsage = 6000;
+            // This is the same value as measured in the editor.
+            nCurrentMemoryUsage = processMemInfo.PagefileUsage / nMegabyte;
+#elif defined(_WIN32) || defined(LINUX32)
+            nAverageMemoryUsage = 800;
+            nHighMemoryUsage = 1200;
+            // This is the same value as measured in the editor.
+            nCurrentMemoryUsage = processMemInfo.PagefileUsage / nMegabyte;
+#endif //_WIN32
+
+            ITexture* pRenderTexture(m_ptexIconAverageMemoryUsage);
+            if (nCurrentMemoryUsage > nHighMemoryUsage)
+            {
+                pRenderTexture = m_ptexIconHighMemoryUsage;
+            }
+            else if (nCurrentMemoryUsage < nAverageMemoryUsage)
+            {
+                pRenderTexture = m_ptexIconLowMemoryUsage;
+            }
+
+            if (pRenderTexture && gEnv->pRenderer)
+            {
+                float vpWidth = (float)gEnv->pRenderer->GetOverlayWidth(), vpHeight = (float)gEnv->pRenderer->GetOverlayHeight();
+                float iconWidth = (float)nIconSize / vpWidth * 800.0f;
+                float iconHeight = (float)nIconSize / vpHeight * 600.0f;
+                gEnv->pRenderer->Push2dImage((fTextPosX / vpWidth) * 800.0f - iconWidth, ((fTextPosY += nIconSize + 3) / vpHeight) * 600.0f,
+                    iconWidth, iconHeight, pRenderTexture->GetTextureID(), 0, 1.0f, 1.0f, 0);
+            }
+        }
+    }
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+static const float DISPLAY_MEMORY_ROW_MARGIN = 16.0f;
+static const float DISPLAY_MEMORY_ROW_HEIGHT = 32.0f;
+static const float DISPLAY_MEMORY_ROW_NUMBER_WIDTH = 128.0f;
+static const float DISPLAY_MEMORY_ROW_FONT_SCALE = 1.5f;
+static const float DISPLAY_MEMORY_COL_LABEL_FONT_SCALE = 1.0f;
+
+static inline void AdjustDisplayMemoryParameters(float& yPos, float& columnInset, float columnWidth, float screenHeight)
+{
+    int column = (int)(yPos + DISPLAY_MEMORY_ROW_HEIGHT) / (int)screenHeight;
+    columnInset += columnWidth * column;
+    yPos -= screenHeight * column;
+}
+
+static void DisplayMemoryRow(C3DEngine& engine, float columnWidth, float screenHeight, float yPos, float valueA, float valueB, const char* valueBFormat, const ColorF& color, const char* categoryName, const char* subcategoryName = nullptr)
+{
+    float columnInset = columnWidth - DISPLAY_MEMORY_ROW_MARGIN;
+    AdjustDisplayMemoryParameters(yPos, columnInset, columnWidth, screenHeight);
+    if (valueA != -1.0f)
+    {
+        engine.DrawTextRightAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH, yPos, DISPLAY_MEMORY_ROW_FONT_SCALE, color, "%.1fMB", valueA);
+    }
+    if (valueB != -1.0f)
+    {
+        engine.DrawTextRightAligned(columnInset, yPos, DISPLAY_MEMORY_ROW_FONT_SCALE, color, valueBFormat, valueB);
+    }
+
+    if (subcategoryName)
+    {
+        static const float MAIN_TEXT_SCALE = 1.5f;
+        static const float SUB_TEXT_SCALE = 1.0f;
+        static const float SUB_LINE_OFFSET_Y = 16.0f;
+
+        engine.DrawTextLeftAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 4, yPos, MAIN_TEXT_SCALE, color, "%s", categoryName);
+        engine.DrawTextLeftAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 4, yPos + SUB_LINE_OFFSET_Y, SUB_TEXT_SCALE, color, "%s", subcategoryName);
+    }
+    else
+    {
+        engine.DrawTextLeftAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 4, yPos, DISPLAY_MEMORY_ROW_FONT_SCALE, color, "%s", categoryName);
+    }
+}
+
+void C3DEngine::DisplayMemoryStatistics()
+{
+    const ColorF headerColor = ColorF(0.4f, 0.9f, 0.3f, 1.0f);
+    const ColorF statisticColor = ColorF(0.4f, 0.9f, 0.9f, 1.0f);
+    const ColorF subtotalColor = ColorF(0.4f, 0.3f, 0.9f, 1.0f);
+    const ColorF totalColor = ColorF(0.9f, 0.9f, 0.9f, 1.0f);
+    const ColorF labelColor = ColorF(0.4f, 0.3f, 0.3f, 1.0f);
+
+    const float screenHeight = (float)m_pRenderer->GetHeight();
+
+    if (GetCVars()->e_MemoryProfiling == 1)
+    {
+        const float columnWidth = (float)(m_pRenderer->GetWidth() / 2);
+        float columnInset = columnWidth - DISPLAY_MEMORY_ROW_MARGIN;
+
+        float memoryYPos = DISPLAY_MEMORY_ROW_HEIGHT;
+        float memoryYPosStepSize = DISPLAY_MEMORY_ROW_HEIGHT;
+
+        // Add column labels and header
+        this->DrawTextRightAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH, memoryYPos, DISPLAY_MEMORY_COL_LABEL_FONT_SCALE, labelColor, "Allocated");
+        this->DrawTextRightAligned(columnInset, memoryYPos, DISPLAY_MEMORY_COL_LABEL_FONT_SCALE, labelColor, "No. Allocations");
+        DisplayMemoryRow(*this, columnWidth, screenHeight, memoryYPos, -1.0f, -1.0f, "%.1fMB", headerColor, "VRAM Usage");
+        memoryYPos += (memoryYPosStepSize * 0.5f);
+
+        float totalTrackedGPUAlloc = 0.0f;
+
+        // Print the memory usage of each major VRAM category and each subcategory
+        for (int category = 0; category < Render::Debug::VRAM_CATEGORY_NUMBER_CATEGORIES; ++category)
+        {
+            float categorySubTotal = 0.0f;
+            AZStd::string categoryName;
+
+            for (int subcategory = 0; subcategory < Render::Debug::VRAM_SUBCATEGORY_NUMBER_SUBCATEGORIES; ++subcategory)
+            {
+                AZStd::string subcategoryName;
+                size_t numberBytesAllocated = 0;
+                size_t numberAllocations = 0;
+                EBUS_EVENT(Render::Debug::VRAMDrillerBus, GetCurrentVRAMStats, static_cast<Render::Debug::VRAMAllocationCategory>(category),
+                    static_cast<Render::Debug::VRAMAllocationSubcategory>(subcategory), categoryName, subcategoryName, numberBytesAllocated, numberAllocations);
+
+                if (numberAllocations != 0)
+                {
+                    float numMBallocated = numberBytesAllocated / (1024.0f * 1024.0f);
+                    DisplayMemoryRow(*this, columnWidth, screenHeight, memoryYPos, numMBallocated, (float)numberAllocations, "%.0f", statisticColor, categoryName.c_str(), subcategoryName.c_str());
+
+                    memoryYPos += memoryYPosStepSize;
+                    totalTrackedGPUAlloc += numMBallocated;
+                    categorySubTotal += numMBallocated;
+                }
+            }
+            if (categorySubTotal > 0.0f)
+            {
+                float yPos = memoryYPos;
+                AdjustDisplayMemoryParameters(yPos, columnInset, columnWidth, screenHeight);
+                DrawTextLeftAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 4, yPos, DISPLAY_MEMORY_ROW_FONT_SCALE, subtotalColor, "%s Subtotal", categoryName.c_str());
+                DrawTextRightAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH, yPos, DISPLAY_MEMORY_ROW_FONT_SCALE, subtotalColor, "%.1fMB", categorySubTotal);
+                memoryYPos += (memoryYPosStepSize * 0.5f);
+            }
+        }
+
+        float allocatedVideoMemoryMB = -1.0f, reservedVideoMemoryMB = -1.0f;
+
+#if defined(AZ_PLATFORM_PROVO)
+        size_t allocatedVideoMemoryBytes = 0, reservedVideoMemoryBytes = 0;
+        VirtualAllocator::QueryVideoMemory(allocatedVideoMemoryBytes, reservedVideoMemoryBytes);
+        allocatedVideoMemoryMB = static_cast<float>(allocatedVideoMemoryBytes) / (1024.0f * 1024.0f);
+        reservedVideoMemoryMB = static_cast<float>(reservedVideoMemoryBytes) / (1024.0f * 1024.0f);
+#else
+        // Non PROVO platforms just sum up the tracked allocations
+        allocatedVideoMemoryMB = totalTrackedGPUAlloc;
+#endif
+
+        DrawTextLeftAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 4, memoryYPos, DISPLAY_MEMORY_ROW_FONT_SCALE, totalColor, "Total");
+        if (reservedVideoMemoryMB != -1.0f)
+        {
+            DrawTextRightAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 1, memoryYPos, DISPLAY_MEMORY_ROW_FONT_SCALE, totalColor, "%.1fMB/%.1fMB", allocatedVideoMemoryMB, reservedVideoMemoryMB);
+            memoryYPos += (memoryYPosStepSize * 0.5f);
+        }
+        else
+        {
+            DrawTextRightAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH * 1, memoryYPos, DISPLAY_MEMORY_ROW_FONT_SCALE, totalColor, "%.1fMB", allocatedVideoMemoryMB);
+            memoryYPos += (memoryYPosStepSize * 0.5f);
+        }
+
+        // Spacer
+        memoryYPos += (memoryYPosStepSize * 0.5f);
+
+        // Add column labels and header
+        this->DrawTextRightAligned(columnInset - DISPLAY_MEMORY_ROW_NUMBER_WIDTH, memoryYPos, DISPLAY_MEMORY_COL_LABEL_FONT_SCALE, labelColor, "Allocated");
+        this->DrawTextRightAligned(columnInset, memoryYPos, DISPLAY_MEMORY_COL_LABEL_FONT_SCALE, labelColor, "Capacity");
+        DisplayMemoryRow(*this, columnWidth, screenHeight, memoryYPos, -1.0f, -1.0f, "%.1fMB", headerColor, "CPU Memory Usage");
+        memoryYPos += (memoryYPosStepSize * 0.5f);
+
+        float totalTrackedCPUAlloc = 0.0f;
+        float totalCapacityCPUAlloc = 0.0f;
+
+        AZ::AllocatorManager& allocatorManager = AZ::AllocatorManager::Instance();
+        const size_t allocatorCount = allocatorManager.GetNumAllocators();
+        AZStd::map<AZ::IAllocatorAllocate*, AZ::IAllocator*> existingAllocators;
+        AZStd::map<AZ::IAllocatorAllocate*, AZ::IAllocator*> sourcesToAllocators;
+
+        // Build a mapping of original allocator sources to their allocators
+        for (int i = 0; i < allocatorCount; ++i)
+        {
+            AZ::IAllocator* allocator = allocatorManager.GetAllocator(i);
+            sourcesToAllocators.emplace(allocator->GetOriginalAllocationSource(), allocator);
+        }
+
+        // Group up any allocators under this size
+        static float smallAllocatorCapacityMaxMB = 10.0f;
+        float smallAllocatorsTotalCapacityMB = 0.0f;
+        float smallAllocatorsTotalAllocatedMB = 0.0f;
+
+        for (int i = 0; i < allocatorCount; ++i)
+        {
+            AZ::IAllocator* allocator = allocatorManager.GetAllocator(i);
+            AZ::IAllocatorAllocate* source = allocator->GetAllocationSource();
+            AZ::IAllocatorAllocate* originalSource = allocator->GetOriginalAllocationSource();
+            AZ::IAllocatorAllocate* schema = allocator->GetSchema();
+            AZ::IAllocator* alias = (source != originalSource) ? sourcesToAllocators[source] : nullptr;
+
+            if (schema && !alias)
+            {
+                // Check to see if this allocator's source maps to another allocator
+                // Need to check both the schema and the allocator itself, as either one might be used as the alias depending on how it's implemented
+                AZStd::array<AZ::IAllocatorAllocate*, 2> checkAllocators = { { schema, allocator->GetAllocationSource() } };
+
+                for (AZ::IAllocatorAllocate* check : checkAllocators)
+                {
+                    auto existing = existingAllocators.emplace(check, allocator);
+
+                    if (!existing.second)
+                    {
+                        alias = existing.first->second;
+                        // Do not break out of the loop as we need to add to the map for all entries
+                    }
+                }
+            }
+
+            if (!alias)
+            {
+                static const AZ::IAllocator* OS_ALLOCATOR = &AZ::AllocatorInstance<AZ::OSAllocator>::GetAllocator();
+                float allocatedMB = (float)source->NumAllocatedBytes() / (1024.0f * 1024.0f);
+                float capacityMB = (float)source->Capacity() / (1024.0f * 1024.0f);
+
+                totalTrackedCPUAlloc += allocatedMB;
+                totalCapacityCPUAlloc += capacityMB;
+
+                // Skip over smaller allocators so the display is readable.
+                if (capacityMB < smallAllocatorCapacityMaxMB)
+                {
+                    smallAllocatorsTotalCapacityMB += capacityMB;
+                    smallAllocatorsTotalAllocatedMB += allocatedMB;
+                    continue;
+                }
+
+                if (allocator == OS_ALLOCATOR)
+                {
+                    // Need to special case the OS allocator because its capacity is a made-up number. Better to just use the allocated amount, it will hopefully be small anyway.
+                    capacityMB = allocatedMB;
+                }
+
+                DisplayMemoryRow(*this, columnWidth, screenHeight, memoryYPos, allocatedMB, capacityMB, "%.1fMB", statisticColor, allocator->GetName(), allocator->GetDescription());
+
+                memoryYPos += memoryYPosStepSize;
+            }
+        }
+
+        if (smallAllocatorCapacityMaxMB > 0.0f)
+        {
+            AZStd::string subText = AZStd::string::format("Allocators smaller than %.0f MB", smallAllocatorCapacityMaxMB);
+            DisplayMemoryRow(*this, columnWidth, screenHeight, memoryYPos, smallAllocatorsTotalAllocatedMB, smallAllocatorsTotalCapacityMB, "%.1fMB", statisticColor, "All Small Allocators", subText.c_str());
+            memoryYPos += memoryYPosStepSize;
+        }
+
+        DisplayMemoryRow(*this, columnWidth, screenHeight, memoryYPos, totalTrackedCPUAlloc, totalCapacityCPUAlloc, "%.1fMB", totalColor, "Total");
+        memoryYPos += (memoryYPosStepSize * 0.5f);
+    }
+    else if (GetCVars()->e_MemoryProfiling == 2)
+    {
+        const float columnWidth = (float)(m_pRenderer->GetWidth() / 2);
+
+        float memoryYPos = DISPLAY_MEMORY_ROW_HEIGHT;
+        float memoryYPosStepSize = DISPLAY_MEMORY_ROW_HEIGHT;
+
+        AZ::AllocatorManager& allocatorManager = AZ::AllocatorManager::Instance();
+        const size_t allocatorCount = allocatorManager.GetNumAllocators();
+        AZStd::map<AZ::IAllocatorAllocate*, AZ::IAllocator*> existingAllocators;
+        AZStd::map<AZ::IAllocatorAllocate*, AZ::IAllocator*> sourcesToAllocators;
+
+        // Build a mapping of original allocator sources to their allocators
+        for (int i = 0; i < allocatorCount; ++i)
+        {
+            AZ::IAllocator* allocator = allocatorManager.GetAllocator(i);
+            sourcesToAllocators.emplace(allocator->GetOriginalAllocationSource(), allocator);
+        }
+
+        for (int i = 0; i < allocatorCount; ++i)
+        {
+            AZ::IAllocator* allocator = allocatorManager.GetAllocator(i);
+            AZ::IAllocatorAllocate* source = allocator->GetAllocationSource();
+            AZ::IAllocatorAllocate* originalSource = allocator->GetOriginalAllocationSource();
+            AZ::IAllocatorAllocate* schema = allocator->GetSchema();
+            AZ::IAllocator* alias = (source != originalSource) ? sourcesToAllocators[source] : nullptr;
+
+            if (schema && !alias)
+            {
+                // Check to see if this allocator's source maps to another allocator
+                // Need to check both the schema and the allocator itself, as either one might be used as the alias depending on how it's implemented
+                AZStd::array<AZ::IAllocatorAllocate*, 2> checkAllocators = { { schema, allocator->GetAllocationSource() } };
+
+                for (AZ::IAllocatorAllocate* check : checkAllocators)
+                {
+                    auto existing = existingAllocators.emplace(check, allocator);
+
+                    if (!existing.second)
+                    {
+                        alias = existing.first->second;
+                        // Do not break out of the loop as we need to add to the map for all entries
+                    }
+                }
+            }
+
+            if (alias)
+            {
+                float columnInset = columnWidth - DISPLAY_MEMORY_ROW_MARGIN;
+                float yPos = memoryYPos;
+                AdjustDisplayMemoryParameters(yPos, columnInset, columnWidth, screenHeight);
+                DrawTextRightAligned(columnInset, yPos, DISPLAY_MEMORY_ROW_FONT_SCALE, statisticColor, "%s => %s", allocator->GetName(), alias->GetName());
+                memoryYPos += (memoryYPosStepSize * 0.5f);
+            }
+        }
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void C3DEngine::SetupDistanceFog()
+{
+    FUNCTION_PROFILER_3DENGINE;
+
+#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
+    // render to texture does not support volumetric fog 
+    if (GetRenderer()->IsRenderToTextureActive() && (GetCVars()->e_VolumetricFog != 0))
+    {
+        GetRenderer()->EnableFog(false);
+        return;
+    }
+#endif // AZ_RENDER_TO_TEXTURE_GEM_ENABLED
+
+    GetRenderer()->SetFogColor(ColorF(m_vFogColor.x, m_vFogColor.y, m_vFogColor.z, 1.0f));
+    GetRenderer()->EnableFog(GetCVars()->e_Fog > 0);
+}
+
+void C3DEngine::ScreenShotHighRes([[maybe_unused]] CStitchedImage* pStitchedImage, [[maybe_unused]] const int nRenderFlags, [[maybe_unused]] const SRenderingPassInfo& passInfo, [[maybe_unused]] uint32 SliceCount, [[maybe_unused]] f32 fTransitionSize)
+{
+#if defined(WIN32) || defined(WIN64) || defined(MAC)
+
+    //If the requested format is TGA we want the framebuffer in BGR format; otherwise we want RGB
+    const char* szExtension = GetCVars()->e_ScreenShotFileFormat->GetString();
+    bool BGRA = (azstricmp(szExtension, "tga") == 0) ? true : false;
+
+    // finish frame started by system
+    GetRenderer()->EndFrame();
+
+    // The occlusion system does not like being restarted mid-frame like this. Disable it for
+    // the screenshot system.
+    AZ::s32 statObjBufferRenderTasks = GetCVars()->e_StatObjBufferRenderTasks;
+    GetCVars()->e_StatObjBufferRenderTasks = 0;
+
+    GetConsole()->SetScrollMax(0);
+
+    const uint32  ScreenWidth =   GetRenderer()->GetWidth();
+    const uint32  ScreenHeight    =   GetRenderer()->GetHeight();
+    uint32* pImage = new uint32[ScreenWidth * ScreenHeight];
+    for (uint32 yy = 0; yy < SliceCount; yy++)
+    {
+        for (uint32 xx = 0; xx < SliceCount; xx++)
+        {
+            const int BlendX  =   (xx * 2) / SliceCount;
+            const int BlendY  =   (yy * 2) / SliceCount;
+            const int x   =   (((xx * 2) % SliceCount) & ~1) + BlendX;
+            const int y   =   (((yy * 2) % SliceCount) & ~1) + BlendY;
+            const int reverseX = SliceCount - 1 - x;
+            const int reverseY = SliceCount - 1 - y;
+
+            const float halfTransitionSize = fTransitionSize * 0.5f;
+            const float sliceCountF = static_cast<float>(SliceCount);
+
+            // start new frame and define needed tile
+            const f32 ScreenScale = 1.0f / ((1.0f / sliceCountF) * (1.0f + fTransitionSize));
+
+            GetRenderer()->BeginFrame();
+
+            // This has to happen after BeginFrame(), because BeginFrame increments the frame counter, and SRenderingPassInfo
+            // pulls from that counter in the constructor. Individual render nodes track the frame they were last rendered with
+            // and will bail if the same frame is rendered twice.
+            SRenderingPassInfo screenShotPassInfo = SRenderingPassInfo::CreateGeneralPassRenderingInfo(passInfo.GetCamera());
+            PrintMessage("Rendering tile %d of %d ... ", xx + yy * SliceCount + 1, SliceCount * SliceCount);
+
+            const float normalizedX = ((static_cast<f32>(reverseX) - halfTransitionSize) / sliceCountF);
+            const float normalizedY = ((static_cast<f32>(reverseY) - halfTransitionSize) / sliceCountF);
+
+                GetRenderer()->SetRenderTile(
+                    ScreenScale * normalizedX,
+                    ScreenScale * normalizedY,
+                    ScreenScale, ScreenScale);
+
+            UpdateRenderingCamera("ScreenShotHighRes", screenShotPassInfo);
+
+            RenderInternal(nRenderFlags, screenShotPassInfo, "ScreenShotHighRes");
+
+            // Make sure we've composited to the final back buffer.
+            GetRenderer()->SwitchToNativeResolutionBackbuffer();
+
+            GetRenderer()->EndFrame();
+
+            PrintMessagePlus("reading frame buffer ... ");
+
+            GetRenderer()->ReadFrameBufferFast(pImage, ScreenWidth, ScreenHeight, BGRA);
+            pStitchedImage->RasterizeRect(pImage, ScreenWidth, ScreenHeight, x, y, fTransitionSize,
+                fTransitionSize > 0.0001f && BlendX,
+                fTransitionSize > 0.0001f && BlendY);
+
+            PrintMessagePlus("ok");
+        }
+    }
+    delete[] pImage;
+
+    GetCVars()->e_StatObjBufferRenderTasks = statObjBufferRenderTasks;
+
+    // re-start frame so system can safely finish it
+    GetRenderer()->BeginFrame();
+
+    // restore initial state
+    GetRenderer()->SetViewport(0, 0, GetRenderer()->GetWidth(), GetRenderer()->GetHeight());
+    GetConsole()->SetScrollMax(300);
+    GetRenderer()->SetRenderTile();
+
+    PrintMessagePlus(" ok");
+#endif // #if defined(WIN32) || defined(WIN64)
+}
+
+
+
+bool C3DEngine::ScreenShotMap([[maybe_unused]] CStitchedImage* pStitchedImage,
+    [[maybe_unused]] const int                         nRenderFlags,
+    [[maybe_unused]] const SRenderingPassInfo& passInfo,
+    [[maybe_unused]] const uint32                  SliceCount,
+    [[maybe_unused]] const f32                         fTransitionSize)
+{
+#if defined(WIN32) || defined(WIN64) || defined(MAC)
+
+    const f32     fTLX   = GetCVars()->e_ScreenShotMapCenterX - GetCVars()->e_ScreenShotMapSizeX + fTransitionSize * GetRenderer()->GetWidth();
+    const f32     fTLY   = GetCVars()->e_ScreenShotMapCenterY - GetCVars()->e_ScreenShotMapSizeY + fTransitionSize * GetRenderer()->GetHeight();
+    const f32     fBRX   = GetCVars()->e_ScreenShotMapCenterX + GetCVars()->e_ScreenShotMapSizeX + fTransitionSize * GetRenderer()->GetWidth();
+    const f32     fBRY   = GetCVars()->e_ScreenShotMapCenterY + GetCVars()->e_ScreenShotMapSizeY + fTransitionSize * GetRenderer()->GetHeight();
+    const f32     Height = GetCVars()->e_ScreenShotMapCamHeight;
+    const int     Orient = GetCVars()->e_ScreenShotMapOrientation;
+
+    const char* SettingsFileName = GetLevelFilePath("ScreenshotMap.Settings");
+
+    AZ::IO::HandleType metaFileHandle = gEnv->pCryPak->FOpen(SettingsFileName, "wt");
+    if (metaFileHandle != AZ::IO::InvalidHandle)
+    {
+        char Data[1024 * 8];
+        snprintf(Data, sizeof(Data), "<Map CenterX=\"%f\" CenterY=\"%f\" SizeX=\"%f\" SizeY=\"%f\" Height=\"%f\"  Quality=\"%d\" Orientation=\"%d\" />",
+            GetCVars()->e_ScreenShotMapCenterX,
+            GetCVars()->e_ScreenShotMapCenterY,
+            GetCVars()->e_ScreenShotMapSizeX,
+            GetCVars()->e_ScreenShotMapSizeY,
+            GetCVars()->e_ScreenShotMapCamHeight,
+            GetCVars()->e_ScreenShotQuality,
+            GetCVars()->e_ScreenShotMapOrientation);
+        string data(Data);
+        gEnv->pCryPak->FWrite(data.c_str(), data.size(), metaFileHandle);
+        gEnv->pCryPak->FClose(metaFileHandle);
+    }
+
+    // This bit is necessary because we don't have a way to render the world using an orthographic projection. This is doing
+    // a hacky orthographic projection by shifting the camera up to a sufficient height to fake it. To preserve depth range
+    // we define a maximum range then then fit the near / far planes to extend [-HeightRangeMax, HeightRangeMax] along Z (which is the up axis).
+    const float HeightRangeMax = 4096;
+    const float HeightRangeMaxDiv2 = HeightRangeMax / 2.0f;
+
+    const float NearClip = max(Height - HeightRangeMaxDiv2, 1.0f);
+    const float FarClip  = max(Height + HeightRangeMaxDiv2, HeightRangeMax);
+
+    CCamera cam = passInfo.GetCamera();
+    Matrix34 tmX, tmY;
+    float xrot = -gf_PI * 0.5f;
+    float yrot = Orient == 0 ? -gf_PI * 0.5f : -0.0f;
+    tmX.SetRotationX(xrot);
+    tmY.SetRotationY(yrot);
+    Matrix34 tm   =   tmX * tmY;
+    tm.SetTranslation(Vec3((fTLX + fBRX) * 0.5f, (fTLY + fBRY) * 0.5f, Height));
+    cam.SetMatrix(tm);
+
+    const f32 AngleX  =   atanf(((fBRX - fTLX) * 0.5f) / Height);
+    const f32 AngleY  =   atanf(((fBRY - fTLY) * 0.5f) / Height);
+
+    ICVar* r_drawnearfov = GetConsole()->GetCVar("r_DrawNearFoV");
+    assert(r_drawnearfov);
+    const f32 drawnearfov_backup = r_drawnearfov->GetFVal();
+    const f32 ViewingSize =   (float)min(cam.GetViewSurfaceX(), cam.GetViewSurfaceZ());
+    if (max(AngleX, AngleY) <= 0)
+    {
+        return false;
+    }
+    cam.SetFrustum((int)ViewingSize, (int)ViewingSize, max(0.001f, max(AngleX, AngleY) * 2.f), NearClip, FarClip);
+    r_drawnearfov->Set(-1);
+    ScreenShotHighRes(pStitchedImage, nRenderFlags, SRenderingPassInfo::CreateTempRenderingInfo(cam, passInfo), SliceCount, fTransitionSize);
+    r_drawnearfov->Set(drawnearfov_backup);
+
+    return true;
+#else       // #if defined(WIN32) || defined(WIN64)
+    return false;
+#endif  // #if defined(WIN32) || defined(WIN64)
+}
+
+
+bool C3DEngine::ScreenShotPanorama([[maybe_unused]] CStitchedImage* pStitchedImage, [[maybe_unused]] const int nRenderFlags, [[maybe_unused]] const SRenderingPassInfo& passInfo, [[maybe_unused]] uint32 SliceCount, [[maybe_unused]] f32 fTransitionSize)
+{
+#if defined(WIN32) || defined(WIN64) || defined(MAC)
+
+    //If the requested format is TGA we want the framebuffer in BGR format; otherwise we want RGB
+    const char* szExtension = GetCVars()->e_ScreenShotFileFormat->GetString();
+    bool BGRA = (azstricmp(szExtension, "tga") == 0) ? true : false;
+
+    // finish frame started by system
+    GetRenderer()->EndFrame();
+
+    float r_drawnearfov_backup = -1;
+    ICVar* r_drawnearfov = GetConsole()->GetCVar("r_DrawNearFoV");
+    assert(r_drawnearfov);
+
+    r_drawnearfov_backup = r_drawnearfov->GetFVal();
+    r_drawnearfov->Set(-1);     // means the fov override should be switched off
+
+    // The occlusion system does not like being restarted mid-frame like this. Disable it for
+    // the screenshot system.
+    AZ::s32 statObjBufferRenderTasks = GetCVars()->e_StatObjBufferRenderTasks;
+    GetCVars()->e_StatObjBufferRenderTasks = 0;
+
+    GetTimer()->EnableTimer(false);
+
+    uint32* pImage = new uint32[GetRenderer()->GetWidth() * GetRenderer()->GetHeight()];
+
+    for (int iSlice = SliceCount - 1; iSlice >= 0; --iSlice)
+    {
+        if (iSlice == 0)                                          // the last one should do eye adaption
+        {
+            GetTimer()->EnableTimer(true);
+        }
+
+        GetRenderer()->BeginFrame();
+
+        Matrix33 rot;
+        rot.SetIdentity();
+
+        float fAngle = pStitchedImage->GetSliceAngle(iSlice);
+
+        rot.SetRotationZ(fAngle);
+
+        CCamera cam = passInfo.GetCamera();
+
+        Matrix34 tm = cam.GetMatrix();
+        tm = tm * rot;
+        tm.SetTranslation(passInfo.GetCamera().GetPosition());
+        cam.SetMatrix(tm);
+
+        cam.SetFrustum(cam.GetViewSurfaceX(), cam.GetViewSurfaceZ(), pStitchedImage->m_fPanoramaShotVertFOV, cam.GetNearPlane(), cam.GetFarPlane(), cam.GetPixelAspectRatio());
+
+        SRenderingPassInfo screenShotPassInfo = SRenderingPassInfo::CreateGeneralPassRenderingInfo(cam);
+
+        UpdateRenderingCamera("ScreenShotPanorama", screenShotPassInfo);
+
+        // render scene
+        RenderInternal(nRenderFlags, screenShotPassInfo, "ScreenShotPanorama");
+
+        // Make sure we've composited to the final back buffer.
+        GetRenderer()->SwitchToNativeResolutionBackbuffer();
+
+        GetRenderer()->ReadFrameBufferFast(pImage, GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), BGRA);
+
+        GetRenderer()->EndFrame();                          // show last frame (from direction)
+
+        const bool bFadeBorders = (iSlice + 1) * 2 <= (int)SliceCount;
+
+        PrintMessage("PanoramaScreenShot %d/%d FadeBorders:%c (id: %d/%d)", iSlice + 1, SliceCount, bFadeBorders ? 't' : 'f', GetRenderer()->GetFrameID(false), GetRenderer()->GetFrameID(true));
+
+        pStitchedImage->RasterizeCylinder(pImage, GetRenderer()->GetWidth(), GetRenderer()->GetHeight(), iSlice + 1, bFadeBorders);
+
+        if (GetCVars()->e_ScreenShotQuality < 0)  // to debug FadeBorders
+        {
+            if (iSlice * 2 == SliceCount)
+            {
+                pStitchedImage->Clear();
+                PrintMessage("PanoramaScreenShot clear");
+            }
+        }
+    }
+    delete [] pImage;
+
+    r_drawnearfov->Set(r_drawnearfov_backup);
+    GetCVars()->e_StatObjBufferRenderTasks = statObjBufferRenderTasks;
+
+    // re-start frame so system can safely finish it
+    GetRenderer()->BeginFrame();
+
+    return true;
+#else       // #if defined(WIN32) || defined(WIN64)
+    return false;
+#endif  // #if defined(WIN32) || defined(WIN64)
+}
+
+
+
+void C3DEngine::SetupClearColor()
+{
+    FUNCTION_PROFILER_3DENGINE;
+
+    bool bCameraInOutdoors = m_pVisAreaManager && !m_pVisAreaManager->m_pCurArea && !(m_pVisAreaManager->m_pCurPortal && m_pVisAreaManager->m_pCurPortal->m_lstConnections.Count() > 1);
+    GetRenderer()->SetClearColor(bCameraInOutdoors ? m_vFogColor : Vec3(0, 0, 0));
+}
+
+void C3DEngine::FillDebugFPSInfo(SDebugFPSInfo& info)
+{
+    size_t c = 0;
+    float average = 0.0f, min = 0.0f, max = 0.0f;
+    const float clampFPS = 200.0f;
+    for (size_t i = 0, end = arrFPSforSaveLevelStats.size(); i < end; ++i)
+    {
+        if (arrFPSforSaveLevelStats[i] > 1.0f && arrFPSforSaveLevelStats[i] < clampFPS)
+        {
+            ++c;
+            average += arrFPSforSaveLevelStats[i];
+        }
+    }
+
+    if (c)
+    {
+        average /= (float)c;
+    }
+
+    int minc = 0, maxc = 0;
+    for (size_t i = 0, end = arrFPSforSaveLevelStats.size(); i < end; ++i)
+    {
+        if (arrFPSforSaveLevelStats[i] > average && arrFPSforSaveLevelStats[i] < clampFPS)
+        {
+            ++maxc;
+            max += arrFPSforSaveLevelStats[i];
+        }
+
+        if (arrFPSforSaveLevelStats[i] < average && arrFPSforSaveLevelStats[i] < clampFPS)
+        {
+            ++minc;
+            min += arrFPSforSaveLevelStats[i];
+        }
+    }
+
+    if (minc == 0)
+    {
+        minc = 1;
+    }
+    if (maxc == 0)
+    {
+        maxc = 1;
+    }
+
+    info.fAverageFPS = average;
+    info.fMinFPS = min / (float)minc;
+    info.fMaxFPS = max / (float)maxc;
+}

+ 574 - 0
Code/CryEngine/Cry3DEngine/3DEngine_Jobs.cpp

@@ -0,0 +1,574 @@
+/*
+* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
+* its licensors.
+*
+* For complete copyright and license terms please see the LICENSE at the root of this
+* distribution (the "License"). All use of this software is governed by the License,
+* or, if provided, by the license below or the license accompanying this file. Do not
+* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+*
+*/
+// Original file Copyright Crytek GMBH or its affiliates, used under license.
+
+// Description : Implementation of I3DEngine interface methods
+
+
+#include "Cry3DEngine_precompiled.h"
+#include <MathConversion.h>
+
+#include "3dEngine.h"
+
+#include <AzFramework/Terrain/TerrainDataRequestBus.h>
+
+#include "VisAreas.h"
+#include "ObjMan.h"
+#include "Ocean.h"
+
+#include "DecalManager.h"
+#include "IndexedMesh.h"
+#include "AABBSV.h"
+
+#include "MatMan.h"
+
+#include "CullBuffer.h"
+#include "CGF/CGFLoader.h"
+#include "CGF/ReadOnlyChunkFile.h"
+
+#include "CloudRenderNode.h"
+#include "CloudsManager.h"
+#include "SkyLightManager.h"
+#include "FogVolumeRenderNode.h"
+#include "DecalRenderNode.h"
+#include "TimeOfDay.h"
+#include "LightEntity.h"
+#include "FogVolumeRenderNode.h"
+#include "ObjectsTree.h"
+#include "WaterVolumeRenderNode.h"
+#include "DistanceCloudRenderNode.h"
+#include "VolumeObjectRenderNode.h"
+#include "RenderMeshMerger.h"
+#include "DeferredCollisionEvent.h"
+#include "OpticsManager.h"
+#include "ClipVolumeManager.h"
+#include "Environment/OceanEnvironmentBus.h"
+
+
+#if !defined(EXCLUDE_DOCUMENTATION_PURPOSE)
+#include "PrismRenderNode.h"
+#endif // EXCLUDE_DOCUMENTATION_PURPOSE
+
+//Platform specific includes
+#if defined(WIN32) || defined(WIN64)
+#include "CryWindows.h"
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+void C3DEngine::CheckAddLight(CDLight* pLight, const SRenderingPassInfo& passInfo)
+{
+    if (pLight->m_Id < 0)
+    {
+        GetRenderer()->EF_ADDDlight(pLight, passInfo);
+        assert(pLight->m_Id >= 0);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+float C3DEngine::GetLightAmount(CDLight* pLight, const AABB& objBox)
+{
+    // find amount of light
+    float fDist = sqrt_tpl(Distance::Point_AABBSq(pLight->m_Origin, objBox));
+    float fLightAttenuation = (pLight->m_Flags & DLF_DIRECTIONAL) ? 1.f : 1.f - (fDist) / (pLight->m_fRadius);
+    if (fLightAttenuation < 0)
+    {
+        fLightAttenuation = 0;
+    }
+
+    float fLightAmount =
+        (pLight->m_Color.r + pLight->m_Color.g + pLight->m_Color.b) * 0.233f +
+        (pLight->GetSpecularMult()) * 0.1f;
+
+    return fLightAmount * fLightAttenuation;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+float C3DEngine::GetWaterLevel()
+{
+    if (OceanToggle::IsActive())
+    {
+        return OceanRequest::GetOceanLevel();
+    }
+    return m_pOcean ? m_pOcean->GetWaterLevel() : WATER_LEVEL_UNKNOWN;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool C3DEngine::IsTessellationAllowed(const CRenderObject* pObj, const SRenderingPassInfo& passInfo, bool bIgnoreShadowPass) const
+{
+#ifdef MESH_TESSELLATION_ENGINE
+    assert(pObj && GetCVars());
+    bool rendererTessellation;
+    GetRenderer()->EF_Query(EFQ_MeshTessellation, rendererTessellation);
+    if (pObj->m_fDistance < GetCVars()->e_TessellationMaxDistance
+        && GetCVars()->e_Tessellation
+        && rendererTessellation
+        && !(pObj->m_ObjFlags & FOB_DISSOLVE)) // dissolve is not working with tessellation for now
+    {
+        bool bAllowTessellation = true;
+
+        // Check if rendering into shadow map and enable tessellation only if allowed
+        if (!bIgnoreShadowPass && passInfo.IsShadowPass())
+        {
+            if (IsTessellationAllowedForShadowMap(passInfo))
+            {
+                // NOTE: This might be useful for game projects
+                // Use tessellation only for objects visible in main view
+                // Shadows will switch to non-tessellated when caster gets out of view
+                IRenderNode* pRN = (IRenderNode*)pObj->m_pRenderNode;
+                if (pRN)
+                {
+                    bAllowTessellation = (pRN->IsRenderNode() && (pRN->GetDrawFrame() > passInfo.GetFrameID() - 10));
+                }
+            }
+            else
+            {
+                bAllowTessellation = false;
+            }
+        }
+
+        return bAllowTessellation;
+    }
+#endif //#ifdef MESH_TESSELLATION_ENGINE
+
+    return false;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void C3DEngine::CreateRNTmpData(CRNTmpData** ppInfo, IRenderNode* pRNode, const SRenderingPassInfo& passInfo)
+{
+    // m_checkCreateRNTmpData lock scope
+    {
+        AUTO_LOCK(m_checkCreateRNTmpData);
+        FUNCTION_PROFILER_3DENGINE;
+
+        if (*ppInfo)
+        {
+            return; // check if another thread already intialized ppInfo
+        }
+        // make sure element is allocated
+        if (m_LTPRootFree.pNext == &m_LTPRootFree)
+        {
+            CRNTmpData* pNew = new CRNTmpData; //m_RNTmpDataPools.GetNewElement();
+            pNew->Link(&m_LTPRootFree);
+        }
+
+        // move element from m_LTPRootFree to m_LTPRootUsed
+        CRNTmpData* pElem = m_LTPRootFree.pNext;
+        pElem->Unlink();
+        pElem->Link(&m_LTPRootUsed);
+
+        pElem->pOwnerRef = ppInfo;
+        pElem->nFrameInfoId = GetFrameInfoId(ppInfo, passInfo.GetMainFrameID());
+
+        assert(!pElem->pOwnerRef || !(*pElem->pOwnerRef));
+        memset(&pElem->userData, 0, sizeof(pElem->userData));
+
+
+        // Add a memory barrier that the write to nFrameInfoID is visible
+        // before *ppInfo is written, else we have a race condtition in
+        // CheckCreateRNTmpData as we don't use a lock there
+        // for performance reasons
+        MemoryBarrier();
+
+        *ppInfo = pElem;
+    }
+
+    if (pRNode)
+    {
+        pRNode->OnRenderNodeBecomeVisible(passInfo); // Internally uses the just assigned RNTmpData pointer i.e IRenderNode::m_pRNTmpData ...
+
+        if (IVisArea* pVisArea = pRNode->GetEntityVisArea())
+        {
+            pRNode->m_pRNTmpData->userData.m_pClipVolume = pVisArea;
+        }
+        else if (GetClipVolumeManager()->IsClipVolumeRequired(pRNode))
+        {
+            GetClipVolumeManager()->UpdateEntityClipVolume(pRNode->GetPos(), pRNode);
+        }
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void C3DEngine::RenderRenderNode_ShadowPass(IShadowCaster* pShadowCaster, const SRenderingPassInfo& passInfo, [[maybe_unused]] AZ::LegacyJobExecutor* pJobExecutor)
+{
+    assert(passInfo.IsShadowPass());
+
+    SRendItemSorter rendItemSorter = SRendItemSorter::CreateShadowPassRendItemSorter(passInfo);
+
+    if (!pShadowCaster->IsRenderNode())
+    {
+        const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+        const AABB objBox = pShadowCaster->GetBBoxVirtual();
+
+        SRendParams rParams;
+        rParams.fDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
+        rParams.lodValue = pShadowCaster->ComputeLod(0, passInfo);
+        rParams.rendItemSorter = rendItemSorter.GetValue();
+
+        pShadowCaster->Render(rParams, passInfo);
+        return;
+    }
+
+    IRenderNode* pRenderNode = static_cast<IRenderNode*>(pShadowCaster);
+    if ((pRenderNode->m_dwRndFlags & ERF_HIDDEN) != 0)
+    {
+        return;
+    }
+
+    int nStaticObjectLod = -1;
+    if (passInfo.GetShadowMapType() == SRenderingPassInfo::SHADOW_MAP_CACHED)
+    {
+        nStaticObjectLod = GetCVars()->e_ShadowsCacheObjectLod;
+    }
+    else if (passInfo.GetShadowMapType() == SRenderingPassInfo::SHADOW_MAP_CACHED_MGPU_COPY)
+    {
+        nStaticObjectLod = pRenderNode->m_cStaticShadowLod;
+    }
+
+    Get3DEngine()->CheckCreateRNTmpData(&pRenderNode->m_pRNTmpData, pRenderNode, passInfo);
+
+    int wantedLod = pRenderNode->m_pRNTmpData->userData.nWantedLod;
+
+    if (GetCVars()->e_LodForceUpdate && m_pObjManager)
+    {
+        const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+        const AABB objBox = pRenderNode->GetBBoxVirtual();
+        float fDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
+        wantedLod = m_pObjManager->GetObjectLOD(pRenderNode, fDistance);
+    }
+
+    if (pRenderNode->GetShadowLodBias() != IRenderNode::SHADOW_LODBIAS_DISABLE)
+    {
+        if (passInfo.IsShadowPass() && (pRenderNode->GetDrawFrame(0) < (passInfo.GetFrameID() - 10)))
+        {
+            wantedLod += GetCVars()->e_ShadowsLodBiasInvis;
+        }
+        wantedLod += GetCVars()->e_ShadowsLodBiasFixed;
+        wantedLod += pRenderNode->GetShadowLodBias();
+    }
+
+    if (nStaticObjectLod >= 0)
+    {
+        wantedLod = nStaticObjectLod;
+    }
+
+    {
+        const Vec3 vCamPos = passInfo.GetCamera().GetPosition();
+        const AABB objBox = pRenderNode->GetBBoxVirtual();
+        SRendParams rParams;
+        rParams.fDistance = sqrt_tpl(Distance::Point_AABBSq(vCamPos, objBox)) * passInfo.GetZoomFactor();
+        rParams.lodValue = pRenderNode->ComputeLod(wantedLod, passInfo);
+        rParams.rendItemSorter = rendItemSorter.GetValue();
+        rParams.pRenderNode = pRenderNode;
+        pRenderNode->Render(rParams, passInfo);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+ITimeOfDay* C3DEngine::GetTimeOfDay()
+{
+    CTimeOfDay* tod = m_pTimeOfDay;
+
+    if (!tod)
+    {
+        tod = new CTimeOfDay;
+        m_pTimeOfDay = tod;
+    }
+
+    return tod;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void C3DEngine::TraceFogVolumes(const Vec3& vPos, const AABB& objBBox, SFogVolumeData& fogVolData, const SRenderingPassInfo& passInfo, bool fogVolumeShadingQuality)
+{
+    CFogVolumeRenderNode::TraceFogVolumes(vPos, objBBox, fogVolData, passInfo, fogVolumeShadingQuality);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void C3DEngine::AsyncOctreeUpdate(IRenderNode* pEnt, int nSID, [[maybe_unused]] int nSIDConsideredSafe, uint32 nFrameID, bool bUnRegisterOnly)
+{
+    FUNCTION_PROFILER_3DENGINE;
+
+#ifdef _DEBUG // crash test basically
+    const char* szClass = pEnt->GetEntityClassName();
+    const char* szName = pEnt->GetName();
+    if (!szName[0] && !szClass[0])
+    {
+        Warning("I3DEngine::RegisterEntity: Entity undefined"); // do not register undefined objects
+    }
+    //  if(strstr(szName,"Dude"))
+    //  int y=0;
+#endif
+
+    IF (bUnRegisterOnly, 0)
+    {
+        UnRegisterEntityImpl(pEnt);
+        return;
+    }
+    ;
+
+    AABB aabb;
+    pEnt->FillBBox(aabb);
+    float fObjRadiusSqr = aabb.GetRadiusSqr();
+    EERType eERType = pEnt->GetRenderNodeType();
+
+#ifdef SUPP_HMAP_OCCL
+    if (pEnt->m_pRNTmpData)
+    {
+        pEnt->m_pRNTmpData->userData.m_OcclState.vLastVisPoint.Set(0, 0, 0);
+    }
+#endif
+
+
+    const unsigned int dwRndFlags = pEnt->GetRndFlags();
+
+    if (!(dwRndFlags & ERF_RENDER_ALWAYS) && !(dwRndFlags & ERF_CASTSHADOWMAPS))
+    {
+        if (GetCVars()->e_ObjFastRegister && pEnt->m_pOcNode && ((COctreeNode*)pEnt->m_pOcNode)->IsRightNode(aabb, fObjRadiusSqr, pEnt->m_fWSMaxViewDist))
+        { // same octree node
+            Vec3 vEntCenter = GetEntityRegisterPoint(pEnt);
+
+            IVisArea* pVisArea = pEnt->GetEntityVisArea();
+            if (pVisArea && pVisArea->IsPointInsideVisArea(vEntCenter))
+            {
+                return; // same visarea
+            }
+            IVisArea* pVisAreaFromPos = (!m_pVisAreaManager || dwRndFlags & ERF_OUTDOORONLY) ? NULL : GetVisAreaManager()->GetVisAreaFromPos(vEntCenter);
+            if (pVisAreaFromPos == pVisArea)
+            {
+                // NOTE: can only get here when pVisArea==NULL due to 'same visarea' check above. So check for changed clip volume
+                if (GetClipVolumeManager()->IsClipVolumeRequired(pEnt))
+                {
+                    GetClipVolumeManager()->UpdateEntityClipVolume(vEntCenter, pEnt);
+                }
+
+                return; // same visarea or same outdoor
+            }
+        }
+    }
+
+    if (pEnt->m_pOcNode)
+    {
+        UnRegisterEntityImpl(pEnt);
+    }
+    else if (GetCVars()->e_StreamCgf && (eERType == eERType_RenderComponent || eERType == eERType_DynamicMeshRenderComponent || eERType == eERType_GeomCache))
+    { //  Temporary solution: Force streaming priority update for objects that was not registered before
+      //  and was not visible before since usual prediction system was not able to detect them
+
+        if ((uint32)pEnt->GetDrawFrame(0) < nFrameID - 16)
+        {
+            // defer the render node streaming priority update still we have a correct 3D Engine camera
+            int nElementID = m_deferredRenderComponentStreamingPriorityUpdates.Find(pEnt);
+            if (nElementID == -1)  // only add elements once
+            {
+                m_deferredRenderComponentStreamingPriorityUpdates.push_back(pEnt);
+            }
+        }
+    }
+
+    pEnt->m_fWSMaxViewDist = pEnt->GetMaxViewDist();
+
+    bool useVisAreas = true;
+
+    if (eERType != eERType_Light)
+    {
+        if (fObjRadiusSqr > sqr(MAX_VALID_OBJECT_VOLUME) || !_finite(fObjRadiusSqr))
+        {
+            Warning("I3DEngine::RegisterEntity: Object has invalid bbox: name: %s, class name: %s, GetRadius() = %.2f",
+                pEnt->GetName(), pEnt->GetEntityClassName(), fObjRadiusSqr);
+            return; // skip invalid objects - usually only objects with invalid very big scale will reach this point
+        }
+
+        if (dwRndFlags & ERF_RENDER_ALWAYS)
+        {
+            if (m_lstAlwaysVisible.Find(pEnt) < 0)
+            {
+                m_lstAlwaysVisible.Add(pEnt);
+            }
+
+            if (dwRndFlags & ERF_HUD)
+            {
+                return;
+            }
+        }
+
+        if (pEnt->m_dwRndFlags & ERF_OUTDOORONLY)
+        {
+            useVisAreas = false;
+        }
+    }
+    else
+    {
+        CLightEntity* pLight = (CLightEntity*)pEnt;
+        uint32 lightFlag = pLight->m_light.m_Flags;
+        if ((lightFlag & DLF_ATTACH_TO_SUN) || //If the light is attached to the sun, we need to make sure it renders even the entity is not in view port
+            (lightFlag & (DLF_IGNORES_VISAREAS | DLF_DEFERRED_LIGHT | DLF_THIS_AREA_ONLY)) == (DLF_IGNORES_VISAREAS | DLF_DEFERRED_LIGHT)
+            )
+        {
+            if (m_lstAlwaysVisible.Find(pEnt) < 0)
+            {
+                m_lstAlwaysVisible.Add(pEnt);
+            }
+        }
+
+        if (lightFlag & DLF_IGNORES_VISAREAS)
+        {
+            useVisAreas = false;
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // Check for occlusion proxy.
+    {
+        CStatObj* pStatObj = (CStatObj*)pEnt->GetEntityStatObj();
+        if (pStatObj)
+        {
+            if (pStatObj->m_bHaveOcclusionProxy)
+            {
+                pEnt->m_dwRndFlags |=   ERF_GOOD_OCCLUDER;
+                pEnt->m_nInternalFlags |=   IRenderNode::HAS_OCCLUSION_PROXY;
+            }
+        }
+    }
+    //////////////////////////////////////////////////////////////////////////
+    if (!useVisAreas || !(m_pVisAreaManager && m_pVisAreaManager->SetEntityArea(pEnt, aabb, fObjRadiusSqr)))
+    {
+        if (m_pObjectsTree == nullptr)
+        {
+            AZ::Aabb terrainAabb = AZ::Aabb::CreateFromPoint(AZ::Vector3::CreateZero());
+            AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(terrainAabb, &AzFramework::Terrain::TerrainDataRequests::GetTerrainAabb);
+            m_pObjectsTree = COctreeNode::Create(nSID, AABB(Vec3(0, 0, 0), Vec3(terrainAabb.GetXExtent(), terrainAabb.GetYExtent(), terrainAabb.GetZExtent())), NULL);
+        }
+
+        m_pObjectsTree->InsertObject(pEnt, aabb, fObjRadiusSqr, aabb.GetCenter());
+    }
+
+    // update clip volume: use vis area if we have one, otherwise check if we're in the same volume as before. check other volumes as last resort only
+    if (pEnt->m_pRNTmpData)
+    {
+        Vec3 vEntCenter = GetEntityRegisterPoint(pEnt);
+        CRNTmpData::SRNUserData& userData = pEnt->m_pRNTmpData->userData;
+
+        if (IVisArea* pVisArea = pEnt->GetEntityVisArea())
+        {
+            userData.m_pClipVolume = pVisArea;
+        }
+        else if (GetClipVolumeManager()->IsClipVolumeRequired(pEnt))
+        {
+            GetClipVolumeManager()->UpdateEntityClipVolume(vEntCenter, pEnt);
+        }
+    }
+
+    // register decals, to clean up longer not renderes decals and their render meshes
+    if (eERType == eERType_Decal)
+    {
+        m_decalRenderNodes.push_back((IDecalRenderNode*)pEnt);
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool C3DEngine::UnRegisterEntityImpl(IRenderNode* pEnt)
+{
+    // make sure we don't try to update the streaming priority if an object
+    // was added and removed in the same frame
+    int nElementID = m_deferredRenderComponentStreamingPriorityUpdates.Find(pEnt);
+    if (nElementID != -1)
+    {
+        m_deferredRenderComponentStreamingPriorityUpdates.DeleteFastUnsorted(nElementID);
+    }
+
+    FUNCTION_PROFILER_3DENGINE;
+
+#ifdef _DEBUG // crash test basically
+    const char* szClass = pEnt->GetEntityClassName();
+    const char* szName = pEnt->GetName();
+    if (!szName[0] && !szClass[0])
+    {
+        Warning("C3DEngine::RegisterEntity: Entity undefined");
+    }
+#endif
+
+    EERType eRenderNodeType = pEnt->GetRenderNodeType();
+
+    bool bFound = false;
+
+    if (pEnt->m_pOcNode)
+    {
+        bFound = ((COctreeNode*)pEnt->m_pOcNode)->DeleteObject(pEnt);
+    }
+
+    if (pEnt->m_dwRndFlags & ERF_RENDER_ALWAYS || (eRenderNodeType == eERType_Light) || (eRenderNodeType == eERType_FogVolume))
+    {
+        m_lstAlwaysVisible.Delete(pEnt);
+    }
+
+    if (eRenderNodeType == eERType_Decal)
+    {
+        std::vector<IDecalRenderNode*>::iterator it = std::find(m_decalRenderNodes.begin(), m_decalRenderNodes.end(), (IDecalRenderNode*)pEnt);
+        if (it != m_decalRenderNodes.end())
+        {
+            m_decalRenderNodes.erase(it);
+        }
+    }
+
+    if (CClipVolumeManager* pClipVolumeManager = GetClipVolumeManager())
+    {
+        pClipVolumeManager->UnregisterRenderNode(pEnt);
+    }
+
+    return bFound;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+Vec3 C3DEngine::GetEntityRegisterPoint(IRenderNode* pEnt)
+{
+    AABB aabb;
+    pEnt->FillBBox(aabb);
+
+    Vec3 vPoint;
+
+    if (pEnt->m_dwRndFlags & ERF_REGISTER_BY_POSITION)
+    {
+        vPoint = pEnt->GetPos();
+
+        if (pEnt->GetRenderNodeType() != eERType_Light)
+        {
+            // check for valid position
+            if (aabb.GetDistanceSqr(vPoint) > sqr(128.f))
+            {
+                Warning("I3DEngine::RegisterEntity: invalid entity position: Name: %s, Class: %s, Pos=(%.1f,%.1f,%.1f), BoxMin=(%.1f,%.1f,%.1f), BoxMax=(%.1f,%.1f,%.1f)",
+                    pEnt->GetName(), pEnt->GetEntityClassName(),
+                    pEnt->GetPos().x, pEnt->GetPos().y, pEnt->GetPos().z,
+                    pEnt->GetBBox().min.x, pEnt->GetBBox().min.y, pEnt->GetBBox().min.z,
+                    pEnt->GetBBox().max.x, pEnt->GetBBox().max.y, pEnt->GetBBox().max.z
+                    );
+            }
+            // clamp by bbox
+            vPoint.CheckMin(aabb.max);
+            vPoint.CheckMax(aabb.min + Vec3(0, 0, .5f));
+        }
+    }
+    else
+    {
+        vPoint = aabb.GetCenter();
+    }
+
+    return vPoint;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+Vec3 C3DEngine::GetSunDirNormalized() const
+{
+    return m_vSunDirNormalized;
+}
+
+

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff